/* * 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 "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 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::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; } 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); } Data::Layout originlayoutdata = m_handler->layoutsController()->originalData(currentlayoutdata.id); auto activelayout = m_handler->layoutsController()->isLayoutOriginal(currentlayoutdata.id) ? m_handler->corona()->layoutsManager()->synchronizer()->centralLayout(originlayoutdata.name) : nullptr; Latte::CentralLayout *currentlayout = activelayout ? activelayout : new Latte::CentralLayout(this, 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) { 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); } } } } } void Views::messageForErrorAppletsWithSameId(const Data::Error &error) { if (error.id != Data::Error::APPLETSWITHSAMEID) { return; } //! construct message QString message = i18nc("error id and title", "Error #%0: %1
").arg(error.id).arg(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%0 [#%1] inside %2 [#%3]
").arg(appletname).arg(appletstorageid).arg(containmentname).arg(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. Try to fix the situation by updating manually the applets id
"); message += i18n("  4. Remove this layout totally
"); //! add actions QAction *openlayoutaction = new QAction(i18n("Open Layout"), this); Data::Layout currentlayout = m_handler->currentData(); openlayoutaction->setData(currentlayout.id); QList actions; actions << openlayoutaction; connect(openlayoutaction, &QAction::triggered, this, [&, openlayoutaction]() { QString file = openlayoutaction->data().toString(); if (!file.isEmpty()) { auto job = new KIO::OpenUrlJob(QUrl::fromLocalFile(file), QStringLiteral("text/plain"), this); job->start(); } }); //! show message m_handler->showInlineMessage(message, KMessageWidget::Error, true, actions); } void Views::messageForErrorOrphanedParentAppletOfSubContainment(const Data::Error &error) { if (error.id != Data::Error::ORPHANEDPARENTAPPLETOFSUBCONTAINMENT) { return; } //! construct message QString message = i18nc("error id and title", "Error #%0: %1

").arg(error.id).arg(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%0 [#%1] inside %2 [#%3]
").arg(appletname).arg(appletstorageid).arg(containmentname).arg(containmentstorageid); } message += "
"; message += i18n("Orphaned Subcontainments:
"); for (int i=0; i%0 [#%1]
").arg(containmentname).arg(containmentstorageid); } message += "
"; message += i18n("Possible Solutions:
"); message += i18n("  1. Try to fix the situation by updating manually the subcontainment id in pseudo applet settings
"); message += i18n("  2. Remove this layout totally
"); //! add actions QAction *openlayoutaction = new QAction(i18n("Open Layout"), this); Data::Layout currentlayout = m_handler->currentData(); openlayoutaction->setData(currentlayout.id); QList actions; actions << openlayoutaction; connect(openlayoutaction, &QAction::triggered, this, [&, openlayoutaction]() { QString file = openlayoutaction->data().toString(); if (!file.isEmpty()) { auto job = new KIO::OpenUrlJob(QUrl::fromLocalFile(file), QStringLiteral("text/plain"), this); job->start(); } }); //! show message m_handler->showInlineMessage(message, KMessageWidget::Error, true, actions); } void Views::messageForWarningAppletAndContainmentWithSameId(const Data::Warning &warning) { if (warning.id != Data::Warning::APPLETANDCONTAINMENTWITHSAMEID) { return; } //! construct message QString message = i18nc("warning id and title", "Warning #%0: %1

").arg(warning.id).arg(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%0 [#%1] inside %2 [#%3]
").arg(appletname).arg(appletstorageid).arg(containmentname).arg(containmentstorageid); } message += "
"; message += i18n("Containments:
"); for (int i=0; i%0 [#%1]
").arg(containmentname).arg(containmentstorageid); } message += "
"; message += i18n("Possible Solutions:
"); message += i18n("  1. Try to fix the situation by updating manually the containments or applets id
"); message += i18n("  2. Remove any of the containments or applets that conflict with each other
"); //! add actions QAction *openlayoutaction = new QAction(i18n("Open Layout"), this); Data::Layout currentlayout = m_handler->currentData(); openlayoutaction->setData(currentlayout.id); QList actions; actions << openlayoutaction; connect(openlayoutaction, &QAction::triggered, this, [&, openlayoutaction]() { QString file = openlayoutaction->data().toString(); if (!file.isEmpty()) { auto job = new KIO::OpenUrlJob(QUrl::fromLocalFile(file), QStringLiteral("text/plain"), this); job->start(); } }); //! show message m_handler->showInlineMessage(message, KMessageWidget::Warning, true, actions); } void Views::messageForWarningOrphanedSubContainments(const Data::Warning &warning) { if (warning.id != Data::Warning::ORPHANEDSUBCONTAINMENT) { return; } //! construct message QString message = i18nc("warning id and title", "Warning #%0: %1

").arg(warning.id).arg(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%0 [#%1]
").arg(containmentname).arg(containmentstorageid); } message += "
"; message += i18n("Possible Solutions:
"); message += i18n("  1. Click Repair button in order to remove them automatically
"); //! add actions QAction *openlayoutaction = new QAction(i18n("Open Layout"), this); QAction *repairlayoutaction = new QAction(i18n("Repair"), this); repairlayoutaction->setEnabled(false); Data::Layout currentlayout = m_handler->currentData(); openlayoutaction->setData(currentlayout.id); QList actions; actions << repairlayoutaction; actions << openlayoutaction; connect(openlayoutaction, &QAction::triggered, this, [&, openlayoutaction]() { QString file = openlayoutaction->data().toString(); if (!file.isEmpty()) { auto job = new KIO::OpenUrlJob(QUrl::fromLocalFile(file), QStringLiteral("text/plain"), this); job->start(); } }); //! show message m_handler->showInlineMessage(message, KMessageWidget::Warning, true, actions); } 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 *centralActive = m_handler->isSelectedLayoutOriginal() ? m_handler->corona()->layoutsManager()->synchronizer()->centralLayout(originallayout.name) : nullptr; Latte::CentralLayout *central = centralActive ? centralActive : new Latte::CentralLayout(this, 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; inewView(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 *originActive = m_handler->layoutsController()->isLayoutOriginal(origincurrentid) ? m_handler->corona()->layoutsManager()->synchronizer()->centralLayout(originlayout.name) : nullptr; Latte::CentralLayout *origin = originActive ? originActive : new Latte::CentralLayout(this, origincurrentid); 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()); centralActive->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); } } } }