/* * Copyright 2021 Michail Vourlakos * * This file is part of Latte-Dock * * Latte-Dock 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 2 of * the License, or (at your option) any later version. * * Latte-Dock 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 . * */ #include "viewscontroller.h" // local #include #include "ui_viewsdialog.h" #include "viewsdialog.h" #include "viewshandler.h" #include "viewsmodel.h" #include "viewstableview.h" #include "delegates/namedelegate.h" #include "delegates/singleoptiondelegate.h" #include "delegates/singletextdelegate.h" #include "../generic/generictools.h" #include "../settingsdialog/templateskeeper.h" #include "../../data/errorinformationdata.h" #include "../../layout/genericlayout.h" #include "../../layout/centrallayout.h" #include "../../layouts/manager.h" #include "../../layouts/synchronizer.h" #include "../../view/view.h" // Qt #include #include // KDE #include #include #if KF5_VERSION_MINOR >= 71 #include #else #include #endif namespace Latte { namespace Settings { namespace Controller { Views::Views(Settings::Handler::ViewsHandler *parent) : QObject(parent), m_handler(parent), m_model(new Model::Views(this, m_handler->corona())), m_proxyModel(new QSortFilterProxyModel(this)), m_view(m_handler->ui()->viewsTable), m_storage(KConfigGroup(KSharedConfig::openConfig(),"LatteSettingsDialog").group("ViewsDialog")) { loadConfig(); m_proxyModel->setSourceModel(m_model); connect(m_model, &QAbstractItemModel::dataChanged, this, &Views::dataChanged); connect(m_model, &Model::Views::rowsInserted, this, &Views::dataChanged); connect(m_model, &Model::Views::rowsRemoved, this, &Views::dataChanged); connect(m_handler, &Handler::ViewsHandler::currentLayoutChanged, this, &Views::onCurrentLayoutChanged); init(); } Views::~Views() { saveConfig(); } QAbstractItemModel *Views::proxyModel() const { return m_proxyModel; } QAbstractItemModel *Views::baseModel() const { return m_model; } QTableView *Views::view() const { return m_view; } void Views::init() { m_view->setModel(m_proxyModel); //m_view->setHorizontalHeader(m_headerView); m_view->verticalHeader()->setVisible(false); m_view->setSortingEnabled(true); m_proxyModel->setSortRole(Model::Views::SORTINGROLE); m_proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); m_view->sortByColumn(m_viewSortColumn, m_viewSortOrder); m_view->setItemDelegateForColumn(Model::Views::IDCOLUMN, new Settings::View::Delegate::SingleText(this)); m_view->setItemDelegateForColumn(Model::Views::NAMECOLUMN, new Settings::View::Delegate::NameDelegate(this)); m_view->setItemDelegateForColumn(Model::Views::SCREENCOLUMN, new Settings::View::Delegate::SingleOption(this)); m_view->setItemDelegateForColumn(Model::Views::EDGECOLUMN, new Settings::View::Delegate::SingleOption(this)); m_view->setItemDelegateForColumn(Model::Views::ALIGNMENTCOLUMN, new Settings::View::Delegate::SingleOption(this)); m_view->setItemDelegateForColumn(Model::Views::SUBCONTAINMENTSCOLUMN, new Settings::View::Delegate::SingleText(this)); applyColumnWidths(); m_cutAction = new QAction(QIcon::fromTheme("edit-cut"), i18n("Cut"), m_view); m_cutAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_X)); connect(m_cutAction, &QAction::triggered, this, &Views::cutSelectedViews); m_copyAction = new QAction(QIcon::fromTheme("edit-copy"), i18n("Copy"), m_view); m_copyAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_C)); connect(m_copyAction, &QAction::triggered, this, &Views::copySelectedViews); m_pasteAction = new QAction(QIcon::fromTheme("edit-paste"), i18n("Paste"), m_view); m_pasteAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_V)); connect(m_pasteAction, &QAction::triggered, this, &Views::pasteSelectedViews); m_duplicateAction = new QAction(QIcon::fromTheme("edit-copy"), i18n("Duplicate Here"), m_view); m_duplicateAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_D)); connect(m_duplicateAction, &QAction::triggered, this, &Views::duplicateSelectedViews); m_view->addAction(m_cutAction); m_view->addAction(m_copyAction); m_view->addAction(m_duplicateAction); m_view->addAction(m_pasteAction); onSelectionsChanged(); connect(m_view, &View::ViewsTableView::selectionsChanged, this, &Views::onSelectionsChanged); connect(m_view, &QObject::destroyed, this, &Views::storeColumnWidths); connect(m_view->horizontalHeader(), &QObject::destroyed, this, [&]() { m_viewSortColumn = m_view->horizontalHeader()->sortIndicatorSection(); m_viewSortOrder = m_view->horizontalHeader()->sortIndicatorOrder(); }); } void Views::reset() { m_model->resetData(); //! Clear any templates keeper data in order to produce reupdates if needed m_handler->layoutsController()->templatesKeeper()->clear(); } bool Views::hasChangedData() const { return m_model->hasChangedData(); } bool Views::hasSelectedView() const { return m_view->selectionModel()->hasSelection(); } int Views::selectedViewsCount() const { return m_view->selectionModel()->selectedRows(Model::Views::IDCOLUMN).count(); } int Views::rowForId(QString id) const { for (int i = 0; i < m_proxyModel->rowCount(); ++i) { QString rowId = m_proxyModel->data(m_proxyModel->index(i, Model::Views::IDCOLUMN), Qt::UserRole).toString(); if (rowId == id) { return i; } } return -1; } const Data::ViewsTable Views::selectedViewsCurrentData() const { Data::ViewsTable selectedviews; if (!hasSelectedView()) { return selectedviews; } QModelIndexList layoutidindexes = m_view->selectionModel()->selectedRows(Model::Views::IDCOLUMN); for(int i=0; icurrentData(selectedid); } return selectedviews; } const Latte::Data::View Views::appendViewFromViewTemplate(const Data::View &view) { Data::View newview = view; newview.name = uniqueViewName(view.name); m_model->appendTemporaryView(newview); return newview; } const Latte::Data::View Views::currentData(const QString &id) { return m_model->currentData(id); } Data::ViewsTable Views::selectedViewsForClipboard() { Data::ViewsTable clipboardviews; if (!hasSelectedView()) { return clipboardviews; } Data::ViewsTable selectedviews = selectedViewsCurrentData(); Latte::Data::Layout currentlayout = m_handler->currentData(); for(int i=0; ilayoutsController()->templatesKeeper()->storedView(currentlayout.id, selectedviews[i].id); copiedview.setState(Data::View::OriginFromLayout, storedviewpath, currentlayout.id, selectedviews[i].id); } else if (selectedviews[i].state() == Data::View::OriginFromViewTemplate) { copiedview.setState(Data::View::OriginFromViewTemplate, selectedviews[i].originFile(), currentlayout.id, selectedviews[i].id); } else if (selectedviews[i].state() == Data::View::OriginFromLayout) { //! is already in valid values } copiedview.isActive = false; clipboardviews << copiedview; } return clipboardviews; } void Views::copySelectedViews() { qDebug() << Q_FUNC_INFO; if (!hasSelectedView()) { return; } //! reset cut substates for views Data::ViewsTable currentviews = m_model->currentViewsData(); for (int i=0; iupdateCurrentView(cview.id, cview); } Data::ViewsTable clipboardviews = selectedViewsForClipboard(); //! reset cut substates for views for (int i=0; icurrentData(clipboardviews[i].id); tempview.isMoveOrigin = false; m_model->updateCurrentView(tempview.id, tempview);*/ } m_handler->layoutsController()->templatesKeeper()->setClipboardContents(clipboardviews); } void Views::cutSelectedViews() { qDebug() << Q_FUNC_INFO; if (!hasSelectedView()) { return; } //! reset previous move records Data::ViewsTable currentviews = m_model->currentViewsData(); for (int i=0; iupdateCurrentView(cview.id, cview); } Data::ViewsTable clipboardviews = selectedViewsForClipboard(); //! activate cut substates for views for (int i=0; icurrentData(clipboardviews[i].id); tempview.isMoveOrigin = true; m_model->updateCurrentView(tempview.id, tempview); } m_handler->layoutsController()->templatesKeeper()->setClipboardContents(clipboardviews); } void Views::pasteSelectedViews() { Data::ViewsTable clipboardviews = m_handler->layoutsController()->templatesKeeper()->clipboardContents(); Latte::Data::Layout currentlayout = m_handler->currentData(); bool hascurrentlayoutcuttedviews{false}; for(int i=0; ishowInlineMessage(i18n("Docks and panels from Paste action are already present in current layout"), KMessageWidget::Warning); } } void Views::duplicateSelectedViews() { qDebug() << Q_FUNC_INFO; if (!hasSelectedView()) { return; } Data::ViewsTable selectedviews = selectedViewsCurrentData(); Latte::Data::Layout currentlayout = m_handler->currentData(); for(int i=0; ilayoutsController()->templatesKeeper()->storedView(currentlayout.id, selectedviews[i].id); Latte::Data::View duplicatedview = selectedviews[i]; duplicatedview.setState(Data::View::OriginFromLayout, storedviewpath, currentlayout.id, selectedviews[i].id); duplicatedview.isActive = false; appendViewFromViewTemplate(duplicatedview); } else if (selectedviews[i].state() == Data::View::OriginFromViewTemplate || selectedviews[i].state() == Data::View::OriginFromLayout) { Latte::Data::View duplicatedview = selectedviews[i]; duplicatedview.isActive = false; appendViewFromViewTemplate(duplicatedview); } } } void Views::removeSelectedViews() { if (!hasSelectedView()) { return; } Data::ViewsTable selectedviews = selectedViewsCurrentData();; int selectionheadrow = m_model->rowForId(selectedviews[0].id); for (int i=0; iremoveView(selectedviews[i].id); } m_view->selectRow(qBound(0, selectionheadrow, m_model->rowCount()-1)); } void Views::selectRow(const QString &id) { m_view->selectRow(rowForId(id)); } void Views::onCurrentLayoutChanged() { Data::Layout currentlayoutdata = m_handler->currentData(); Data::ViewsTable clipboardviews = m_handler->layoutsController()->templatesKeeper()->clipboardContents(); if (!clipboardviews.isEmpty()) { //! clipboarded views needs to update the relevant flags to loaded views for (int i=0; isetOriginalData(currentlayoutdata.views); //! track viewscountchanged signal for current active layout scenario for (const auto &var : m_currentLayoutConnections) { QObject::disconnect(var); } Latte::CentralLayout *currentlayout = m_handler->centralLayout(currentlayoutdata.id); if (currentlayout && currentlayout->isActive()) { m_currentLayoutConnections << connect(currentlayout, &Layout::GenericLayout::viewsCountChanged, this, [&, currentlayout](){ m_model->updateActiveStatesBasedOn(currentlayout); }); } messagesForErrorsWarnings(currentlayout); } void Views::onSelectionsChanged() { bool hasselectedview = hasSelectedView(); m_cutAction->setVisible(hasselectedview); m_copyAction->setVisible(hasselectedview); m_duplicateAction->setVisible(hasselectedview); m_pasteAction->setEnabled(m_handler->layoutsController()->templatesKeeper()->hasClipboardContents()); } int Views::viewsForRemovalCount() const { if (!hasChangedData()) { return 0; } Latte::Data::ViewsTable originalViews = m_model->originalViewsData(); Latte::Data::ViewsTable currentViews = m_model->currentViewsData(); Latte::Data::ViewsTable removedViews = originalViews.subtracted(currentViews); return removedViews.rowCount(); } bool Views::hasValidOriginView(const Data::View &view) { bool viewidisinteger{true}; int vid_int = view.originView().toInt(&viewidisinteger); QString vid_str = view.originView(); if (vid_str.isEmpty() || !viewidisinteger || vid_int<=0) { return false; } return true; } CentralLayout *Views::originLayout(const Data::View &view) { QString origincurrentid = view.originLayout(); Data::Layout originlayoutdata = m_handler->layoutsController()->originalData(origincurrentid); Latte::CentralLayout *originactive = m_handler->layoutsController()->isLayoutOriginal(origincurrentid) ? m_handler->corona()->layoutsManager()->synchronizer()->centralLayout(originlayoutdata.name) : nullptr; return originactive; } void Views::updateDoubledMoveDestinationRows() { //! only one isMoveDestination should exist for each unique move isMoveOrigin case //! all the rest that have been created through Cut/Paste or Duplicate options should become //! simple OriginFromViewTemplate cases for (int i=0; irowCount(); ++i) { Data::View baseview = m_model->at(i); if (!baseview.isMoveDestination || baseview.state()!=Data::View::OriginFromLayout) { continue; } for (int j=i+1; jrowCount(); ++j) { Data::View subsequentview = m_model->at(j); if (subsequentview.isMoveDestination && subsequentview.state() == Data::View::OriginFromLayout && subsequentview.originFile() == baseview.originFile() && subsequentview.originLayout() == baseview.originLayout() && subsequentview.originView() == baseview.originView()) { //! this is a subsequent view that needs to be updated properly subsequentview.isMoveDestination = false; subsequentview.isMoveOrigin = false; subsequentview.setState(Data::View::OriginFromViewTemplate, subsequentview.originFile(), QString(), QString()); m_model->updateCurrentView(subsequentview.id, subsequentview); } } } } void Views::messagesForErrorsWarnings(const Latte::CentralLayout *centralLayout, const bool &showNoErrorsMessage) { if (!centralLayout) { return; } Data::Layout currentdata = centralLayout->data(); m_model->clearErrorsAndWarnings(); //! warnings if (currentdata.warnings > 0) { Data::WarningsList warnings = centralLayout->warnings(); // show warnings for (int i=0; i< warnings.count(); ++i) { if (warnings[i].id == Data::Warning::ORPHANEDSUBCONTAINMENT) { messageForWarningOrphanedSubContainments(warnings[i]); } else if (warnings[i].id == Data::Warning::APPLETANDCONTAINMENTWITHSAMEID) { messageForWarningAppletAndContainmentWithSameId(warnings[i]); } } // count warnings per view for (int i=0; icurrentData(cid); if (!view.isValid()) { //! one step back from subcontainment to view in order to find the influenced view id cid = m_model->viewForSubContainment(cid); view = m_model->currentData(cid); } if (view.isValid()) { view.warnings++; m_model->updateCurrentView(cid, view); } } } } //! errors if (currentdata.errors > 0) { Data::ErrorsList errors = centralLayout->errors(); // show errors for (int i=0; i< errors.count(); ++i) { if (errors[i].id == Data::Error::APPLETSWITHSAMEID) { messageForErrorAppletsWithSameId(errors[i]); } else if (errors[i].id == Data::Error::ORPHANEDPARENTAPPLETOFSUBCONTAINMENT) { messageForErrorOrphanedParentAppletOfSubContainment(errors[i]); } } // count errors per view for (int i=0; icurrentData(cid); if (!view.isValid()) { //! one step back from subcontainment to view in order to find the influenced view id cid = m_model->viewForSubContainment(cid); view = m_model->currentData(cid); } if (view.isValid()) { view.errors++; m_model->updateCurrentView(cid, view); } } } } m_handler->layoutsController()->setLayoutCurrentErrorsWarnings(currentdata.id, currentdata.errors, currentdata.warnings); if (showNoErrorsMessage && currentdata.errors == 0 && currentdata.warnings == 0) { m_handler->showInlineMessage(i18n("Really nice! You are good to go, your layout does not report any errors or warnings."), KMessageWidget::Positive, false); } } void Views::showDefaultPersistentErrorWarningInlineMessage(const QString &messageText, const KMessageWidget::MessageType &messageType, QList extraActions, const bool &showOpenLayoutAction) { QList actions; actions << extraActions; if (showOpenLayoutAction) { Data::Layout currentlayout = m_handler->currentData(); //! add default action to open layout QAction *openlayoutaction = new QAction(i18n("Edit Layout"), this); openlayoutaction->setEnabled(!currentlayout.isActive); openlayoutaction->setIcon(QIcon::fromTheme("document-edit")); openlayoutaction->setData(currentlayout.id); actions << openlayoutaction; connect(openlayoutaction, &QAction::triggered, this, [&, openlayoutaction]() { QString file = openlayoutaction->data().toString(); if (!file.isEmpty()) { #if KF5_VERSION_MINOR >= 71 auto job = new KIO::OpenUrlJob(QUrl::fromLocalFile(file), QStringLiteral("text/plain"), this); job->start(); #else KRun::runUrl(QUrl::fromLocalFile(file), QStringLiteral("text/plain"), m_view); #endif showDefaultInlineMessageValidator(); } }); } //! show message m_handler->showInlineMessage(messageText, messageType, true, actions); } void Views::showDefaultInlineMessageValidator() { Data::Layout currentlayout = m_handler->currentData(); //! add default action to open layout QAction *validateaction = new QAction(i18n("Validate"), this); validateaction->setIcon(QIcon::fromTheme("view-refresh")); validateaction->setData(currentlayout.id); QList actions; actions << validateaction; connect(validateaction, &QAction::triggered, this, [&, currentlayout]() { auto centrallayout = m_handler->centralLayout(currentlayout.id); if (centrallayout && !centrallayout->isActive()) { KSharedConfigPtr lFile = KSharedConfig::openConfig(centrallayout->file()); //! update configuration with latest changes lFile->reparseConfiguration(); } messagesForErrorsWarnings(centrallayout, true); }); QString messagetext = i18n("After you have made your layout file changes, please click Validate to confirm them."); //! show message m_handler->showInlineMessage(messagetext, KMessageWidget::Warning, true, actions); } void Views::messageForErrorAppletsWithSameId(const Data::Error &error) { if (error.id != Data::Error::APPLETSWITHSAMEID) { return; } //! construct message QString message = i18nc("error id and title", "Error #%1: %2
",error.id, error.name); message += "
"; message += i18n("In your layout there are two or more applets with same id. Such situation can create crashes, abnormal behavior and data loss when you activate and use this layout.
"); message += "
"; message += i18n("Applets:
"); for (int i=0; i%1 [#%2] inside %3 [#%4]
", appletname, appletstorageid, containmentname, containmentstorageid); } message += "
"; message += i18n("Possible Solutions:
"); message += i18n("  1. Activate this layout and restart Latte
"); message += i18n("  2. Remove the mentioned applets from your layout
"); message += i18n("  3. Update manually the applets id when the layout is not active
"); message += i18n("  4. Remove this layout totally
"); showDefaultPersistentErrorWarningInlineMessage(message, KMessageWidget::Error); } void Views::messageForErrorOrphanedParentAppletOfSubContainment(const Data::Error &error) { if (error.id != Data::Error::ORPHANEDPARENTAPPLETOFSUBCONTAINMENT) { return; } //! construct message QString message = i18nc("error id and title", "Error #%1: %2

