예제 #1
0
// QListView does item layout in a very inflexible way, so let's do our custom layout again.
// FIXME: this is very inefficient, but due to the design flaw of QListView, this is currently the only workaround.
void DesktopWindow::relayoutItems() {
    displayNames_.clear();
    loadItemPositions(); // something may have changed
    // qDebug("relayoutItems()");
    if(relayoutTimer_) {
        // this slot might be called from the timer, so we cannot delete it directly here.
        relayoutTimer_->deleteLater();
        relayoutTimer_ = nullptr;
    }

    QDesktopWidget* desktop = qApp->desktop();
    int screen = 0;
    int row = 0;
    int rowCount = proxyModel_->rowCount();

    auto delegate = static_cast<Fm::FolderItemDelegate*>(listView_->itemDelegateForColumn(0));
    auto itemSize = delegate->itemSize();

    for(;;) {
        if(desktop->isVirtualDesktop()) {
            if(screen >= desktop->numScreens()) {
                break;
            }
        }
        else {
            screen = screenNum_;
        }
        QRect workArea = desktop->availableGeometry(screen);
        workArea.adjust(12, 12, -12, -12); // add a 12 pixel margin to the work area
        // qDebug() << "workArea" << screen <<  workArea;
        // FIXME: we use an internal class declared in a private header here, which is pretty bad.
        QPoint pos = workArea.topLeft();
        for(; row < rowCount; ++row) {
            QModelIndex index = proxyModel_->index(row, 0);
            int itemWidth = delegate->sizeHint(listView_->getViewOptions(), index).width();
            auto file = proxyModel_->fileInfoFromIndex(index);
            // remember display names of desktop entries and shortcuts
            if(file->isDesktopEntry() || file->isShortcut()) {
                displayNames_[index] = file->displayName();
            }
            auto name = file->name();
            auto find_it = customItemPos_.find(name);
            if(find_it != customItemPos_.cend()) { // the item has a custom position
                QPoint customPos = find_it->second;
                // center the contents vertically
                listView_->setPositionForIndex(customPos + QPoint((itemSize.width() - itemWidth) / 2, 0), index);
                // qDebug() << "set custom pos:" << name << row << index << customPos;
                continue;
            }
            // check if the current pos is alredy occupied by a custom item
            bool used = false;
            for(auto it = customItemPos_.cbegin(); it != customItemPos_.cend(); ++it) {
                QPoint customPos = it->second;
                if(QRect(customPos, itemSize).contains(pos)) {
                    used = true;
                    break;
                }
            }
            if(used) { // go to next pos
                --row;
            }
            else {
                // center the contents vertically
                listView_->setPositionForIndex(pos + QPoint((itemSize.width() - itemWidth) / 2, 0), index);
                // qDebug() << "set pos" << name << row << index << pos;
            }
            // move to next cell in the column
            pos.setY(pos.y() + itemSize.height() + listView_->spacing());
            if(pos.y() + itemSize.height() > workArea.bottom() + 1) {
                // if the next position may exceed the bottom of work area, go to the top of next column
                pos.setX(pos.x() + itemSize.width() + listView_->spacing());
                pos.setY(workArea.top());

                // check if the new column exceeds the right margin of work area
                if(pos.x() + itemSize.width() > workArea.right() + 1) {
                    if(desktop->isVirtualDesktop()) {
                        // in virtual desktop mode, go to next screen
                        ++screen;
                        break;
                    }
                }
            }
        }
        if(row >= rowCount) {
            break;
        }
    }

    if(!listView_->updatesEnabled()) {
        listView_->setUpdatesEnabled(true);
    }
}
예제 #2
0
DesktopWindow::DesktopWindow(int screenNum):
  View(Fm::FolderView::IconMode),
  proxyModel_(NULL),
  model_(NULL),
  folder_(NULL),
  wallpaperMode_(WallpaperNone),
  fileLauncher_(NULL),
  showWmMenu_(false),
  screenNum_(screenNum),
  relayoutTimer_(NULL) {

  QDesktopWidget* desktopWidget = QApplication::desktop();
  setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
  setAttribute(Qt::WA_X11NetWmWindowTypeDesktop);
  setAttribute(Qt::WA_DeleteOnClose);

  // set our custom file launcher
  View::setFileLauncher(&fileLauncher_);

  listView_ = static_cast<Fm::FolderViewListView*>(childView());
  listView_->setMovement(QListView::Snap);
  listView_->setResizeMode(QListView::Adjust);
  listView_->setFlow(QListView::TopToBottom);

  // NOTE: When XRnadR is in use, the all screens are actually combined to form a
  // large virtual desktop and only one DesktopWindow needs to be created and screenNum is -1.
  // In some older multihead setups, such as xinerama, every physical screen
  // is treated as a separate desktop so many instances of DesktopWindow may be created.
  // In this case we only want to show desktop icons on the primary screen.
  if(desktopWidget->isVirtualDesktop() || screenNum_ == desktopWidget->primaryScreen()) {
    loadItemPositions();
    Settings& settings = static_cast<Application* >(qApp)->settings();

    model_ = Fm::CachedFolderModel::modelFromPath(fm_path_get_desktop());
    folder_ = reinterpret_cast<FmFolder*>(g_object_ref(model_->folder()));

    proxyModel_ = new Fm::ProxyFolderModel();
    proxyModel_->setSourceModel(model_);
    proxyModel_->setShowThumbnails(settings.showThumbnails());
    proxyModel_->sort(settings.desktopSortColumn(), settings.desktopSortOrder());
    proxyModel_->setFolderFirst(settings.desktopSortFolderFirst());
    setModel(proxyModel_);

    connect(proxyModel_, &Fm::ProxyFolderModel::rowsInserted, this, &DesktopWindow::onRowsInserted);
    connect(proxyModel_, &Fm::ProxyFolderModel::rowsAboutToBeRemoved, this, &DesktopWindow::onRowsAboutToBeRemoved);
    connect(proxyModel_, &Fm::ProxyFolderModel::layoutChanged, this, &DesktopWindow::onLayoutChanged);
    connect(proxyModel_, &Fm::ProxyFolderModel::sortFilterChanged, this, &DesktopWindow::onModelSortFilterChanged);
    connect(listView_, &QListView::indexesMoved, this, &DesktopWindow::onIndexesMoved);
  }

  // set our own delegate
  delegate_ = new DesktopItemDelegate(listView_);
  listView_->setItemDelegateForColumn(Fm::FolderModel::ColumnFileName, delegate_);

  // remove frame
  listView_->setFrameShape(QFrame::NoFrame);
  // inhibit scrollbars FIXME: this should be optional in the future
  listView_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  listView_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

  connect(this, &DesktopWindow::openDirRequested, this, &DesktopWindow::onOpenDirRequested);

  listView_->installEventFilter(this);

  // setup shortcuts
  QShortcut* shortcut;
  shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_X), this); // cut
  connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onCutActivated);

  shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_C), this); // copy
  connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onCopyActivated);

  shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_V), this); // paste
  connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onPasteActivated);

  shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_A), this); // select all
  connect(shortcut, &QShortcut::activated, listView_, &QListView::selectAll);

  shortcut = new QShortcut(QKeySequence(Qt::Key_Delete), this); // delete
  connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onDeleteActivated);

  shortcut = new QShortcut(QKeySequence(Qt::Key_F2), this); // rename
  connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onRenameActivated);

  shortcut = new QShortcut(QKeySequence(Qt::ALT + Qt::Key_Return), this); // rename
  connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onFilePropertiesActivated);

  shortcut = new QShortcut(QKeySequence(Qt::SHIFT + Qt::Key_Delete), this); // force delete
  connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onDeleteActivated);
}
예제 #3
0
DesktopWindow::DesktopWindow(int screenNum):
    View(Fm::FolderView::IconMode),
    proxyModel_(nullptr),
    model_(nullptr),
    wallpaperMode_(WallpaperNone),
    slideShowInterval_(0),
    wallpaperTimer_(nullptr),
    wallpaperRandomize_(false),
    fileLauncher_(nullptr),
    showWmMenu_(false),
    screenNum_(screenNum),
    relayoutTimer_(nullptr) {

    QDesktopWidget* desktopWidget = QApplication::desktop();
    setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
    setAttribute(Qt::WA_X11NetWmWindowTypeDesktop);
    setAttribute(Qt::WA_DeleteOnClose);

    // set our custom file launcher
    View::setFileLauncher(&fileLauncher_);

    listView_ = static_cast<Fm::FolderViewListView*>(childView());
    listView_->setMovement(QListView::Snap);
    listView_->setResizeMode(QListView::Adjust);
    listView_->setFlow(QListView::TopToBottom);

    // This is to workaround Qt bug 54384 which affects Qt >= 5.6
    // https://bugreports.qt.io/browse/QTBUG-54384
    // Setting a QPixmap larger then the screen resolution to desktop's QPalette won't work.
    // So we make the viewport transparent by preventing its backround from being filled automatically.
    // Then we paint desktop's background ourselves by using its paint event handling method.
    listView_->viewport()->setAutoFillBackground(false);

    // NOTE: When XRnadR is in use, the all screens are actually combined to form a
    // large virtual desktop and only one DesktopWindow needs to be created and screenNum is -1.
    // In some older multihead setups, such as xinerama, every physical screen
    // is treated as a separate desktop so many instances of DesktopWindow may be created.
    // In this case we only want to show desktop icons on the primary screen.
    if(desktopWidget->isVirtualDesktop() || screenNum_ == desktopWidget->primaryScreen()) {
        loadItemPositions();
        Settings& settings = static_cast<Application* >(qApp)->settings();

        auto desktopPath = Fm::FilePath::fromLocalPath(XdgDir::readDesktopDir().toStdString().c_str());
        model_ = Fm::CachedFolderModel::modelFromPath(desktopPath);
        folder_ = model_->folder();

        proxyModel_ = new Fm::ProxyFolderModel();
        proxyModel_->setSourceModel(model_);
        proxyModel_->setShowThumbnails(settings.showThumbnails());
        proxyModel_->sort(settings.desktopSortColumn(), settings.desktopSortOrder());
        proxyModel_->setFolderFirst(settings.desktopSortFolderFirst());
        setModel(proxyModel_);

        connect(proxyModel_, &Fm::ProxyFolderModel::rowsInserted, this, &DesktopWindow::onRowsInserted);
        connect(proxyModel_, &Fm::ProxyFolderModel::rowsAboutToBeRemoved, this, &DesktopWindow::onRowsAboutToBeRemoved);
        connect(proxyModel_, &Fm::ProxyFolderModel::layoutChanged, this, &DesktopWindow::onLayoutChanged);
        connect(proxyModel_, &Fm::ProxyFolderModel::sortFilterChanged, this, &DesktopWindow::onModelSortFilterChanged);
        connect(proxyModel_, &Fm::ProxyFolderModel::dataChanged, this, &DesktopWindow::onDataChanged);
        connect(listView_, &QListView::indexesMoved, this, &DesktopWindow::onIndexesMoved);
    }

    // remove frame
    listView_->setFrameShape(QFrame::NoFrame);
    // inhibit scrollbars FIXME: this should be optional in the future
    listView_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    listView_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

    connect(this, &DesktopWindow::openDirRequested, this, &DesktopWindow::onOpenDirRequested);

    listView_->installEventFilter(this);
    listView_->viewport()->installEventFilter(this);

    // setup shortcuts
    QShortcut* shortcut;
    shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_X), this); // cut
    connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onCutActivated);

    shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_C), this); // copy
    connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onCopyActivated);

    shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_V), this); // paste
    connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onPasteActivated);

    shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_A), this); // select all
    connect(shortcut, &QShortcut::activated, this, &FolderView::selectAll);

    shortcut = new QShortcut(QKeySequence(Qt::Key_Delete), this); // delete
    connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onDeleteActivated);

    shortcut = new QShortcut(QKeySequence(Qt::Key_F2), this); // rename
    connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onRenameActivated);

    shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_F2), this); // bulk rename
    connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onBulkRenameActivated);

    shortcut = new QShortcut(QKeySequence(Qt::ALT + Qt::Key_Return), this); // properties
    connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onFilePropertiesActivated);

    shortcut = new QShortcut(QKeySequence(Qt::SHIFT + Qt::Key_Delete), this); // force delete
    connect(shortcut, &QShortcut::activated, this, &DesktopWindow::onDeleteActivated);
}
예제 #4
0
// QListView does item layout in a very inflexible way, so let's do our custom layout again.
// FIXME: this is very inefficient, but due to the design flaw of QListView, this is currently the only workaround.
void DesktopWindow::relayoutItems() {
  loadItemPositions(); // something may have changed
  // qDebug("relayoutItems()");
  if(relayoutTimer_) {
    // this slot might be called from the timer, so we cannot delete it directly here.
    relayoutTimer_->deleteLater();
    relayoutTimer_ = NULL;
  }

  QDesktopWidget* desktop = qApp->desktop();
  int screen = 0;
  int row = 0;
  int rowCount = proxyModel_->rowCount();
  for(;;) {
    if(desktop->isVirtualDesktop()) {
      if(screen >= desktop->numScreens())
        break;
    }else {
      screen = screenNum_;
    }
    QRect workArea = desktop->availableGeometry(screen);
    workArea.adjust(12, 12, -12, -12); // add a 12 pixel margin to the work area
    // qDebug() << "workArea" << screen <<  workArea;
    // FIXME: we use an internal class declared in a private header here, which is pretty bad.
    QSize grid = listView_->gridSize();
    QPoint pos = workArea.topLeft();
    for(; row < rowCount; ++row) {
      QModelIndex index = proxyModel_->index(row, 0);
      int itemWidth = delegate_->sizeHint(listView_->getViewOptions(), index).width();
      FmFileInfo* file = proxyModel_->fileInfoFromIndex(index);
      QByteArray name = fm_file_info_get_name(file);
      QHash<QByteArray, QPoint>::iterator it = customItemPos_.find(name);
      if(it != customItemPos_.end()) { // the item has a custom position
        QPoint customPos = *it;
        // center the contents vertically
        listView_->setPositionForIndex(customPos + QPoint((grid.width() - itemWidth) / 2, 0), index);
        // qDebug() << "set custom pos:" << name << row << index << customPos;
        continue;
      }
      // check if the current pos is alredy occupied by a custom item
      bool used = false;
      for(it = customItemPos_.begin(); it != customItemPos_.end(); ++it) {
        QPoint customPos = *it;
        if(QRect(customPos, grid).contains(pos)) {
          used = true;
          break;
        }
      }
      if(used) { // go to next pos
        --row;
      }
      else {
        // center the contents vertically
        listView_->setPositionForIndex(pos + QPoint((grid.width() - itemWidth) / 2, 0), index);
        // qDebug() << "set pos" << name << row << index << pos;
      }
      // move to next cell in the column
      pos.setY(pos.y() + grid.height() + listView_->spacing());
      if(pos.y() + grid.height() > workArea.bottom() + 1) {
        // if the next position may exceed the bottom of work area, go to the top of next column
        pos.setX(pos.x() + grid.width() + listView_->spacing());
        pos.setY(workArea.top());

        // check if the new column exceeds the right margin of work area
        if(pos.x() + grid.width() > workArea.right() + 1) {
          if(desktop->isVirtualDesktop()) {
            // in virtual desktop mode, go to next screen
            ++screen;
            break;
          }
        }
      }
    }
    if(row >= rowCount)
      break;
  }
}