peony/peony-qt-desktop/desktop-icon-view.cpp

2770 lines
93 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Peony-Qt
*
* Copyright (C) 2019, Tianjin KYLIN Information Technology Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Authors: Yue Lan <lanyue@kylinos.cn>
*
*/
#include "peony-desktop-application.h"
#include "desktop-icon-view.h"
#include "icon-view-style.h"
#include "desktop-icon-view-delegate.h"
#include "desktop-item-model.h"
#include "desktop-item-proxy-model.h"
#include "file-operation-manager.h"
#include "file-move-operation.h"
#include "file-copy-operation.h"
#include "file-trash-operation.h"
#include "clipboard-utils.h"
#include "properties-window.h"
#include "file-utils.h"
#include "file-operation-utils.h"
#include "desktop-menu.h"
#include "file-item-model.h"
#include "file-info-job.h"
#include "file-launch-manager.h"
#include <QProcess>
#include <QDesktopServices>
#include "desktop-index-widget.h"
#include "file-meta-info.h"
#include "global-settings.h"
#include "audio-play-manager.h"
#include <QAction>
#include <QMouseEvent>
#include <QDragEnterEvent>
#include <QDragMoveEvent>
#include <QDropEvent>
#include <QMimeData>
#include <QHoverEvent>
#include <QWheelEvent>
#include <QApplication>
#include <QStringList>
#include <QMessageBox>
#include <QDir>
#include <QDebug>
#include <QToolTip>
#include <QGSettings>
#include <QDrag>
#include <QMimeData>
#include <QPixmap>
#include <QPainter>
#include <QClipboard>
#include <QtX11Extras/QX11Info>
#include <kstartupinfo.h>
using namespace Peony;
#define ITEM_POS_ATTRIBUTE "metadata::peony-qt-desktop-item-position"
#define PANEL_SETTINGS "org.ukui.panel.settings"
#define UKUI_STYLE_SETTINGS "org.ukui.style"
#define RESTORE_ITEM_POS_ATTRIBUTE "metadata::peony-qt-desktop-restore-item-position"
#define RESTORE_EXTEND_ITEM_POS_ATTRIBUTE "metadata::peony-qt-desktop-restore-extend-item-position"
#define RESTORE_SINGLESCREEN_ITEM_POS_ATTRIBUTE "metadata::peony-qt-desktop-restore-singlescreen-item-position"
static bool iconSizeLessThan (const QPair<QRect, QString> &p1, const QPair<QRect, QString> &p2);
static bool refreshing = false;
static bool g_isHighVersion = false;
DesktopIconView::DesktopIconView(QWidget *parent) : QListView(parent)
{
//m_refresh_timer.setInterval(500);
//m_refresh_timer.setSingleShot(true);
setAttribute(Qt::WA_AlwaysStackOnTop);
installEventFilter(this);
initShoutCut();
//initMenu();
initDoubleClick();
connect(qApp, &QApplication::paletteChanged, this, [=]() {
viewport()->update();
});
m_edit_trigger_timer.setSingleShot(true);
m_edit_trigger_timer.setInterval(3000);
m_last_index = QModelIndex();
setAttribute(Qt::WA_TranslucentBackground);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
//fix rubberband style.
setStyle(DirectoryView::IconViewStyle::getStyle());
setItemDelegate(new DesktopIconViewDelegate(this));
setDefaultDropAction(Qt::MoveAction);
setSelectionMode(QListView::ExtendedSelection);
setEditTriggers(QListView::NoEditTriggers);
setViewMode(QListView::IconMode);
setMovement(QListView::Snap);
setFlow(QListView::TopToBottom);
setResizeMode(QListView::Fixed);
setWordWrap(true);
setDragDropMode(QListView::DragDrop);
setSelectionMode(QListView::ExtendedSelection);
auto zoomLevel = this->zoomLevel();
setDefaultZoomLevel(zoomLevel);
//task#74174 修改model为全局的
m_model = PeonyDesktopApplication::getModel();
m_proxy_model = new DesktopItemProxyModel(m_model);
m_proxy_model->setSourceModel(m_model);
m_proxy_model->setId(m_id);
QString version = qVersion();
if (version >= QString("5.14.0")) {
g_isHighVersion = true;
} else {
g_isHighVersion = false;
}
qDebug() << "qt version: " << version << g_isHighVersion;
connect(m_model, &QAbstractItemModel::rowsRemoved, this, [=](){
for (auto uri : getAllFileUris()) {
auto pos = getFileMetaInfoPos(uri);
if (pos.x() >= 0)
updateItemPosByUri(uri, pos);
}
});
connect(m_proxy_model, &QAbstractItemModel::rowsRemoved, this, [=](){
auto itemsNeedRelayout = m_model->m_items_need_relayout;
if (!itemsNeedRelayout.isEmpty()) {
this->relayoutExsitingItems(itemsNeedRelayout);
}
for (auto uri : getAllFileUris()) {
auto pos = getFileMetaInfoPos(uri);
if (pos.x() >= 0)
updateItemPosByUri(uri, pos);
}
});
//task#74174 扩展模式下支持拖拽图标放置到扩展屏,拖拽后需要通过设置的id重新过滤
connect(this, &DesktopIconView::updateView, this, [=]() {
m_proxy_model->invalidateModel();
for (auto uri : getAllFileUris()) {
auto pos = getFileMetaInfoPos(uri);
if (pos.x() >= 0) {
updateItemPosByUri(uri, pos);
} else {
ensureItemPosByUri(uri);
}
}
checkItemsOver();
});
connect(m_model, &DesktopItemModel::refreshed, this, [=]() {
this->setCursor(QCursor(Qt::ArrowCursor));
refreshing = false;
// check if there are items overlapped.
QTimer::singleShot(150, this, [=](){
initViewport();
checkItemsOver();
// check icon is out of screen
auto geo = viewport()->rect();
if (geo.width() != 0 && geo.height() != 0) {
for (auto rec : m_item_rect_hash.values()) {
if (!geo.contains(rec)) {
resolutionChange();
break;
}
}
}
});
return;
});
connect(m_model, &DesktopItemModel::requestClearIndexWidget, this, &DesktopIconView::clearAllIndexWidgets);
connect(m_proxy_model, &QSortFilterProxyModel::layoutChanged, this, [=]() {
//qDebug()<<"layout changed=========================\n\n\n\n\n";
if (m_proxy_model->getSortType() == DesktopItemProxyModel::Other) {
return;
}
if (m_proxy_model->sortColumn() != 0) {
return;
}
//qDebug()<<"save====================================";
QTimer::singleShot(100, this, [=]() {
//this->saveAllItemPosistionInfos();
});
});
connect(m_proxy_model, &DesktopItemProxyModel::showHiddenFile, this, [=]() {
QTimer::singleShot(100, this, [=]() {
resetAllItemPositionInfos();
refresh();
});
});
connect(this, &QListView::iconSizeChanged, this, [=]() {
//qDebug()<<"save=============";
this->setSortType(GlobalSettings::getInstance()->getValue(LAST_DESKTOP_SORT_ORDER).toInt());
QTimer::singleShot(100, this, [=]() {
bool isFull = false;
auto geo = viewport()->rect();
this->saveAllItemPosistionInfos();
for (int i = 0; i < m_proxy_model->rowCount(); i++) {
auto index = m_proxy_model->index(i, 0);
m_item_rect_hash.insert(index.data(Qt::UserRole).toString(), QListView::visualRect(index));
updateItemPosByUri(index.data(Qt::UserRole).toString(), QListView::visualRect(index).topLeft());
if (geo.width() != 0 && geo.height() != 0) {
if (!geo.contains(QListView::visualRect(index))) {
isFull = true;
}
}
}
if (isFull) resolutionChange();
});
});
setModel(m_proxy_model);
//m_proxy_model->sort(0);
m_peonyDbusSer = new PeonyDbusService(this);
m_peonyDbusSer->DbusServerRegister();
setMouseTracking(true);//追踪鼠标
connect(GlobalSettings::getInstance(), &GlobalSettings::valueChanged, this, [=] (const QString &key) {
if (key == DISPLAY_STANDARD_ICONS) {
//this->refresh();
m_proxy_model->invalidate();
this->resolutionChange();
if (isItemsOverlapped()) {
// refresh again?
this->refresh();
QStringList needRelayoutItems;
QRegion notEmptyRegion;
for (auto value : m_item_rect_hash.values()) {
auto keys = m_item_rect_hash.keys(value);
if (keys.count() > 1) {
keys.pop_front();
for (auto key : keys) {
needRelayoutItems.append(key);
m_item_rect_hash.remove(key);
}
}
notEmptyRegion += value;
}
int gridWidth = gridSize().width();
int gridHeight = gridSize().height();
// aligin exsited rect
int marginTop = notEmptyRegion.boundingRect().top();
while (marginTop - gridHeight > 0) {
marginTop -= gridHeight;
}
int marginLeft = notEmptyRegion.boundingRect().left();
while (marginLeft - gridWidth > 0) {
marginLeft -= gridWidth;
}
marginLeft = marginLeft < 0? 0: marginLeft;
marginTop = marginTop < 0? 0: marginTop;
int posX = marginLeft;
int posY = marginTop;
for (auto item : needRelayoutItems) {
QRect itemRect = QRect(posX, posY, gridWidth, gridHeight);
while (notEmptyRegion.contains(itemRect.center())) {
if (posY + 2*gridHeight > this->viewport()->height()) {
posY = marginTop;
posX += gridWidth;
} else {
posY += gridHeight;
}
if (this->viewport()->geometry().contains(itemRect.topLeft())) {
itemRect.moveTo(posX, posY);
} else {
itemRect.moveTo(0, 0);
}
}
notEmptyRegion += itemRect;
m_item_rect_hash.insert(item, itemRect);
}
for (auto uri : m_item_rect_hash.keys()) {
auto rect = m_item_rect_hash.value(uri);
updateItemPosByUri(uri, rect.topLeft());
setFileMetaInfoPos(uri, rect.topLeft());
}
this->saveAllItemPosistionInfos();
}
}
});
//fix task bar overlap with desktop icon and can drag move issue
//bug #27811,33188
if (QGSettings::isSchemaInstalled(PANEL_SETTINGS))
{
//panel monitor
QGSettings *panelSetting = new QGSettings(PANEL_SETTINGS, QByteArray(), this);
connect(panelSetting, &QGSettings::changed, this, [=](const QString &key){
if (key == "panelposition" || key == "panelsize") {
int position = panelSetting->get("panelposition").toInt();
int margins = panelSetting->get("panelsize").toInt();
switch (position) {
case 1: {
setViewportMargins(0, margins, 0, 0);
m_panel_margin = QMargins(0, margins, 0, 0);
break;
}
case 2: {
setViewportMargins(margins, 0, 0, 0);
m_panel_margin = QMargins(margins, 0, 0, 0);
break;
}
case 3: {
setViewportMargins(0, 0, margins, 0);
m_panel_margin = QMargins(0, 0, margins, 0);
break;
}
default: {
setViewportMargins(0, 0, 0, margins);
m_panel_margin = QMargins(0, 0, 0, margins);
break;
}
}
}
if (m_initialized)
resolutionChange();
});
}
// try fixing #63358
if (QGSettings::isSchemaInstalled(UKUI_STYLE_SETTINGS)) {
auto styleSettings = new QGSettings(UKUI_STYLE_SETTINGS, QByteArray(), this);
connect(styleSettings, &QGSettings::changed, this, [=](const QString &key){
if (key == "iconThemeName") {
QTimer::singleShot(1000, viewport(), [=]{
viewport()->update();
});
}
});
}
}
void DesktopIconView::setId(int id)
{
m_proxy_model->setId(id);
m_id = id ;
}
DesktopIconView::~DesktopIconView()
{
delete m_peonyDbusSer;
//saveAllItemPosistionInfos();
}
bool DesktopIconView::eventFilter(QObject *obj, QEvent *e)
{
//fixme:
//comment to fix change night style refresh desktop issue
if (e->type() == QEvent::StyleChange || e->type() == QEvent::ApplicationFontChange || e->type() == QEvent::FontChange) {
auto type = e->type();
if (m_proxy_model) {
for (auto uri : getAllFileUris()) {
auto pos = getFileMetaInfoPos(uri);
if (pos.x() >= 0)
updateItemPosByUri(uri, pos);
}
QTimer::singleShot(0, this, [=]{
for (auto uri : getAllFileUris()) {
auto pos = getFileMetaInfoPos(uri);
if (pos.x() >= 0)
updateItemPosByUri(uri, pos);
}
});
}
}
return false;
}
static bool meetSpecialConditions(const QStringList& selectedUris)
{
/* The desktop home directory, computer, and trash do not allow operations such as copying, cutting,
* deleting, renaming, moving, or using shortcut keys for corresponding operations.add by 2021/06/17 */
static QString homeUri = "file://" + QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
if (selectedUris.contains("computer:///")
||selectedUris.contains("trash:///")
||selectedUris.contains(homeUri)){
return true;
}
return false;
}
void DesktopIconView::initShoutCut()
{
QAction *copyAction = new QAction(this);
copyAction->setShortcut(QKeySequence::Copy);
connect(copyAction, &QAction::triggered, [=]() {
auto selectedUris = this->getSelections();
if (!selectedUris.isEmpty() && !meetSpecialConditions(selectedUris)){
ClipboardUtils::setClipboardFiles(selectedUris, false);}
});
addAction(copyAction);
QAction *cutAction = new QAction(this);
cutAction->setShortcut(QKeySequence::Cut);
connect(cutAction, &QAction::triggered, [=]() {
auto selectedUris = this->getSelections();
if (!selectedUris.isEmpty() && !meetSpecialConditions(selectedUris))
{
ClipboardUtils::setClipboardFiles(selectedUris, true);
this->update();
}
});
addAction(cutAction);
QAction *pasteAction = new QAction(this);
pasteAction->setShortcut(QKeySequence::Paste);
connect(pasteAction, &QAction::triggered, [=]() {
if (qApp->clipboard()->mimeData()->hasFormat ("uos/remote-copy")) {
ClipboardUtils::pasteClipboardFiles(this->getDirectoryUri());
} else {
//auto clipUris = ClipboardUtils::getClipboardFilesUris();
if (ClipboardUtils::isClipboardHasFiles() && !meetSpecialConditions(this->getSelections())) {
ClipboardUtils::pasteClipboardFiles(this->getDirectoryUri());
}
}
});
addAction(pasteAction);
//add CTRL+D for delete operation
auto trashAction = new QAction(this);
trashAction->setShortcuts(QList<QKeySequence>()<<Qt::Key_Delete<<QKeySequence(Qt::CTRL + Qt::Key_D));
connect(trashAction, &QAction::triggered, [=]() {
auto selectedUris = getSelections();
if (!selectedUris.isEmpty() && !meetSpecialConditions(selectedUris)){
FileOperationUtils::trash(selectedUris, true);
}
});
addAction(trashAction);
QAction *undoAction = new QAction(this);
undoAction->setShortcut(QKeySequence::Undo);
connect(undoAction, &QAction::triggered,
[=]() {
// do not relayout item with undo.
setRenaming(true);
FileOperationManager::getInstance()->undo();
});
addAction(undoAction);
QAction *redoAction = new QAction(this);
redoAction->setShortcut(QKeySequence::Redo);
connect(redoAction, &QAction::triggered,
[=]() {
// do not relayout item with redo.
setRenaming(true);
FileOperationManager::getInstance()->redo();
});
addAction(redoAction);
QAction *zoomInAction = new QAction(this);
zoomInAction->setShortcut(QKeySequence::ZoomIn);
connect(zoomInAction, &QAction::triggered, [=]() {
this->zoomIn();
});
addAction(zoomInAction);
QAction *zoomOutAction = new QAction(this);
zoomOutAction->setShortcut(QKeySequence::ZoomOut);
connect(zoomOutAction, &QAction::triggered, [=]() {
this->zoomOut();
});
addAction(zoomOutAction);
QAction *renameAction = new QAction(this);
renameAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_E));
connect(renameAction, &QAction::triggered, [=]() {
auto selections = this->getSelections();
if (selections.count() == 1 && !meetSpecialConditions(selections)) {
this->editUri(selections.first());
}
});
addAction(renameAction);
QAction *removeAction = new QAction(this);
removeAction->setShortcut(QKeySequence(Qt::SHIFT + Qt::Key_Delete));
connect(removeAction, &QAction::triggered, [=]() {
auto selectedUris = this->getSelections();
if (!meetSpecialConditions(selectedUris)){
qDebug() << "delete" << selectedUris;
clearAllIndexWidgets();
FileOperationUtils::executeRemoveActionWithDialog(selectedUris);
}
});
addAction(removeAction);
QAction *helpAction = new QAction(this);
helpAction->setShortcut(Qt::Key_F1);
connect(helpAction, &QAction::triggered, this, [=]() {
PeonyDesktopApplication::showGuide();
});
addAction(helpAction);
auto propertiesWindowAction = new QAction(this);
propertiesWindowAction->setShortcuts(QList<QKeySequence>()<<QKeySequence(Qt::ALT + Qt::Key_Return)
<<QKeySequence(Qt::ALT + Qt::Key_Enter));
connect(propertiesWindowAction, &QAction::triggered, this, [=]() {
DesktopMenu menu(this);
if (this->getSelections().count() > 0)
{
menu.showProperties(this->getSelections());
}
else
{
QString desktopPath = "file://" + QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
menu.showProperties(desktopPath);
}
});
addAction(propertiesWindowAction);
auto newFolderAction = new QAction(this);
newFolderAction->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_N));
connect(newFolderAction, &QAction::triggered, this, [=]() {
CreateTemplateOperation op(this->getDirectoryUri(), CreateTemplateOperation::EmptyFolder, tr("New Folder"));
op.run();
auto targetUri = op.target();
QTimer::singleShot(500, this, [=]() {
this->scrollToSelection(targetUri);
});
});
addAction(newFolderAction);
QAction *refreshWinAction = new QAction(this);
refreshWinAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_R));
connect(refreshWinAction, &QAction::triggered, [=]() {
this->refresh();
});
addAction(refreshWinAction);
QAction *reverseSelectAction = new QAction(this);
reverseSelectAction->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_L));
connect(reverseSelectAction, &QAction::triggered, [=]() {
this->invertSelections();
});
addAction(reverseSelectAction);
QAction *normalIconAction = new QAction(this);
normalIconAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_0));
connect(normalIconAction, &QAction::triggered, [=]() {
if (this->zoomLevel() == DesktopIconView::Normal)
return;
this->setDefaultZoomLevel(DesktopIconView::Normal);
});
addAction(normalIconAction);
auto refreshAction = new QAction(this);
refreshAction->setShortcut(Qt::Key_F5);
connect(refreshAction, &QAction::triggered, this, [=]() {
this->refresh();
});
addAction(refreshAction);
QAction *editAction = new QAction(this);
editAction->setShortcuts(QList<QKeySequence>()<<QKeySequence(Qt::ALT + Qt::Key_E)<<Qt::Key_F2);
connect(editAction, &QAction::triggered, this, [=]() {
auto selections = this->getSelections();
if (selections.count() == 1) {
this->editUri(selections.first());
}
});
addAction(editAction);
auto settings = GlobalSettings::getInstance();
m_show_hidden = settings->isExist(SHOW_HIDDEN_PREFERENCE)? settings->getValue(SHOW_HIDDEN_PREFERENCE).toBool(): false;
//show hidden action
QAction *showHiddenAction = new QAction(this);
showHiddenAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_H));
addAction(showHiddenAction);
connect(showHiddenAction, &QAction::triggered, this, [=]() {
this->setShowHidden();
});
auto cancelAction = new QAction(this);
cancelAction->setShortcut(Qt::Key_Escape);
connect(cancelAction, &QAction::triggered, [=]() {
if (Peony::ClipboardUtils::isClipboardHasFiles())
{
Peony::ClipboardUtils::clearClipboard();
this->update();
}
});
addAction(cancelAction);
}
void DesktopIconView::initMenu()
{
return;
setContextMenuPolicy(Qt::CustomContextMenu);
// menu
connect(this, &QListView::customContextMenuRequested, this,
[=](const QPoint &pos) {
// FIXME: use other menu
qDebug() << "menu request in desktop icon view";
if (!this->indexAt(pos).isValid()) {
this->clearSelection();
} else {
this->clearSelection();
this->selectionModel()->select(this->indexAt(pos), QItemSelectionModel::Select);
}
QTimer::singleShot(1, [=]() {
DesktopMenu menu(this);
if (this->getSelections().isEmpty()) {
auto action = menu.addAction(tr("set background"));
connect(action, &QAction::triggered, [=]() {
//go to control center set background
PeonyDesktopApplication::gotoSetBackground();
});
}
menu.exec(QCursor::pos());
auto urisToEdit = menu.urisToEdit();
if (urisToEdit.count() == 1) {
QTimer::singleShot(
100, this, [=]() {
this->editUri(urisToEdit.first());
});
}
});
}, Qt::UniqueConnection);
}
void DesktopIconView::setShowHidden()
{
m_show_hidden = !GlobalSettings::getInstance()->getValue(SHOW_HIDDEN_PREFERENCE).toBool();
m_proxy_model->setShowHidden(m_show_hidden);
//fix show hidden file desktop icons overlapped issue
QTimer::singleShot(100, this, [=]() {
resetAllItemPositionInfos();
refresh();
});
}
void DesktopIconView::resolutionChange()
{
qInfo()<<"start resolutionChange()";
QSize screenSize = this->viewport()->size();
// do not relayout items while screen size is empty.
if (screenSize.isEmpty()) {
qWarning()<<"screen size is not avaliable";
return;
}
if (m_item_rect_hash.isEmpty()) {
return;
}
float iconWidth = 0;
float iconHeigth = 0;
// icon size
QSize icon = gridSize();
iconWidth = icon.width();
iconHeigth = icon.height();
QRect screenRect = QRect(0, 0, screenSize.width(), screenSize.height());
qInfo()<<"screen rect:"<<screenRect;
if (!m_item_rect_hash.isEmpty()) {
QList<QPair<QRect, QString>> newPosition;
for (auto i = m_item_rect_hash.constBegin(); i != m_item_rect_hash.constEnd(); ++i) {
newPosition << QPair<QRect, QString>(i.value(), i.key());
}
// not get current size
if (iconWidth == 0 || iconHeigth == 0) {
qDebug() << "Unable to get icon size, need to get it another way!";
return;
}
// qDebug() << "icon width: " << iconWidth << " icon heigth: " << iconHeigth;
// qDebug() << "width:" << screenSize.width() << " height:" << screenSize.height();
std::stable_sort(newPosition.begin(), newPosition.end(), iconSizeLessThan);
//m_item_rect_hash.clear();
// only reset items over viewport.
QRegion notEmptyRegion;
QList<QPair<QRect, QString>> needChanged;
for (auto pair : newPosition) {
if (!screenRect.contains(pair.first)) {
needChanged.append(pair);
if (!m_resolution_item_rect.contains(pair.second)) {
// remember item position before resolution changed.
m_resolution_item_rect.insert(pair.second, m_item_rect_hash.value(pair.second));
//m_item_rect_hash.remove(pair.second);
}
} else {
notEmptyRegion += pair.first;
}
}
qInfo()<<"need changed item"<<needChanged;
// aligin exsited rect
int marginTop = notEmptyRegion.boundingRect().top();
while (marginTop - iconHeigth >= 0) {
marginTop -= iconHeigth;
}
int marginLeft = notEmptyRegion.boundingRect().left();
while (marginLeft - iconWidth >= 0) {
marginLeft -= iconWidth;
}
marginTop = marginTop < 0? 0: marginTop;
marginLeft = marginLeft < 0? 0: marginLeft;
if (!needChanged.isEmpty()) {
qInfo()<<"屏幕过小,有元素超过屏幕范围";
int posX = marginLeft;
int posY = marginTop;
for (int i = 0; i < needChanged.count(); i++) {
while (notEmptyRegion.intersects(QRect(posX, posY, iconWidth, iconHeigth))) {
if (posY + 2 * iconHeigth > screenSize.height()) {
posY = marginTop;
posX += iconWidth;
} else {
posY += iconHeigth;
}
}
QRect newRect = QRect(QPoint(posX, posY), gridSize());
if (posX + iconWidth > screenSize.width()) {
newRect.moveTo(0, 0);
}
m_item_rect_hash.insert(needChanged.at(i).second, newRect);
notEmptyRegion += newRect;
}
} else {
qInfo()<<"没有元素超过屏幕范围";
QStringList itemNeedBeRelayout;
qInfo()<<"尝试恢复超过屏幕范围的元素" <<m_resolution_item_rect;
for (auto uri : m_resolution_item_rect.keys()) {
auto originalRect = m_resolution_item_rect.value(uri);
if (screenRect.contains(originalRect)) {
m_item_rect_hash.insert(uri, originalRect);
m_resolution_item_rect.remove(uri);
} else {
m_item_rect_hash.remove(uri);
itemNeedBeRelayout<<uri;
}
}
qInfo()<<"重排需要更新位置的元素";
relayoutExsitingItems(itemNeedBeRelayout);
// re-layout overlayed items
// for (auto pair : newPosition) {
// if (QRect(0, 0, 10, 10).contains(pair.first.topLeft())) {
// needChanged.append(pair);
// }
// }
// // first item doesn't need re-layout
// if (!needChanged.isEmpty())
// needChanged.removeFirst();
// // 重新计算非空区域
// notEmptyRegion = QRegion();
// for (auto pair : needChanged) {
// m_item_rect_hash.remove(pair.second);
// }
// for (auto rect : m_item_rect_hash.values()) {
// notEmptyRegion += rect;
// }
// int posX = marginLeft;
// int posY = marginTop;
// for (int i = 0; i < needChanged.count(); i++) {
// while (notEmptyRegion.contains(QPoint(posX + iconWidth/2, posY + iconHeigth/2))) {
// if (posY + iconHeigth * 2 > screenSize.height()) {
// posY = marginTop;
// posX += iconWidth;
// } else {
// posY += iconHeigth;
// }
// }
// QRect newRect = QRect(QPoint(posX, posY), gridSize());
// if (posX + iconWidth > screenSize.width()) {
// newRect.moveTo(0, 0);
// }
// notEmptyRegion += newRect;
// m_item_rect_hash.insert(needChanged.at(i).second, newRect);
// }
// // try restore items which's positions changed by resolution changed.
// QStringList needRelayoutItems2;
// for (auto uri : m_resolution_item_rect.keys()) {
// auto rect = m_resolution_item_rect.value(uri);
// if (screenRect.contains(rect)) {
// m_item_rect_hash.insert(uri, rect);
// } else {
// // need be relayout.
// needRelayoutItems2<<uri;
// }
// }
// relayoutExsitingItems(needRelayoutItems2);
}
}
for (auto uri : m_item_rect_hash.keys()) {
auto rect = m_item_rect_hash.value(uri);
updateItemPosByUri(uri, rect.topLeft());
setFileMetaInfoPos(uri, rect.topLeft());
}
setAllRestoreInfo();
this->saveAllItemPosistionInfos();
}
void DesktopIconView::openFileByUri(QString uri)
{
auto info = FileInfo::fromUri(uri);
auto job = new FileInfoJob(info);
job->setAutoDelete();
job->connect(job, &FileInfoJob::queryAsyncFinished, [=]() {
if ((info->isDir() || info->isVolume() || info->isVirtual())) {
QDir dir(info->filePath());
if (! dir.exists())
{
Peony::AudioPlayManager::getInstance()->playWarningAudio();
auto result = QMessageBox::question(nullptr, tr("Open Link failed"),
tr("File not exist, do you want to delete the link file?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
if (result == QMessageBox::Yes) {
qDebug() << "Delete unused symbollink in desktop.";
QStringList selections;
selections.push_back(uri);
FileOperationUtils::trash(selections, true);
}
return;
}
if (! info->uri().startsWith("trash://")
&& ! info->uri().startsWith("computer://")
&& ! info->canExecute())
{
Peony::AudioPlayManager::getInstance()->playWarningAudio();
QMessageBox::critical(nullptr, tr("Open failed"),
tr("Open directory failed, you have no permission!"));
return;
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
QProcess p;
QUrl url = uri;
p.setProgram("peony");
p.setArguments(QStringList() << url.toEncoded() <<"%U&");
qint64 pid;
p.startDetached(&pid);
// send startinfo to kwindowsystem
quint32 timeStamp = QX11Info::isPlatformX11() ? QX11Info::appUserTime() : 0;
KStartupInfoId startInfoId;
startInfoId.initId(KStartupInfo::createNewStartupIdForTimestamp(timeStamp));
startInfoId.setupStartupEnv();
KStartupInfoData data;
data.setHostname();
data.addPid(pid);
QRect rect = info.get()->property("iconGeometry").toRect();
// if (rect.isValid())
// data.setIconGeometry(rect);
data.setLaunchedBy(getpid());
KStartupInfo::sendStartup(startInfoId, data);
#else
QProcess p;
QString strq;
for (int i = 0;i < uri.length();++i) {
if(uri[i] == ' '){
strq += "%20";
}else{
strq += uri[i];
}
}
p.startDetached("peony", QStringList()<<strq<<"%U&");
#endif
} else {
if (!(info->isDesktopFile() && execSharedFileLink(uri))) {
FileLaunchManager::openAsync(uri, false, false);
}
}
this->clearSelection();
});
job->queryAsync();
}
void DesktopIconView::initDoubleClick()
{
connect(this, &QListView::activated, this, [=](const QModelIndex &index) {
qDebug() << "double click" << index.data(FileItemModel::UriRole);
auto uri = index.data(FileItemModel::UriRole).toString();
openFileByUri(uri);
}, Qt::UniqueConnection);
}
void DesktopIconView::saveAllItemPosistionInfos()
{
//qDebug()<<"======================save";
for (int i = 0; i < m_proxy_model->rowCount(); i++) {
auto index = m_proxy_model->index(i, 0);
auto indexRect = QListView::visualRect(index);
QStringList topLeft;
topLeft<<QString::number(indexRect.top());
topLeft<<QString::number(indexRect.left());
auto metaInfo = FileMetaInfo::fromUri(index.data(Qt::UserRole).toString());
if (metaInfo) {
//qDebug()<<"save real"<<index.data()<<topLeft;
metaInfo->setMetaInfoStringList(ITEM_POS_ATTRIBUTE, topLeft);
QRect rect(mapToGlobal(indexRect.topLeft()), indexRect.size());
FileInfo::fromUri(index.data(Qt::UserRole).toString()).get()->setProperty("iconGeometry", rect);
}
}
//qDebug()<<"======================save finished";
}
void DesktopIconView::saveItemPositionInfo(const QString &uri)
{
return;
}
void DesktopIconView::resetAllItemPositionInfos()
{
if (!m_proxy_model)
return;
clearAllRestoreInfo();
m_item_rect_hash.clear();
for (int i = 0; i < m_proxy_model->rowCount(); i++) {
auto index = m_proxy_model->index(i, 0);
auto indexRect = QListView::visualRect(index);
QStringList topLeft;
topLeft<<QString::number(indexRect.top());
topLeft<<QString::number(indexRect.left());
auto metaInfo = FileMetaInfo::fromUri(index.data(Qt::UserRole).toString());
if (metaInfo) {
QStringList tmp;
tmp<<"-1"<<"-1";
metaInfo->setMetaInfoStringList(ITEM_POS_ATTRIBUTE, tmp);
FileInfo::fromUri(index.data(Qt::UserRole).toString()).get()->setProperty("iconGeometry", QVariant());
}
}
}
void DesktopIconView::resetItemPosistionInfo(const QString &uri)
{
return;
}
void DesktopIconView::updateItemPosistions(const QString &uri)
{
return;
}
QPoint DesktopIconView::getFileMetaInfoPos(const QString &uri)
{
auto value = m_item_rect_hash.value(uri);
if (!value.isEmpty())
return value.topLeft();
auto metaInfo = FileMetaInfo::fromUri(uri);
if (metaInfo) {
auto list = metaInfo->getMetaInfoStringList(ITEM_POS_ATTRIBUTE);
if (!list.isEmpty()) {
if (list.count() == 2) {
int top = list.first().toInt();
int left = list.at(1).toInt();
if (top >= 0 && left >= 0) {
QPoint p(left, top);
return p;
}
}
}
}
return QPoint(-1, -1);
}
void DesktopIconView::setFileMetaInfoPos(const QString &uri, const QPoint &pos)
{
auto delegate = qobject_cast<DesktopIconViewDelegate *>(itemDelegate());
QSize iconSize = delegate->sizeHint(QStyleOptionViewItem(), QModelIndex());
m_item_rect_hash.remove(uri);
m_item_rect_hash.insert(uri, QRect(pos, iconSize));
QRect rect(mapToGlobal(pos), iconSize);
FileInfo::fromUri(uri).get()->setProperty("iconGeometry", rect);
auto metaInfo = FileMetaInfo::fromUri(uri);
if (metaInfo) {
QStringList topLeft;
topLeft<<QString::number(pos.y());
topLeft<<QString::number(pos.x());
metaInfo->setMetaInfoStringList(ITEM_POS_ATTRIBUTE, topLeft);
metaInfo->setMetaInfoInt("peony-qt-desktop-id", m_id);
}
}
QMap<QString, QRect> DesktopIconView::getCurrentItemRects()
{
return m_item_rect_hash;
}
int DesktopIconView::removeItemRect(const QString &uri)
{
return m_item_rect_hash.remove(uri);
}
void DesktopIconView::updateItemPosByUri(const QString &uri, const QPoint &pos)
{
auto delegate = qobject_cast<DesktopIconViewDelegate *>(itemDelegate());
QSize iconSize = delegate->sizeHint(QStyleOptionViewItem(), QModelIndex());
auto srcIndex = m_model->indexFromUri(uri);
auto index = m_proxy_model->mapFromSource(srcIndex);
if (index.isValid()) {
setPositionForIndex(pos, index);
m_item_rect_hash.remove(uri);
m_item_rect_hash.insert(uri, QRect(pos, iconSize));
//qDebug()<<"DesktopIconView::updateItemPosByUri"<<m_item_rect_hash[uri]<<" uri:"<<uri;
}
}
void DesktopIconView::ensureItemPosByUri(const QString &uri)
{
auto srcIndex = m_model->indexFromUri(uri);
auto index = m_proxy_model->mapFromSource(srcIndex);
auto rect = QListView::visualRect(index);
if (index.isValid()) {
m_item_rect_hash.remove(uri);
m_item_rect_hash.insert(uri, rect);
setFileMetaInfoPos(uri, rect.topLeft());
}
}
const QStringList DesktopIconView::getSelections()
{
QStringList uris;
auto indexes = selectionModel()->selection().indexes();
for (auto index : indexes) {
uris<<index.data(Qt::UserRole).toString();
}
uris.removeDuplicates();
return uris;
}
const QStringList DesktopIconView::getAllFileUris()
{
QStringList uris;
for (int i = 0; i < m_proxy_model->rowCount(); i++) {
auto index = m_proxy_model->index(i, 0);
uris<<index.data(Qt::UserRole).toString();
}
return uris;
}
void DesktopIconView::setSelections(const QStringList &uris)
{
clearSelection();
for (int i = 0; i < m_proxy_model->rowCount(); i++) {
auto index = m_proxy_model->index(i, 0);
if (uris.contains(index.data(Qt::UserRole).toString())) {
selectionModel()->select(index, QItemSelectionModel::Select);
}
}
}
void DesktopIconView::invertSelections()
{
QItemSelectionModel *selectionModel = this->selectionModel();
const QItemSelection currentSelection = selectionModel->selection();
this->selectAll();
selectionModel->select(currentSelection, QItemSelectionModel::Deselect);
clearAllIndexWidgets();
}
void DesktopIconView::scrollToSelection(const QString &uri)
{
}
int DesktopIconView::getSortType()
{
return m_proxy_model->getSortType();
}
void DesktopIconView::setSortType(int sortType)
{
clearAllRestoreInfo();
m_item_rect_hash.clear();
//resetAllItemPositionInfos();
m_proxy_model->setSortType(sortType);
m_proxy_model->sort(1);
m_proxy_model->sort(0, m_proxy_model->sortOrder());
saveAllItemPosistionInfos();
bool isFull = false;
auto geo = viewport()->rect();
if (geo.width() != 0 && geo.height() != 0) {
for (int i = 0; i < m_proxy_model->rowCount(); i++) {
auto index = m_proxy_model->index(i, 0);
m_item_rect_hash.insert(index.data(Qt::UserRole).toString(), QListView::visualRect(index));
updateItemPosByUri(index.data(Qt::UserRole).toString(), QListView::visualRect(index).topLeft());
if (!geo.contains(QListView::visualRect(index))) {
isFull = true;
}
}
if (isFull) {
resolutionChange();
}
}
}
int DesktopIconView::getSortOrder()
{
return m_proxy_model->sortOrder();
}
void DesktopIconView::setSortOrder(int sortOrder)
{
m_proxy_model->sort(0, Qt::SortOrder(sortOrder));
}
void DesktopIconView::editUri(const QString &uri)
{
clearAllIndexWidgets();
auto origin = FileUtils::getOriginalUri(uri);
QTimer::singleShot(100, this, [=]() {
edit(m_proxy_model->mapFromSource(m_model->indexFromUri(origin)));
});
}
void DesktopIconView::editUris(const QStringList uris)
{
}
void DesktopIconView::scrollTo(const QModelIndex &index, QAbstractItemView::ScrollHint hint)
{
return;
}
void DesktopIconView::setCutFiles(const QStringList &uris)
{
ClipboardUtils::setClipboardFiles(uris, true);
}
void DesktopIconView::closeView()
{
deleteLater();
}
void DesktopIconView::wheelEvent(QWheelEvent *e)
{
if (QApplication::keyboardModifiers() == Qt::ControlModifier)
{
if (e->delta() > 0) {
zoomIn();
} else {
zoomOut();
}
}
}
void DesktopIconView::keyPressEvent(QKeyEvent *e)
{
switch (e->key()) {
case Qt::Key_Home: {
auto boundingRect = getBoundingRect();
QRect homeRect = QRect(boundingRect.topLeft(), this->gridSize());
while (!indexAt(homeRect.center()).isValid()) {
homeRect.translate(0, gridSize().height());
}
auto homeIndex = indexAt(homeRect.center());
selectionModel()->select(homeIndex, QItemSelectionModel::SelectCurrent);
break;
}
case Qt::Key_End: {
auto boundingRect = getBoundingRect();
QRect endRect = QRect(boundingRect.bottomRight(), this->gridSize());
endRect.translate(-gridSize().width(), -gridSize().height());
while (!indexAt(endRect.center()).isValid()) {
endRect.translate(0, -gridSize().height());
}
auto endIndex = indexAt(endRect.center());
selectionModel()->select(endIndex, QItemSelectionModel::SelectCurrent);
break;
}
case Qt::Key_Up: {
if (getSelections().isEmpty()) {
selectionModel()->select(model()->index(0, 0), QItemSelectionModel::SelectCurrent);
} else {
auto index = selectionModel()->selectedIndexes().first();
auto center = visualRect(index).center();
auto up = center - QPoint(0, gridSize().height());
auto upIndex = indexAt(up);
if (upIndex.isValid()) {
clearAllIndexWidgets();
selectionModel()->select(upIndex, QItemSelectionModel::SelectCurrent);
auto delegate = qobject_cast<DesktopIconViewDelegate *>(itemDelegate());
auto indexWidget = new DesktopIndexWidget(delegate, viewOptions(), upIndex, this);
setIndexWidget(upIndex, indexWidget);
indexWidget->move(visualRect(upIndex).topLeft());
if (g_isHighVersion) {
for (auto uri : getAllFileUris()) {
auto pos = getFileMetaInfoPos(uri);
if (pos.x() >= 0)
updateItemPosByUri(uri, pos);
}
}
}
}
return;
}
case Qt::Key_Down: {
if (getSelections().isEmpty()) {
selectionModel()->select(model()->index(0, 0), QItemSelectionModel::SelectCurrent);
} else {
auto index = selectionModel()->selectedIndexes().first();
auto center = visualRect(index).center();
auto down = center + QPoint(0, gridSize().height());
auto downIndex = indexAt(down);
if (downIndex.isValid()) {
clearAllIndexWidgets();
selectionModel()->select(downIndex, QItemSelectionModel::SelectCurrent);
auto delegate = qobject_cast<DesktopIconViewDelegate *>(itemDelegate());
auto indexWidget = new DesktopIndexWidget(delegate, viewOptions(), downIndex, this);
setIndexWidget(downIndex, indexWidget);
indexWidget->move(visualRect(downIndex).topLeft());
if (g_isHighVersion) {
for (auto uri : getAllFileUris()) {
auto pos = getFileMetaInfoPos(uri);
if (pos.x() >= 0)
updateItemPosByUri(uri, pos);
}
}
}
}
return;
}
case Qt::Key_Left: {
if (getSelections().isEmpty()) {
selectionModel()->select(model()->index(0, 0), QItemSelectionModel::SelectCurrent);
} else {
auto index = selectionModel()->selectedIndexes().first();
auto center = visualRect(index).center();
auto left = center - QPoint(gridSize().width(), 0);
auto leftIndex = indexAt(left);
if (leftIndex.isValid()) {
clearAllIndexWidgets();
selectionModel()->select(leftIndex, QItemSelectionModel::SelectCurrent);
auto delegate = qobject_cast<DesktopIconViewDelegate *>(itemDelegate());
auto indexWidget = new DesktopIndexWidget(delegate, viewOptions(), leftIndex, this);
setIndexWidget(leftIndex, indexWidget);
indexWidget->move(visualRect(leftIndex).topLeft());
if (g_isHighVersion) {
for (auto uri : getAllFileUris()) {
auto pos = getFileMetaInfoPos(uri);
if (pos.x() >= 0)
updateItemPosByUri(uri, pos);
}
}
}
}
return;
}
case Qt::Key_Right: {
if (getSelections().isEmpty()) {
selectionModel()->select(model()->index(0, 0), QItemSelectionModel::SelectCurrent);
} else {
auto index = selectionModel()->selectedIndexes().first();
auto center = visualRect(index).center();
auto right = center + QPoint(gridSize().width(), 0);
auto rightIndex = indexAt(right);
if (rightIndex.isValid()) {
clearAllIndexWidgets();
selectionModel()->select(rightIndex, QItemSelectionModel::SelectCurrent);
auto delegate = qobject_cast<DesktopIconViewDelegate *>(itemDelegate());
auto indexWidget = new DesktopIndexWidget(delegate, viewOptions(), rightIndex, this);
setIndexWidget(rightIndex, indexWidget);
if (g_isHighVersion) {
for (auto uri : getAllFileUris()) {
auto pos = getFileMetaInfoPos(uri);
if (pos.x() >= 0)
updateItemPosByUri(uri, pos);
}
}
}
}
return;
}
case Qt::Key_Shift:
case Qt::Key_Control:
m_ctrl_or_shift_pressed = true;
m_ctrl_key_pressed = true;
break;
case Qt::Key_Enter:
case Qt::Key_Return:
{
auto selections = this->getSelections();
for (auto uri : selections)
{
openFileByUri(uri);
}
}
break;
default:
return QListView::keyPressEvent(e);
}
}
void DesktopIconView::keyReleaseEvent(QKeyEvent *e)
{
QListView::keyReleaseEvent(e);
m_ctrl_or_shift_pressed = false;
m_ctrl_key_pressed = false;
}
void DesktopIconView::focusOutEvent(QFocusEvent *e)
{
QListView::focusOutEvent(e);
m_ctrl_or_shift_pressed = false;
}
void DesktopIconView::resizeEvent(QResizeEvent *e)
{
qInfo()<<"resize event";
QListView::resizeEvent(e);
//refresh();
if (m_initialized) {
resolutionChange();
} else {
qWarning()<<"model not initialized";
}
}
void DesktopIconView::rowsInserted(const QModelIndex &parent, int start, int end)
{
relayoutExsitingItems(m_model->m_items_need_relayout);
QListView::rowsInserted(parent, start, end);
for (auto uri : getAllFileUris()) {
auto pos = getFileMetaInfoPos(uri);
if (pos.x() >= 0) {
updateItemPosByUri(uri, pos);
}
}
// try fix item overrlapped sometimes, link to #58739
//task#74174 扩展模式下支持拖拽图标放置到扩展屏,当扩展屏没有时会崩溃
if (start == end && m_item_rect_hash.count() > 1) {
auto index = model()->index(start, 0);
auto uri = index.data(Qt::UserRole).toString();
auto itemRectHash = m_item_rect_hash;
itemRectHash.remove(uri);
QRegion notEmptyRegion;
QSize itemRectSize = m_item_rect_hash.first().size();
for (auto rect : itemRectHash.values()) {
notEmptyRegion += rect;
}
auto itemRect = QRect(m_item_rect_hash.value(uri).topLeft(), itemRectSize);
if (notEmptyRegion.intersects(itemRect)) {
// handle overlapped
qWarning()<<"unexpected overrlapped happend";
qDebug()<<"check item rect hash"<<m_item_rect_hash;
QStringList fakeList;
fakeList<<uri;
relayoutExsitingItems(fakeList);
}
if (uri == m_model->m_renaming_file_pos.first || uri == m_model->m_renaming_file_pos.first + ".desktop") {
updateItemPosByUri(uri, m_model->m_renaming_file_pos.second);
} else if (m_model->m_renaming_operation_info.get()) {
if (m_model->m_renaming_operation_info.get()->target() == uri) {
updateItemPosByUri(uri, m_model->m_renaming_file_pos.second);
}
}
}
clearAllIndexWidgets();
}
void DesktopIconView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
{
for (int row = start; row <= end; row++) {
auto uri = model()->index(row, 0).data(Qt::UserRole).toString();
m_item_rect_hash.remove(uri);
m_resolution_item_rect.remove(uri);
// QPoint itemPos(-1, -1);
// setRestoreInfo(uri, itemPos);
}
qDebug() << "[DesktopIconView::rowsAboutToBeRemove] need relayout:" << m_model->m_items_need_relayout;
relayoutExsitingItems(m_model->m_items_need_relayout);
QListView::rowsAboutToBeRemoved(parent, start, end);
// QTimer::singleShot(1, this, [=](){
// for (auto uri : getAllFileUris()) {
// auto pos = getFileMetaInfoPos(uri);
// if (pos.x() >= 0)
// updateItemPosByUri(uri, pos);
// }
// });
clearAllIndexWidgets();
}
bool DesktopIconView::isItemsOverlapped()
{
QList<QRect> itemRects;
if (model()) {
for (int i = 0; i < model()->rowCount(); i++) {
auto index = model()->index(i, 0);
auto rect = QListView::visualRect(index);
if (itemRects.contains(rect))
return true;
itemRects<<QListView::visualRect(index);
}
}
return false;
}
bool DesktopIconView::isRenaming()
{
return m_is_renaming;
}
void DesktopIconView::setRenaming(bool renaming)
{
m_is_renaming = renaming;
}
const QRect DesktopIconView::getBoundingRect()
{
QRegion itemsRegion;
for (int i = 0; i < m_proxy_model->rowCount(); i++) {
auto index = m_proxy_model->index(i, 0);
QRect indexRect = QListView::visualRect(index);
itemsRegion += indexRect;
}
return itemsRegion.boundingRect();
}
void DesktopIconView::relayoutExsitingItems(const QStringList &uris)
{
if (uris.isEmpty() || m_item_rect_hash.isEmpty()) {
return;
}
auto allFileUris = getAllFileUris();
auto ensuredItemRectHash = m_item_rect_hash;
for (auto uri : uris) {
ensuredItemRectHash.remove(uri);
}
QRegion notEmptyRegion;
for (auto rect : ensuredItemRectHash.values()) {
notEmptyRegion += rect;
}
auto grid = this->gridSize();
auto viewRect = this->viewport()->rect();
// aligin exsited rect
int marginTop = notEmptyRegion.isEmpty()? getViewRect().top() : notEmptyRegion.boundingRect().top();
while (marginTop - grid.height() >= 0) {
marginTop -= grid.height();
}
int marginLeft = notEmptyRegion.boundingRect().left();
while (marginLeft - grid.width() >= 0) {
marginLeft -= grid.width();
}
marginLeft = marginLeft < 0? 0: marginLeft;
marginTop = marginTop < 0? 0: marginTop;
for (auto uri : uris) {
if (!allFileUris.contains(uri))
continue;
auto indexRect = QRect(QPoint(marginLeft, marginTop), m_item_rect_hash.values().first().size());
if (notEmptyRegion.intersects(indexRect)) {
// move index to closest empty grid.
auto next = indexRect;
bool isEmptyPos = false;
while (!isEmptyPos) {
next.translate(0, grid.height());
if (next.bottom() > viewRect.bottom()) {
int top = next.y();
while (true) {
if (top < grid.height()) {
break;
}
top-=grid.height();
}
//put item to next column first row
next.moveTo(next.x() + grid.width(), top);
//如果满了就放到00 位置
if (next.right() > viewRect.right()) {
next.moveTo(0, 0);
isEmptyPos = true;
m_item_rect_hash.insert(uri, next);
setFileMetaInfoPos(uri, next.topLeft());
qDebug() << "满屏 " << uri << " point:" <<next.topLeft();
break;
}
}
if (notEmptyRegion.intersects(next))
continue;
isEmptyPos = true;
m_item_rect_hash.insert(uri, next);
notEmptyRegion += next;
setFileMetaInfoPos(uri, next.topLeft());
}
} else {
notEmptyRegion += indexRect;
setFileMetaInfoPos(uri, indexRect.topLeft());
}
}
}
void DesktopIconView::checkItemsOver()
{
QStringList needRelayoutItems;
QRegion notEmptyRegion;
if (model()) {
for (int i = 0; i < model()->rowCount(); i++) {
auto index = model()->index(i, 0);
auto rect = QListView::visualRect(index);
if (notEmptyRegion.intersects(rect)) {
needRelayoutItems.append(index.data(Qt::UserRole).toString());
} else {
notEmptyRegion += rect;
}
}
}
if (0 == needRelayoutItems.size()) {
return;
}
int gridWidth = gridSize().width();
int gridHeight = gridSize().height();
// aligin exsited rect
int marginTop = notEmptyRegion.boundingRect().top();
while (marginTop - gridHeight >= 0) {
marginTop -= gridHeight;
}
int marginLeft = notEmptyRegion.boundingRect().left();
while (marginLeft - gridWidth >= 0) {
marginLeft -= gridWidth;
}
marginLeft = marginLeft < 0? 0: marginLeft;
marginTop = marginTop < 0? 0: marginTop;
int posX = marginLeft;
int posY = marginTop;
qDebug()<<"need relayout items:"<<needRelayoutItems;
bool isFull = false;
for (auto item : needRelayoutItems) {
QRect itemRect = QRect(posX, posY, gridWidth, gridHeight);
while (notEmptyRegion.contains(itemRect.center()) && !isFull) {
if (posY + 2*gridHeight > this->viewport()->height()) {
posY = marginTop;
posX += gridWidth;
} else {
posY += gridHeight;
}
itemRect.moveTo(posX, posY);
if (itemRect.right() > this->viewport()->rect().right()) {
itemRect.moveTo(0, 0);
posX = 0;
posY = 0;
isFull = true;
qDebug() << "满屏 " << item << " point:" <<itemRect.topLeft();
break;
}
}
notEmptyRegion += itemRect;
m_item_rect_hash.insert(item, itemRect);
}
for (auto uri : m_item_rect_hash.keys()) {
auto rect = m_item_rect_hash.value(uri);
updateItemPosByUri(uri, rect.topLeft());
setFileMetaInfoPos(uri, rect.topLeft());
}
}
void DesktopIconView::zoomOut()
{
clearAllIndexWidgets();
switch (zoomLevel()) {
case Huge:
setDefaultZoomLevel(Large);
break;
case Large:
setDefaultZoomLevel(Normal);
break;
case Normal:
setDefaultZoomLevel(Small);
break;
default:
//setDefaultZoomLevel(zoomLevel());
break;
}
}
void DesktopIconView::zoomIn()
{
clearAllIndexWidgets();
switch (zoomLevel()) {
case Small:
setDefaultZoomLevel(Normal);
break;
case Normal:
setDefaultZoomLevel(Large);
break;
case Large:
setDefaultZoomLevel(Huge);
break;
default:
//setDefaultZoomLevel(zoomLevel());
break;
}
}
/*
Small, //icon: 32x32; grid: 56x64; hover rect: 40x56; font: system*0.8
Normal, //icon: 48x48; grid: 64x72; hover rect = 56x64; font: system
Large, //icon: 64x64; grid: 115x135; hover rect = 105x118; font: system*1.2
Huge //icon: 96x96; grid: 130x150; hover rect = 120x140; font: system*1.4
*/
void DesktopIconView::setDefaultZoomLevel(ZoomLevel level)
{
//qDebug()<<"set default zoom level:"<<level;
m_zoom_level = level;
switch (level) {
case Small:
setIconSize(QSize(24, 24));
setGridSize(QSize(5, 5) + itemDelegate()->sizeHint(viewOptions(), QModelIndex()));
break;
case Large:
setIconSize(QSize(64, 64));
setGridSize(QSize(15, 15) + itemDelegate()->sizeHint(viewOptions(), QModelIndex()));
break;
case Huge:
setIconSize(QSize(96, 96));
setGridSize(QSize(20, 20) + itemDelegate()->sizeHint(viewOptions(), QModelIndex()));
break;
default:
m_zoom_level = Normal;
setIconSize(QSize(48, 48));
setGridSize(QSize(10, 10) + itemDelegate()->sizeHint(viewOptions(), QModelIndex()));
break;
}
clearAllIndexWidgets();
auto metaInfo = FileMetaInfo::fromUri("computer:///");
if (metaInfo) {
qDebug()<<"set zoom level"<<m_zoom_level;
metaInfo->setMetaInfoInt("peony-qt-desktop-zoom-level", int(m_zoom_level));
}
resetAllItemPositionInfos();
if (m_model) {
m_model->clearFloatItems();
}
}
DesktopIconView::ZoomLevel DesktopIconView::zoomLevel() const
{
//FIXME:
if (m_zoom_level != Invalid)
return m_zoom_level;
auto metaInfo = FileMetaInfo::fromUri("computer:///");
if (metaInfo) {
auto i = metaInfo->getMetaInfoInt("peony-qt-desktop-zoom-level");
return ZoomLevel(i);
}
GFile *computer = g_file_new_for_uri("computer:///");
GFileInfo *info = g_file_query_info(computer,
"metadata::peony-qt-desktop-zoom-level",
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
nullptr,
nullptr);
char* zoom_level = g_file_info_get_attribute_as_string(info, "metadata::peony-qt-desktop-zoom-level");
if (!zoom_level) {
//qDebug()<<"======================no zoom level meta info\n\n\n";
g_object_unref(info);
g_object_unref(computer);
return Normal;
}
g_object_unref(info);
g_object_unref(computer);
QString zoomLevel = zoom_level;
g_free(zoom_level);
//qDebug()<<ZoomLevel(QString(zoomLevel).toInt())<<"\n\n\n\n\n\n\n\n";
return ZoomLevel(zoomLevel.toInt()) == Invalid? Normal: ZoomLevel(QString(zoomLevel).toInt());
}
void DesktopIconView::setEditFlag(bool edit)
{
m_is_edit = edit;
}
bool DesktopIconView::getEditFlag()
{
return m_is_edit;
}
int DesktopIconView::verticalOffset() const
{
return 0;
}
int DesktopIconView::horizontalOffset() const
{
return 0;
}
void DesktopIconView::restoreItemsPosByMetaInfo()
{
for (auto uri : getAllFileUris()) {
auto pos = getFileMetaInfoPos(uri);
if (pos.x() >= 0) {
updateItemPosByUri(uri, pos);
}
}
}
void DesktopIconView::mousePressEvent(QMouseEvent *e)
{
m_press_pos = e->pos();
// bug extend selection bug
m_real_do_edit = false;
if (e->modifiers() & Qt::ControlModifier)
m_ctrl_key_pressed = true;
else
m_ctrl_key_pressed = false;
if (!m_ctrl_or_shift_pressed) {
if (!indexAt(e->pos()).isValid()) {
clearAllIndexWidgets();
clearSelection();
} else {
auto index = indexAt(e->pos());
m_last_index = index;
//fix rename state has no menuRequest issue, bug#44107
if (! m_is_edit)
{
clearAllIndexWidgets();
//force to recreate new DesktopIndexWidget, to fix not show name issue
if (indexWidget(m_last_index))
setIndexWidget(m_last_index, nullptr);
auto indexWidget = new DesktopIndexWidget(qobject_cast<DesktopIconViewDelegate *>(itemDelegate()), viewOptions(), m_last_index);
setIndexWidget(m_last_index,
indexWidget);
indexWidget->move(visualRect(m_last_index).topLeft());
}
if (g_isHighVersion) {
for (auto uri : getAllFileUris()) {
auto pos = getFileMetaInfoPos(uri);
if (pos.x() >= 0)
updateItemPosByUri(uri, pos);
}
}
}
}
//qDebug()<<m_last_index.data();
if (e->button() != Qt::LeftButton) {
// fix #115384, context menu key issue
if (e->button() == Qt::RightButton) {
auto index = indexAt(e->pos());
if (!selectedIndexes().contains(index)) {
selectionModel()->select(index, QItemSelectionModel::SelectCurrent);
}
}
return;
}
QListView::mousePressEvent(e);
}
void DesktopIconView::mouseReleaseEvent(QMouseEvent *e)
{
QListView::mouseReleaseEvent(e);
this->viewport()->update(viewport()->rect());
}
void DesktopIconView::mouseMoveEvent(QMouseEvent *e)
{
QModelIndex itemIndex = indexAt(e->pos());
if (!itemIndex.isValid()) {
if (QToolTip::isVisible()) {
QToolTip::hideText();
}
}
QListView::mouseMoveEvent(e);
}
void DesktopIconView::mouseDoubleClickEvent(QMouseEvent *event)
{
QListView::mouseDoubleClickEvent(event);
m_real_do_edit = false;
}
void DesktopIconView::dragEnterEvent(QDragEnterEvent *e)
{
m_real_do_edit = false;
auto action = m_ctrl_key_pressed ? Qt::CopyAction : Qt::MoveAction;
qDebug()<<"drag enter event" <<action;
if (e->mimeData()->hasUrls()) {
if (FileUtils::containsStandardPath(e->mimeData()->urls())) {
e->ignore();
return;
}
e->setDropAction(action);
e->accept();
//e->acceptProposedAction();
}
if (e->source() == this) {
m_drag_indexes = selectedIndexes();
} else {
//task#74174 扩展模式下支持拖拽图标放置到扩展屏,获取选中项
auto view = static_cast<DesktopIconView*>(e->source());
if (view) {
m_drag_indexes = view->selectedIndexes();
}
}
}
void DesktopIconView::dragMoveEvent(QDragMoveEvent *e)
{
m_real_do_edit = false;
if (e->keyboardModifiers() & Qt::ControlModifier)
m_ctrl_key_pressed = true;
else
m_ctrl_key_pressed = false;
auto action = m_ctrl_key_pressed ? Qt::CopyAction : Qt::MoveAction;
auto index = indexAt(e->pos());
if (index.isValid() && index != m_last_index) {
QHoverEvent he(QHoverEvent::HoverMove, e->posF(), e->posF());
viewportEvent(&he);
} else {
QHoverEvent he(QHoverEvent::HoverLeave, e->posF(), e->posF());
viewportEvent(&he);
}
e->setDropAction(action);
if (e->isAccepted())
return;
qDebug()<<"drag move event" <<action;
if (this == e->source()) {
e->accept();
return QListView::dragMoveEvent(e);
}
e->accept();
}
void DesktopIconView::dropEvent(QDropEvent *e)
{
// fix #122768, dirty region issues.
this->viewport()->update();
m_model->clearFloatItems();
m_real_do_edit = false;
//qDebug()<<"drop event";
/*!
\todo
fix the bug that move drop action can not move the desktop
item to correct position.
i use copy action to avoid this bug, but the drop indicator
is incorrect.
*/
m_edit_trigger_timer.stop();
if (e->keyboardModifiers() & Qt::ControlModifier) {
m_ctrl_key_pressed = true;
} else {
m_ctrl_key_pressed = false;
}
auto action = m_ctrl_key_pressed ? Qt::CopyAction : Qt::MoveAction;
if (e->keyboardModifiers() & Qt::ShiftModifier) {
action = Qt::TargetMoveAction;
}
qDebug() << "DesktopIconView dropEvent" <<action;
auto index = indexAt(e->pos());
if (index.isValid() || m_ctrl_key_pressed)
{
qDebug() <<"DesktopIconView index copyAction:";
auto urls = e->mimeData()->urls();
QString homePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
QStringList uris;
for (auto url : urls)
{
if (url.toString() == "computer:///")
uris << "computer:///";
else
uris << url.path();
}
//fix can drag copy home folder issue, link to bug#64824
if (uris.contains(homePath) || uris.contains("computer:///"))
return;
}
if (this == e->source() && !m_ctrl_key_pressed) {
qDebug() <<"DesktopIconView index:" <<index <<index.isValid();
bool bmoved = false;
if (index.isValid()) {
auto uri = m_model->indexUri(m_proxy_model->mapToSource(index));
auto info = FileInfo::fromUri(index.data(Qt::UserRole).toString());
if (!info->isDir()||e->mimeData()->urls().contains(uri)) {
return;
}
bmoved = true;
}
if (bmoved) {
//move file to desktop folder
qDebug() << "DesktopIconView move file to folder";
for (auto uuri : e->mimeData()->urls()) {
if ("trash:///" == uuri.toDisplayString() || "computer:///" == uuri.toDisplayString()) {
return;
}
}
m_model->dropMimeData(e->mimeData(), action, -1, -1, this->indexAt(e->pos()));
} else {
// do not trigger file operation, link to: #66345
m_model->setAcceptDropAction(false);
QListView::dropEvent(e);
m_model->setAcceptDropAction(true);
}
QRegion dirtyRegion;
QHash<QModelIndex, QRect> currentIndexesRects;
for (int i = 0; i < m_proxy_model->rowCount(); i++) {
auto tmp = m_proxy_model->index(i, 0);
currentIndexesRects.insert(tmp, QListView::visualRect(tmp));
if (!m_drag_indexes.contains(tmp)) {
dirtyRegion += QListView::visualRect(tmp);
}
}
//fixme: handle overlapping.
if (!m_drag_indexes.isEmpty()) {
// remove info from resolution item rect map.
for (auto index : m_drag_indexes) {
m_resolution_item_rect.remove(index.data(Qt::UserRole).toString());
QPoint itemPos(-1, -1);
QString uri = index.data(Qt::UserRole).toString();
setRestoreInfo(uri, itemPos);
}
QModelIndexList overlappedIndexes;
QModelIndexList unoverlappedIndexes = m_drag_indexes;
for (auto index : unoverlappedIndexes) {
QRect visualRect = QListView::visualRect(index);
if (dirtyRegion.intersects(visualRect)) {
unoverlappedIndexes.removeOne(index);
overlappedIndexes.append(index);
}
}
for (auto index : unoverlappedIndexes) {
// save pos
QTimer::singleShot(1, this, [=]() {
setFileMetaInfoPos(index.data(Qt::UserRole).toString(), QListView::visualRect(index).topLeft());
});
}
auto grid = this->gridSize();
auto viewRect = this->viewport()->rect();
QRegion notEmptyRegion;
for (auto rect : currentIndexesRects) {
notEmptyRegion += rect;
}
for (auto dragedIndex : overlappedIndexes) {
auto indexRect = QListView::visualRect(dragedIndex);
if (notEmptyRegion.intersects(indexRect)) {
// move index to closest empty grid.
auto next = indexRect;
bool isEmptyPos = false;
while (!isEmptyPos) {
next.translate(0, grid.height());
if (next.bottom() > viewRect.bottom()) {
int top = next.y();
while (true) {
if (top < gridSize().height()) {
break;
}
top-=gridSize().height();
}
//put item to next column first column
next.moveTo(next.x() + grid.width(), top);
}
if (notEmptyRegion.intersects(next)) {
continue;
}
isEmptyPos = true;
setPositionForIndex(next.topLeft(), dragedIndex);
setFileMetaInfoPos(dragedIndex.data(Qt::UserRole).toString(), next.topLeft());
notEmptyRegion += next;
}
}
}
// check if there is any item out of view
for (auto index : m_drag_indexes) {
auto indexRect = QListView::visualRect(index);
if (this->viewport()->rect().contains(indexRect)) {
continue;
}
// try relocating invisible item
QRect next(0, 0, 0, 0);
for (auto existedRect = notEmptyRegion.begin(); existedRect != notEmptyRegion.end(); ++existedRect) {
if (this->viewport()->rect().contains(*existedRect)) {
next = *existedRect;
break;
} else if (existedRect == notEmptyRegion.end() - 1
&& next == QRect(0, 0, 0, 0)) {
next = *existedRect;
next.moveTo(0, 0);
}
}
while (next.translated(-grid.width(), 0).x() >= 0) {
next.translate(-grid.width(), 0);
}
while (next.translated(0, -grid.height()).top() >= 0) {
next.translate(0, -grid.height());
}
while (notEmptyRegion.intersects(next)) {
next.translate(0, grid.height());
if (next.bottom() > viewRect.bottom()) {
int top = next.y();
while (true) {
if (top < gridSize().height()) {
break;
}
top-=gridSize().height();
}
//put item to next column first column
next.moveTo(next.x() + grid.width(), top);
}
}
setPositionForIndex(next.topLeft(), index);
setFileMetaInfoPos(index.data(Qt::UserRole).toString(), next.topLeft());
notEmptyRegion += next;
}
}
m_drag_indexes.clear();
auto urls = e->mimeData()->urls();
for (auto url : urls) {
// if (url.path() == QStandardPaths::writableLocation(QStandardPaths::HomeLocation))
// continue;
saveItemPositionInfo(url.toDisplayString());
}
return;
}
//task#74174 扩展模式下支持拖拽图标放置到扩展屏,拖拽释放后进行设置过滤器proxyModel刷新
if (!m_ctrl_key_pressed && dragToOtherScreen(e))
return;
m_model->dropMimeData(e->mimeData(), action, -1, -1, this->indexAt(e->pos()));
//FIXME: save item position
}
void DesktopIconView::startDrag(Qt::DropActions supportedActions)
{
auto indexes = selectedIndexes();
if (indexes.count() > 0) {
auto pos = m_press_pos;
qreal scale = 1.0;
QWidget *window = this->window();
if (window) {
auto windowHandle = window->windowHandle();
if (windowHandle) {
scale = windowHandle->devicePixelRatio();
}
}
auto drag = new QDrag(this);
drag->setMimeData(model()->mimeData(indexes));
QRegion rect;
QHash<QModelIndex, QRect> indexRectHash;
for (auto index : indexes) {
rect += (visualRect(index));
indexRectHash.insert(index, visualRect(index));
}
QRect realRect = rect.boundingRect();
// fix #78263, text displayment is not completed.
//realRect.adjust(-5, -5, 5, 5);
realRect.adjust(-15, -15, 15, 15);
QPixmap pixmap(realRect.size() * scale);
pixmap.fill(Qt::transparent);
pixmap.setDevicePixelRatio(scale);
QPainter painter(&pixmap);
for (auto index : indexes) {
painter.save();
painter.translate(indexRectHash.value(index).topLeft() - rect.boundingRect().topLeft());
itemDelegate()->paint(&painter, viewOptions(), index);
painter.restore();
}
drag->setPixmap(pixmap);
drag->setHotSpot(pos - rect.boundingRect().topLeft() - QPoint(viewportMargins().left(), viewportMargins().top()));
drag->setDragCursor(QPixmap(), m_ctrl_key_pressed? Qt::CopyAction: Qt::MoveAction);
drag->exec(m_ctrl_key_pressed? Qt::CopyAction: Qt::MoveAction);
} else {
return QListView::startDrag(Qt::MoveAction|Qt::CopyAction);
}
}
const QFont DesktopIconView::getViewItemFont(QStyleOptionViewItem *item)
{
return item->font;
// auto font = item->font;
// if (font.pixelSize() <= 0) {
// font = QApplication::font();
// }
// switch (zoomLevel()) {
// case DesktopIconView::Small:
// font.setPixelSize(int(font.pixelSize() * 0.8));
// break;
// case DesktopIconView::Large:
// font.setPixelSize(int(font.pixelSize() * 1.2));
// break;
// case DesktopIconView::Huge:
// font.setPixelSize(int(font.pixelSize() * 1.4));
// break;
// default:
// break;
// }
// return font;
}
void DesktopIconView::clearAllIndexWidgets(const QStringList &uris)
{
if (!model())
return;
int row = 0;
auto index = model()->index(row, 0);
while (index.isValid()) {
if (uris.isEmpty() || uris.contains(index.data(Qt::UserRole).toString())) {
setIndexWidget(index, nullptr);
}
row++;
index = model()->index(row, 0);
}
// avoid dirty region out of index visual rect.
// link to: #77272.
viewport()->update();
}
void DesktopIconView::refresh()
{
this->setCursor(QCursor(Qt::WaitCursor));
// if (m_refresh_timer.isActive())
// return;
//fix refresh clear copy files issue, link to bug#109247
if (Peony::ClipboardUtils::isDesktopFilesBeCut())
Peony::ClipboardUtils::clearClipboard();/* Refresh clear cut status */
if (!m_model)
return;
if (refreshing)
return;
refreshing = true;
m_model->refresh();
//m_refresh_timer.start();
}
QRect DesktopIconView::visualRect(const QModelIndex &index) const
{
auto rect = QListView::visualRect(index);
QPoint p(10, 5);
switch (zoomLevel()) {
case Small:
p *= 0.8;
break;
case Large:
p *= 1.2;
break;
case Huge:
p *= 1.4;
break;
default:
break;
}
rect.moveTo(rect.topLeft() + p);
auto size = itemDelegate()->sizeHint(QStyleOptionViewItem(), index);
rect.setSize(size);
return rect;
}
QRect DesktopIconView::getViewRect()
{
QRect rect = viewport()->rect();
QPoint p(10, 5);
switch (zoomLevel()) {
case Small:
p *= 0.8;
break;
case Large:
p *= 1.2;
break;
case Huge:
p *= 1.4;
break;
default:
break;
}
rect.moveTo(rect.topLeft() + p);
return rect;
}
int DesktopIconView::updateBWList()
{
m_proxy_model->updateBlackAndWriteLists();
/*
* 重新按照既定规则排序,这样可以避免出现空缺和图标重叠的情况
*/
int sortType = GlobalSettings::getInstance()->getValue(LAST_DESKTOP_SORT_ORDER).toInt();
setSortType(sortType);
return 0;
}
void DesktopIconView::setRestoreInfo(QString &uri, QPoint &itemPos)
{
//bug#108126 根据url重新记录要恢复的元素的位置
auto metaInfo = FileMetaInfo::fromUri(uri);
if (metaInfo) {
QStringList restoreInfo;
// restoreInfo<<pixelRatio;
restoreInfo<<QString::number(itemPos.x());
restoreInfo<<QString::number(itemPos.y());
restoreInfo<<QString::number(m_id);
metaInfo->setMetaInfoStringList(RESTORE_ITEM_POS_ATTRIBUTE, restoreInfo);
}
}
void DesktopIconView::setAllRestoreInfo()
{
//bug#108126 超出屏幕的元素记录到metInfo,以便以后恢复
for (auto uri : m_resolution_item_rect.keys()) {
auto metaInfo = FileMetaInfo::fromUri(uri);
if (metaInfo) {
auto rect = m_resolution_item_rect.value(uri);
QStringList restoreInfo;
restoreInfo<<QString::number(rect.topLeft().x());
restoreInfo<<QString::number(rect.topLeft().y());
restoreInfo<<QString::number(m_id);
metaInfo->setMetaInfoStringList(RESTORE_ITEM_POS_ATTRIBUTE, restoreInfo);
}
}
}
void DesktopIconView::getAllRestoreInfo()
{
//bug#108126 一开始加载将上一次超出屏幕的元素恢复
for (auto uri : m_item_rect_hash.keys()) {
auto metaInfo = FileMetaInfo::fromUri(uri);
if (metaInfo) {
QStringList restoreInfo = metaInfo->getMetaInfoStringList(RESTORE_ITEM_POS_ATTRIBUTE);
if (restoreInfo.count() == 3) {
int top = restoreInfo.at(0).toInt();
int left = restoreInfo.at(1).toInt();
int id = restoreInfo.at(2).toInt();
if (id == m_id && top >= 0 && left >= 0) {
QPoint topLeft(top, left);
updateItemPosByUri(uri, topLeft);
setFileMetaInfoPos(uri, topLeft);
QStringList resetInfo;
resetInfo<<"";
metaInfo->setMetaInfoStringList(RESTORE_ITEM_POS_ATTRIBUTE, resetInfo);
}
}
}
}
}
void DesktopIconView::clearAllRestoreInfo()
{
//bug#108126 超出屏幕的元素记录清空
for (auto uri : m_resolution_item_rect.keys()) {
auto metaInfo = FileMetaInfo::fromUri(uri);
if (metaInfo) {
auto rect = m_resolution_item_rect.value(uri);
QStringList restoreInfo;
restoreInfo<<"";
metaInfo->setMetaInfoStringList(RESTORE_ITEM_POS_ATTRIBUTE, restoreInfo);
}
}
m_resolution_item_rect.clear();
}
void DesktopIconView::clearCache()
{
m_item_rect_hash.clear();
m_resolution_item_rect.clear();
}
bool DesktopIconView::execSharedFileLink(const QString uri)
{
auto info = FileInfo::fromUri(uri);
if (info->isEmptyInfo()) {
FileInfoJob j(info);
j.querySync();
}
if (uri.endsWith(".desktop")) {
GKeyFile* key_file = g_key_file_new();
QUrl url = uri;
QString desktopfp = url.path();
g_key_file_load_from_file(key_file, desktopfp.toUtf8().constData(), G_KEY_FILE_KEEP_COMMENTS, nullptr);
GError* error = NULL;
if (g_key_file_has_key(key_file, G_KEY_FILE_DESKTOP_GROUP, "X-Peony-CMD", nullptr)) {
if (g_key_file_has_key(key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, nullptr)) {
g_autofree char* val = g_key_file_get_value(key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, &error);
if (error) {
qWarning() << "get desktop file:" << uri << " name error:" << error->code << " -- " << error->message;
g_error_free(error);
error = nullptr;
} else {
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
QProcess p;
p.setProgram("peony");
QString str = val;
str = str.replace("peony ","");
p.setArguments(QStringList() << str);
qint64 pid;
p.startDetached(&pid);
// send startinfo to kwindowsystem
quint32 timeStamp = QX11Info::isPlatformX11() ? QX11Info::appUserTime() : 0;
KStartupInfoId startInfoId;
startInfoId.initId(KStartupInfo::createNewStartupIdForTimestamp(timeStamp));
startInfoId.setupStartupEnv();
KStartupInfoData data;
data.setHostname();
data.addPid(pid);
QRect rect = info.get()->property("iconGeometry").toRect();
// if (rect.isValid()) {
// data.setIconGeometry(rect);
// }
data.setLaunchedBy(getpid());
KStartupInfo::sendStartup(startInfoId, data);
#else
QProcess p;
QString strq;
for (int i = 0;i < uri.length();++i) {
if(uri[i] == ' '){
strq += "%20";
}else{
strq += uri[i];
}
}
p.startDetached("peony", QStringList()<<strq<<"%U&");
#endif
return true;
}
}
}
}
return false;
}
void DesktopIconView::refreshResolutionChange()
{
setAllRestoreInfo();
getAllRestoreInfo();
}
DesktopItemProxyModel *DesktopIconView::getProxyModel()
{
return m_proxy_model;
}
void DesktopIconView::fileCreated(const QString &uri)
{
qDebug()<<"DesktopIconView::fileCreated,view:" << this;
if (m_new_files_to_be_selected.isEmpty()) {
m_new_files_to_be_selected<<uri;
QTimer::singleShot(500, this, [=]() {
if (this->state() & QAbstractItemView::EditingState)
return;
this->setSelections(m_new_files_to_be_selected);
m_new_files_to_be_selected.clear();
});
} else {
if (!m_new_files_to_be_selected.contains(uri)) {
m_new_files_to_be_selected<<uri;
}
}
auto geo = viewport()->rect();
if (geo.width() != 0 && geo.height() != 0) {
QModelIndex index = m_proxy_model->mapToSource(m_model->indexFromUri(uri));
if (index.isValid()) {
QRect indexRect = visualRect(index);
if (!geo.contains(indexRect)) {
resolutionChange();
}
} else {
qWarning()<<"file is created but not valid in proxy model now";
}
}
}
bool DesktopIconView::dragToOtherScreen(QDropEvent *e)
{
auto view = static_cast<DesktopIconView*>(e->source());
if (this != e->source() && view) {
bool bDropToOtherScreen = false;
for (QModelIndex index : m_drag_indexes) {
auto metaInfo = FileMetaInfo::fromUri(index.data(Qt::UserRole).toString());
if (metaInfo) {
int id = metaInfo->getMetaInfoInt("peony-qt-desktop-id");
if (m_id != id) {
metaInfo->setMetaInfoInt("peony-qt-desktop-id", m_id);
bDropToOtherScreen =true;
}
}
}
if (bDropToOtherScreen) {
QRegion notEmptyRegion;
for (int i = 0; i < m_proxy_model->rowCount(); i++) {
auto tmp = m_proxy_model->index(i, 0);
notEmptyRegion += QListView::visualRect(tmp);
}
auto grid = this->gridSize();
QRect viewRect = getViewRect();
QPoint startPos = view->visualRect(m_drag_indexes[0]).topLeft();
for (QModelIndex index : m_drag_indexes) {
bool isOverRect = false;
QRect rect = view->visualRect(index);
QPoint relativePos = QPoint(rect.topLeft().x() - startPos.x(),rect.topLeft().y() - startPos.y());
QPoint currentPos = e->pos() + relativePos;
int x = currentPos.x()/grid.width()*grid.width();
int y = currentPos.y()/grid.height()*grid.height()+viewRect.topLeft().y();
rect.moveTo(QPoint(x,y));
if (!this->viewport()->rect().contains(rect)) {
if (isFull()) {
rect.moveTo(0, 0);
setFileMetaInfoPos(index.data(Qt::UserRole).toString(), rect.topLeft());
continue;
} else {
rect.moveTo(0, viewRect.topLeft().y());
isOverRect = true;
}
}
if (notEmptyRegion.contains(rect)) {
auto next = rect;
bool isEmptyPos = false;
while (!isEmptyPos) {
next.translate(0, grid.height());
if (next.top() + gridSize().height() > viewRect.bottom()) {
int top = next.y();
while (true) {
if (top < gridSize().height()) {
break;
}
top-=gridSize().height();
}
//put item to next column first column
next.moveTo(next.x() + grid.width(), top);
if (next.left()+grid.width() > this->viewport()->rect().right()) {
if (isFull() || isOverRect) {
next.moveTo(0, 0);
isEmptyPos = true;
setFileMetaInfoPos(index.data(Qt::UserRole).toString(), next.topLeft());
continue;
} else {
next.moveTo(0, top);
isOverRect = true;
}
}
}
if (notEmptyRegion.contains(next.center())) {
continue;
}
isEmptyPos = true;
setFileMetaInfoPos(index.data(Qt::UserRole).toString(), next.topLeft());
notEmptyRegion += next;
}
}
else{
setFileMetaInfoPos(index.data(Qt::UserRole).toString(), rect.topLeft());
notEmptyRegion += rect;
}
}
Q_EMIT updateView();
Q_EMIT view->updateView();
return bDropToOtherScreen;
}
}
return false;
}
void DesktopIconView::saveExtendItemInfo()
{
if (!m_proxy_model)
return;
//task#74174 扩展屏的元素记录到metInfo,以便以后恢复
for (int i = 0; i < m_proxy_model->rowCount(); i++) {
auto index = m_proxy_model->index(i, 0);
auto indexRect = QListView::visualRect(index);
QString str = index.data(Qt::UserRole).toString();
QStringList topLeft;
topLeft<<QString::number(indexRect.top());
topLeft<<QString::number(indexRect.left());
topLeft<<QString::number(m_id);
QString uri = index.data(Qt::UserRole).toString();
auto metaInfo = FileMetaInfo::fromUri(uri);
if (metaInfo) {
qDebug() << "uri:"<<str<<" topLeft:"<<topLeft;
QStringList extendPos = metaInfo->getMetaInfoStringList(RESTORE_EXTEND_ITEM_POS_ATTRIBUTE);
if (extendPos.count() == 3) {
continue;
}
QStringList pos = metaInfo->getMetaInfoStringList(RESTORE_SINGLESCREEN_ITEM_POS_ATTRIBUTE);
if (pos.count() == 2) {
metaInfo->setMetaInfoStringList(ITEM_POS_ATTRIBUTE, pos);
QStringList tmp;
tmp<<"";
metaInfo->setMetaInfoStringList(RESTORE_SINGLESCREEN_ITEM_POS_ATTRIBUTE, tmp);
}
metaInfo->setMetaInfoStringList(RESTORE_EXTEND_ITEM_POS_ATTRIBUTE, topLeft);
metaInfo->setMetaInfoInt("peony-qt-desktop-id", 0);
}
}
}
bool DesktopIconView::isFull()
{
//bug#123045 主屏桌面空间不足,新建的文件未放置到扩展屏桌面上
int colNum = viewport()->width()/gridSize().width();
int rowNum = viewport()->height()/gridSize().height();
qDebug() << "colNum:" <<colNum << "rowNum:"<< rowNum << "total:" << m_proxy_model->rowCount();
if (colNum * rowNum <= m_proxy_model->rowCount()) {
return true;
}
return false;
}
void DesktopIconView::resetExtendItemInfo()
{
if (!m_model)
return;
//bug#108126 一开始加载将上一次超出屏幕的元素恢复
for (int i = 0; i < m_model->rowCount(); i++) {
auto index = m_model->index(i, 0);
QString uri = index.data(Qt::UserRole).toString();
auto metaInfo = FileMetaInfo::fromUri(uri);
auto str = index.data(Qt::UserRole).toString();
if (metaInfo) {
QStringList list = metaInfo->getMetaInfoStringList(RESTORE_EXTEND_ITEM_POS_ATTRIBUTE);
QStringList pos = metaInfo->getMetaInfoStringList(ITEM_POS_ATTRIBUTE);
if (list.count() == 3) {
QString id = list.takeLast();
qDebug() << "[DesktopIconView::resetExtendItemInfo] uri:"<<str<<" peony-qt-desktop-restore-extend-item-position:"<<list<<" id:"<<m_id;
if (id.toInt() != m_id) {
continue;
}
metaInfo->setMetaInfoStringList(ITEM_POS_ATTRIBUTE, list);
metaInfo->setMetaInfoInt("peony-qt-desktop-id", m_id);
QStringList tmp;
tmp<<"";
metaInfo->setMetaInfoStringList(RESTORE_EXTEND_ITEM_POS_ATTRIBUTE, tmp);
qDebug() << "[DesktopIconView::resetExtendItemInfo] need relayout:"<<m_model->m_items_need_relayout;
}
QStringList screenlist = metaInfo->getMetaInfoStringList(RESTORE_SINGLESCREEN_ITEM_POS_ATTRIBUTE);
if (screenlist.count() != 2) {
metaInfo->setMetaInfoStringList(RESTORE_SINGLESCREEN_ITEM_POS_ATTRIBUTE, pos);
}
}
}
}
void DesktopIconView::clearItemRect()
{
m_resolution_item_rect.clear();
m_item_rect_hash.clear();
}
void DesktopIconView::clearExtendItemPos(bool saveId)
{
if (!m_proxy_model)
return;
//重置扩展屏和单屏坐标
qDebug() << "primary screen id:" << m_id ;
for (int i = 0; i < m_proxy_model->rowCount(); i++) {
auto index = m_proxy_model->index(i, 0);
QString uri = index.data(Qt::UserRole).toString();
auto metaInfo = FileMetaInfo::fromUri(uri);
if (metaInfo) {
QStringList tmp;
tmp<<"";
metaInfo->setMetaInfoStringList(RESTORE_SINGLESCREEN_ITEM_POS_ATTRIBUTE, tmp);
if (saveId) {
metaInfo->setMetaInfoStringList(RESTORE_ITEM_POS_ATTRIBUTE, tmp);
QStringList extendPos = metaInfo->getMetaInfoStringList(RESTORE_EXTEND_ITEM_POS_ATTRIBUTE);
if (extendPos.count() == 3) {
tmp.clear();
tmp<<"-1"<<"-1"<<extendPos[2];
}
}
metaInfo->setMetaInfoStringList(RESTORE_EXTEND_ITEM_POS_ATTRIBUTE, tmp);
}
}
}
void DesktopIconView::initViewport()
{
if (!m_initialized) {
qInfo()<<"desktop icon view model inited";
m_initialized = true;
if (!QGSettings::isSchemaInstalled(PANEL_SETTINGS))
return;
//panel
QGSettings *panelSetting = new QGSettings(PANEL_SETTINGS, QByteArray(), this);
int position = panelSetting->get("panelposition").toInt();
int margins = panelSetting->get("panelsize").toInt();
switch (position) {
case 1: {
setViewportMargins(0, margins, 0, 0);
break;
}
case 2: {
setViewportMargins(margins, 0, 0, 0);
break;
}
case 3: {
setViewportMargins(0, 0, margins, 0);
break;
}
default: {
setViewportMargins(0, 0, 0, margins);
break;
}
}
getAllRestoreInfo();
resolutionChange();
setAllRestoreInfo();
}
}
static bool iconSizeLessThan (const QPair<QRect, QString>& p1, const QPair<QRect, QString>& p2)
{
if (p1.first.x() > p2.first.x())
return false;
if (p1.first.x() < p2.first.x())
return true;
if ((p1.first.x() == p2.first.x()))
return p1.first.y() < p2.first.y();
return true;
}