", error.id, error.name); message += i18n("In your layout there are orphaned pseudo applets that link to unexistent subcontainments. Such case is for example a systemtray that has lost connection with its child applets. Such situation can create crashes, abnormal behavior and data loss when you activate and use this layout.
"); message += "
"; message += i18n("Pseudo Applets:
"); for (int i=0; i%1 [#%2] inside %3 [#%4]
", appletname, appletstorageid, containmentname, containmentstorageid); } message += "
"; message += i18n("Orphaned Subcontainments:
"); for (int i=0; i%1 [#%2]
", containmentname, containmentstorageid); } message += "
"; message += i18n("Possible Solutions:
"); message += i18n("  1. Update manually the subcontainment id inside pseudo applet settings when the layout is not active
"); message += i18n("  2. Remove this layout totally
"); //! show message showDefaultPersistentErrorWarningInlineMessage(message, KMessageWidget::Error); } void Views::messageForWarningAppletAndContainmentWithSameId(const Data::Warning &warning) { if (warning.id != Data::Warning::APPLETANDCONTAINMENTWITHSAMEID) { return; } //! construct message QString message = i18nc("warning id and title", "Warning #%1: %2

", warning.id, warning.name); message += i18n("In your layout there are applets and containments with the same id. Such situation is not dangerous but it should not occur.
"); message += "
"; message += i18n("Applets:
"); for (int i=0; i%1 [#%2] inside %3 [#%4]
", appletname, appletstorageid, containmentname, containmentstorageid); } message += "
"; message += i18n("Containments:
"); for (int i=0; i%1 [#%2]
", containmentname, containmentstorageid); } message += "
"; message += i18n("Possible Solutions:
"); message += i18n("  1. Update manually the containments or applets id when the layout is not active
"); message += i18n("  2. Remove any of the containments or applets that conflict with each other
"); //! show message showDefaultPersistentErrorWarningInlineMessage(message, KMessageWidget::Warning); } void Views::messageForWarningOrphanedSubContainments(const Data::Warning &warning) { if (warning.id != Data::Warning::ORPHANEDSUBCONTAINMENT) { return; } QList orphaned; //! construct message QString message = i18nc("warning id and title", "Warning #%1: %2

