void DesktopWindow::onIndexesMoved(const QModelIndexList& indexes) { auto delegate = static_cast<Fm::FolderItemDelegate*>(listView_->itemDelegateForColumn(0)); auto itemSize = delegate->itemSize(); // remember the custom position for the items Q_FOREACH(const QModelIndex& index, indexes) { // Under some circumstances, Qt might emit indexMoved for // every single cells in the same row. (when QAbstractItemView::SelectItems is set) // So indexes list may contain several indixes for the same row. // Since we only care about rows, not individual cells, // let's handle column 0 of every row here. if(index.column() == 0) { auto file = proxyModel_->fileInfoFromIndex(index); QRect itemRect = listView_->rectForIndex(index); QPoint tl = itemRect.topLeft(); QRect workArea = qApp->desktop()->availableGeometry(screenNum_); workArea.adjust(12, 12, -12, -12); // check if the position is occupied by another item auto existingItem = std::find_if(customItemPos_.cbegin(), customItemPos_.cend(), [tl](const std::pair<std::string, QPoint>& elem){ return elem.second == tl; }); if(existingItem == customItemPos_.cend() // don't put items on each other && tl.x() >= workArea.x() && tl.y() >= workArea.y() && tl.x() + itemSize.width() <= workArea.right() + 1 // for historical reasons (-> Qt doc) && tl.y() + itemSize.height() <= workArea.bottom() + 1) { // as above customItemPos_[file->name()] = tl; // qDebug() << "indexMoved:" << name << index << itemRect; } } } saveItemPositions(); queueRelayout(); }
void DesktopWindow::onStickToCurrentPos(bool toggled) { QModelIndexList indexes = listView_->selectionModel()->selectedIndexes(); if(!indexes.isEmpty()) { bool relayout(false); QModelIndexList::const_iterator it; for(it = indexes.constBegin(); it != indexes.constEnd(); ++it) { auto file = proxyModel_->fileInfoFromIndex(*it); auto name = file->name(); if(toggled) { // remember the current custom position QRect itemRect = listView_->rectForIndex(*it); customItemPos_[name] = itemRect.topLeft(); } else { // cancel custom position and perform relayout auto item = customItemPos_.find(name); if(item != customItemPos_.end()) { customItemPos_.erase(item); relayout = true; } } } saveItemPositions(); if(relayout) { relayoutItems(); } } }
void DesktopWindow::onRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end) { Q_UNUSED(parent); Q_UNUSED(start); Q_UNUSED(end); if(!customItemPos_.empty()) { // also delete stored custom item positions for the items currently being removed. // Here we can't rely on ProxyFolderModel::fileInfoFromIndex() because, although rows // aren't removed yet, files are already removed. bool changed = false; char* dektopPath = Fm::Path::getDesktop().toStr(); QString desktopDir = QString(dektopPath) + QString("/"); g_free(dektopPath); for(auto it = customItemPos_.cbegin(); it != customItemPos_.cend();) { auto& name = it->first; if(!QFile::exists(desktopDir + QString::fromStdString(name))) { it = customItemPos_.erase(it); changed = true; } else { ++it; } } if(changed) { saveItemPositions(); } } listView_->setUpdatesEnabled(false); queueRelayout(100); }
void DesktopWindow::onIndexesMoved(const QModelIndexList& indexes) { // remember the custom position for the items Q_FOREACH(const QModelIndex& index, indexes) { // Under some circumstances, Qt might emit indexMoved for // every single cells in the same row. (when QAbstractItemView::SelectItems is set) // So indexes list may contain several indixes for the same row. // Since we only care about rows, not individual cells, // let's handle column 0 of every row here. if(index.column() == 0) { FmFileInfo* file = proxyModel_->fileInfoFromIndex(index); QRect itemRect = listView_->rectForIndex(index); QPoint tl = itemRect.topLeft(); QRect workArea = qApp->desktop()->availableGeometry(screenNum_); workArea.adjust(12, 12, -12, -12); if(customItemPos_.keys(tl).isEmpty() // don't put items on each other && tl.x() >= workArea.x() && tl.y() >= workArea.y() && tl.x() + listView_->gridSize().width() <= workArea.right() + 1 // for historical reasons (-> Qt doc) && tl.y() + listView_->gridSize().height() <= workArea.bottom() + 1) { // as above QByteArray name = fm_file_info_get_name(file); customItemPos_[name] = tl; // qDebug() << "indexMoved:" << name << index << itemRect; } } } saveItemPositions(); queueRelayout(); }
void DesktopWindow::childDropEvent(QDropEvent* e) { const QMimeData* mimeData = e->mimeData(); bool moveItem = false; if(e->source() == listView_ && e->keyboardModifiers() == Qt::NoModifier) { // drag source is our list view, and no other modifier keys are pressed // => we're dragging desktop items if(mimeData->hasFormat("application/x-qabstractitemmodeldatalist")) { QModelIndex dropIndex = listView_->indexAt(e->pos()); if(dropIndex.isValid()) { // drop on an item QModelIndexList selected = selectedIndexes(); // the dragged items if(selected.contains(dropIndex)) { // drop on self, ignore moveItem = true; } } else { // drop on a blank area moveItem = true; } } } if(moveItem) { e->accept(); } else { auto delegate = static_cast<Fm::FolderItemDelegate*>(listView_->itemDelegateForColumn(0)); auto grid = delegate->itemSize(); Fm::FolderView::childDropEvent(e); // position dropped items successively, starting with the drop rectangle if(mimeData->hasUrls() && (e->dropAction() == Qt::CopyAction || e->dropAction() == Qt::MoveAction || e->dropAction() == Qt::LinkAction)) { QList<QUrl> urlList = mimeData->urls(); for(int i = 0; i < urlList.count(); ++i) { std::string name = urlList.at(i).fileName().toUtf8().constData(); if(!name.empty()) { // respect the positions of existing files QString desktopDir = XdgDir::readDesktopDir() + QString(QLatin1String("/")); if(!QFile::exists(desktopDir + QString::fromStdString(name))) { QRect workArea = qApp->desktop()->availableGeometry(screenNum_); workArea.adjust(12, 12, -12, -12); QPoint pos = mapFromGlobal(e->pos()); alignToGrid(pos, workArea.topLeft(), grid, listView_->spacing()); if(i > 0) pos.setY(pos.y() + grid.height() + listView_->spacing()); if(pos.y() + grid.height() > workArea.bottom() + 1) { pos.setX(pos.x() + grid.width() + listView_->spacing()); pos.setY(workArea.top()); } customItemPos_[name] = pos; } } } saveItemPositions(); } } }
void DesktopWindow::onStickToCurrentPos(bool toggled) { QAction* action = static_cast<QAction*>(sender()); Fm::FileMenu* menu = static_cast<Fm::FileMenu*>(action->parent()); QModelIndexList indexes = listView_->selectionModel()->selectedIndexes(); if(!indexes.isEmpty()) { FmFileInfo* file = menu->firstFile(); QByteArray name = fm_file_info_get_name(file); QModelIndex index = indexes.first(); if(toggled) { // remember to current custom position QRect itemRect = listView_->rectForIndex(index); customItemPos_[name] = itemRect.topLeft(); saveItemPositions(); } else { // cancel custom position and perform relayout QHash<QByteArray, QPoint>::iterator it = customItemPos_.find(name); if(it != customItemPos_.end()) { customItemPos_.erase(it); saveItemPositions(); relayoutItems(); } } } }
void DesktopWindow::onRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end) { Q_UNUSED(parent); Q_UNUSED(start); Q_UNUSED(end); if(!customItemPos_.isEmpty()) { // also delete stored custom item positions for the items currently being removed. // Here we can't rely on ProxyFolderModel::fileInfoFromIndex() because, although rows // aren't removed yet, files are already removed. QHash<QByteArray, QPoint> _customItemPos = customItemPos_; char* dektopPath = fm_path_to_str(fm_path_get_desktop()); QString desktopDir = QString(dektopPath) + QString("/"); g_free(dektopPath); QHash<QByteArray, QPoint>::iterator it; for(it = _customItemPos.begin(); it != _customItemPos.end(); ++it) { const QByteArray& name = it.key(); if(!QFile::exists(desktopDir + QString::fromUtf8(name, name.length()))) customItemPos_.remove(it.key()); } if(customItemPos_ != _customItemPos) saveItemPositions(); } queueRelayout(); }