", warning.id, warning.name); message += i18n("In your layout there are orphaned subcontainments that are not used by any dock or panel. Such situation is not dangerous but it is advised to remove them in order to reduce memory usage.
"); message += "
"; message += i18n("Orphaned Subcontainments:
"); for (int i=0; i%1 [#%2]
", containmentname, containmentstorageid); orphaned << warning.information[i].containment.storageId.toInt(); } message += "
"; message += i18n("Possible Solutions:
"); message += i18n("  1. Click Repair button in order to remove orphaned subcontainments
"); message += i18n("  2. Remove manually orphaned subcontainments when the layout is not active
"); //! add extra repair action QAction *repairlayoutaction = new QAction(i18n("Repair"), this); repairlayoutaction->setIcon(QIcon::fromTheme("dialog-yes")); QList extraactions; extraactions << repairlayoutaction; Latte::Data::Layout currentlayout = m_handler->currentData(); connect(repairlayoutaction, &QAction::triggered, this, [&, currentlayout, orphaned]() { auto centrallayout = m_handler->centralLayout(currentlayout.id); for (int i=0; iremoveOrphanedSubContainment(orphaned[i]); } messagesForErrorsWarnings(centrallayout, true); }); //! show message showDefaultPersistentErrorWarningInlineMessage(message, KMessageWidget::Warning, extraactions); } void Views::save() { //! when this function is called we consider that removal has already been approved updateDoubledMoveDestinationRows(); Latte::Data::Layout originallayout = m_handler->originalData(); Latte::Data::Layout currentlayout = m_handler->currentData(); Latte::CentralLayout *central = m_handler->centralLayout(currentlayout.id); //! views in model Latte::Data::ViewsTable originalViews = m_model->originalViewsData(); Latte::Data::ViewsTable currentViews = m_model->currentViewsData(); Latte::Data::ViewsTable alteredViews = m_model->alteredViews(); Latte::Data::ViewsTable newViews = m_model->newViews(); QHash newviewsresponses; QHash cuttedpastedviews; QHash cuttedpastedactiveviews; m_debugSaveCall++; qDebug() << "org.kde.latte ViewsDialog::save() call: " << m_debugSaveCall << "-------- "; //! add new views that are accepted for(int i=0; iisActive() && originActive && central != originActive && hasValidOriginView(newViews[i]); if (inmovebetweenactivelayouts) { cuttedpastedactiveviews[newViews[i].id] = newViews[i]; continue; } cuttedpastedviews[newViews[i].id] = newViews[i]; } if (newViews[i].state() == Data::View::OriginFromViewTemplate) { Data::View addedview = central->newView(newViews[i]); newviewsresponses[newViews[i].id] = addedview; } else if (newViews[i].state() == Data::View::OriginFromLayout) { Data::View adjustedview = newViews[i]; adjustedview.setState(Data::View::OriginFromViewTemplate, newViews[i].originFile(), QString(), QString()); Data::View addedview = central->newView(adjustedview); newviewsresponses[newViews[i].id] = addedview; } } //! update altered views for (int i=0; iupdateView(alteredViews[i]); } } //! remove deprecated views that have been removed from user Latte::Data::ViewsTable removedViews = originalViews.subtracted(currentViews); for (int i=0; iremoveView(removedViews[i]); } //! remove deprecated views from external layouts that must be removed because of Cut->Paste Action for(const auto vid: cuttedpastedviews.keys()){ bool viewidisinteger{true}; int vid_int = cuttedpastedviews[vid].originView().toInt(&viewidisinteger); QString vid_str = cuttedpastedviews[vid].originView(); if (vid_str.isEmpty() || !viewidisinteger || vid_int<=0) { //! ignore origin views that have not been created already continue; } qDebug() << "org.kde.latte ViewsDialog::save() removing cut-pasted view :: " << cuttedpastedviews[vid]; //! Be Careful: Remove deprecated views from Cut->Paste Action QString origincurrentid = cuttedpastedviews[vid].originLayout(); Data::Layout originlayout = m_handler->layoutsController()->originalData(origincurrentid); Latte::CentralLayout *origin = m_handler->centralLayout(originlayout.id); Data::ViewsTable originviews = Latte::Layouts::Storage::self()->views(origin); if (originviews.containsId(vid_str)) { origin->removeView(originviews[vid_str]); } } //! move active views between different active layouts for (const auto vid: cuttedpastedactiveviews.keys()) { Data::View pastedactiveview = cuttedpastedactiveviews[vid]; uint originviewid = pastedactiveview.originView().toUInt(); CentralLayout *origin = originLayout(pastedactiveview); QString originlayoutname = origin->name(); QString destinationlayoutname = originallayout.name; auto view = origin->viewForContainment(originviewid); QString tempviewid = pastedactiveview.id; pastedactiveview.id = QString::number(originviewid); qDebug() << "org.kde.latte ViewsDialog::save() move to another layout cutted-pasted active view :: " << pastedactiveview; if (view) { //! onscreen_view->onscreen_view //! onscreen_view->offscreen_view pastedactiveview.setState(pastedactiveview.state(), pastedactiveview.originFile(), destinationlayoutname, pastedactiveview.originView()); origin->updateView(pastedactiveview); } else { //! offscreen_view->onscreen_view m_handler->corona()->layoutsManager()->moveView(originlayoutname, originviewid, destinationlayoutname); //!is needed in order for layout to not trigger another move pastedactiveview.setState(Data::View::IsCreated, QString(), QString(), QString()); central->updateView(pastedactiveview); } pastedactiveview.setState(Data::View::IsCreated, QString(), QString(), QString()); newviewsresponses[tempviewid] = pastedactiveview; } //! update if ((removedViews.rowCount() > 0) || (newViews.rowCount() > 0)) { m_handler->corona()->layoutsManager()->synchronizer()->syncActiveLayoutsToOriginalFiles(); } //! update model for newly added views for (const auto vid: newviewsresponses.keys()) { m_model->setOriginalView(vid, newviewsresponses[vid]); } //! update all table with latest data and make the original one currentViews = m_model->currentViewsData(); m_model->setOriginalData(currentViews); //! update model activeness if (central->isActive()) { m_model->updateActiveStatesBasedOn(central); } //! Clear any templates keeper data in order to produce reupdates if needed m_handler->layoutsController()->templatesKeeper()->clear(); } QString Views::uniqueViewName(QString name) { if (name.isEmpty()) { return name; } int pos_ = name.lastIndexOf(QRegExp(QString(" - [0-9]+"))); if (m_model->containsCurrentName(name) && pos_ > 0) { name = name.left(pos_); } int i = 2; QString namePart = name; while (m_model->containsCurrentName(name)) { name = namePart + " - " + QString::number(i); i++; } return name; } QString Views::visibleViewName(const QString &id) const { if (id.isEmpty()) { return QString(); } Data::View view = m_model->currentData(id); if (view.isValid()) { return view.name; } return QString(); } void Views::applyColumnWidths() { m_view->horizontalHeader()->setSectionResizeMode(Model::Views::SUBCONTAINMENTSCOLUMN, QHeaderView::Stretch); if (m_viewColumnWidths.count()<(Model::Views::columnCount()-1)) { return; } m_view->setColumnWidth(Model::Views::IDCOLUMN, m_viewColumnWidths[0].toInt()); m_view->setColumnWidth(Model::Views::NAMECOLUMN, m_viewColumnWidths[1].toInt()); m_view->setColumnWidth(Model::Views::SCREENCOLUMN, m_viewColumnWidths[2].toInt()); m_view->setColumnWidth(Model::Views::EDGECOLUMN, m_viewColumnWidths[3].toInt()); m_view->setColumnWidth(Model::Views::ALIGNMENTCOLUMN, m_viewColumnWidths[4].toInt()); } void Views::storeColumnWidths() { if (m_viewColumnWidths.isEmpty() || (m_viewColumnWidths.count()columnWidth(Model::Views::IDCOLUMN)); m_viewColumnWidths[1] = QString::number(m_view->columnWidth(Model::Views::NAMECOLUMN)); m_viewColumnWidths[2] = QString::number(m_view->columnWidth(Model::Views::SCREENCOLUMN)); m_viewColumnWidths[3] = QString::number(m_view->columnWidth(Model::Views::EDGECOLUMN)); m_viewColumnWidths[4] = QString::number(m_view->columnWidth(Model::Views::ALIGNMENTCOLUMN)); } void Views::loadConfig() { QStringList defaultcolumnwidths; defaultcolumnwidths << QString::number(59) << QString::number(256) << QString::number(142) << QString::number(135) << QString::number(131); m_viewColumnWidths = m_storage.readEntry("columnWidths", defaultcolumnwidths); m_viewSortColumn = m_storage.readEntry("sortColumn", (int)Model::Views::SCREENCOLUMN); m_viewSortOrder = static_cast(m_storage.readEntry("sortOrder", (int)Qt::AscendingOrder)); } void Views::saveConfig() { m_storage.writeEntry("columnWidths", m_viewColumnWidths); m_storage.writeEntry("sortColumn", m_viewSortColumn); m_storage.writeEntry("sortOrder", (int)m_viewSortOrder); } } } }