You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1116 lines
42 KiB
C++
1116 lines
42 KiB
C++
/*
|
|
* Copyright 2021 Michail Vourlakos <mvourlakos@gmail.com>
|
|
*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "viewscontroller.h"
|
|
|
|
// local
|
|
#include <config-latte.h>
|
|
#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 <QHeaderView>
|
|
#include <QItemSelection>
|
|
|
|
// KDE
|
|
#include <KMessageWidget>
|
|
#include <KSharedConfig>
|
|
|
|
#if KF5_VERSION_MINOR >= 71
|
|
#include <KIO/OpenUrlJob>
|
|
#else
|
|
#include <KRun>
|
|
#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; i<layoutidindexes.count(); ++i) {
|
|
QString selectedid = layoutidindexes[i].data(Qt::UserRole).toString();
|
|
selectedviews << m_model->currentData(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; i<selectedviews.rowCount(); ++i) {
|
|
if (selectedviews[i].state() == Data::View::IsInvalid) {
|
|
continue;
|
|
}
|
|
|
|
Latte::Data::View copiedview = selectedviews[i];
|
|
|
|
if (selectedviews[i].state() == Data::View::IsCreated) {
|
|
QString storedviewpath = m_handler->layoutsController()->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; i<currentviews.rowCount(); ++i) {
|
|
Data::View cview = currentviews[i];
|
|
cview.isMoveOrigin = false;
|
|
m_model->updateCurrentView(cview.id, cview);
|
|
}
|
|
|
|
Data::ViewsTable clipboardviews = selectedViewsForClipboard();
|
|
|
|
//! reset cut substates for views
|
|
for (int i=0; i<clipboardviews.rowCount(); ++i) {
|
|
clipboardviews[i].isMoveOrigin = false;
|
|
|
|
/* Data::View tempview = m_model->currentData(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; i<currentviews.rowCount(); ++i) {
|
|
Data::View cview = currentviews[i];
|
|
cview.isMoveOrigin = false;
|
|
m_model->updateCurrentView(cview.id, cview);
|
|
}
|
|
|
|
Data::ViewsTable clipboardviews = selectedViewsForClipboard();
|
|
|
|
//! activate cut substates for views
|
|
for (int i=0; i<clipboardviews.rowCount(); ++i) {
|
|
clipboardviews[i].isMoveOrigin = true;
|
|
|
|
Data::View tempview = m_model->currentData(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; i<clipboardviews.rowCount(); ++i) {
|
|
if (clipboardviews[i].isMoveOrigin && clipboardviews[i].originLayout() == currentlayout.id) {
|
|
hascurrentlayoutcuttedviews = true;
|
|
continue;
|
|
}
|
|
|
|
if (clipboardviews[i].isMoveOrigin) {
|
|
//! update cut flags only for real cutted view and not for copied one
|
|
clipboardviews[i].isMoveOrigin = false;
|
|
clipboardviews[i].isMoveDestination = true;
|
|
}
|
|
|
|
appendViewFromViewTemplate(clipboardviews[i]);
|
|
}
|
|
|
|
if (hascurrentlayoutcuttedviews) {
|
|
m_handler->showInlineMessage(i18n("Docks and panels from <b>Paste</b> 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; i<selectedviews.rowCount(); ++i) {
|
|
if (selectedviews[i].state() == Data::View::IsCreated) {
|
|
QString storedviewpath = m_handler->layoutsController()->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; i<selectedviews.rowCount(); ++i) {
|
|
m_model->removeView(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; i<currentlayoutdata.views.rowCount(); ++i) {
|
|
QString vid = currentlayoutdata.views[i].id;
|
|
|
|
if (!clipboardviews.containsId(vid)) {
|
|
continue;
|
|
}
|
|
|
|
if (clipboardviews[vid].isMoveOrigin && (clipboardviews[vid].originLayout() == currentlayoutdata.id)) {
|
|
currentlayoutdata.views[vid].isMoveOrigin = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_model->setOriginalData(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; i<m_model->rowCount(); ++i) {
|
|
Data::View baseview = m_model->at(i);
|
|
|
|
if (!baseview.isMoveDestination || baseview.state()!=Data::View::OriginFromLayout) {
|
|
continue;
|
|
}
|
|
|
|
for (int j=i+1; j<m_model->rowCount(); ++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; i<warnings.count(); ++i) {
|
|
for (int j=0; j<warnings[i].information.rowCount(); ++j) {
|
|
if (!warnings[i].information[j].containment.isValid()) {
|
|
continue;
|
|
}
|
|
|
|
QString cid = warnings[i].information[j].containment.storageId;
|
|
Data::View view = m_model->currentData(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; i<errors.count(); ++i) {
|
|
for (int j=0; j<errors[i].information.rowCount(); ++j) {
|
|
if (!errors[i].information[j].containment.isValid()) {
|
|
continue;
|
|
}
|
|
|
|
QString cid = errors[i].information[j].containment.storageId;
|
|
Data::View view = m_model->currentData(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<QAction *> extraActions,
|
|
const bool &showOpenLayoutAction)
|
|
{
|
|
QList<QAction *> 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<QAction *> 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 <b>Validate</b> 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", "<b>Error #%1: %2</b> <br/>",error.id, error.name);
|
|
message += "<br/>";
|
|
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.<br/>");
|
|
|
|
message += "<br/>";
|
|
message += i18n("<b>Applets:</b><br/>");
|
|
for (int i=0; i<error.information.rowCount(); ++i) {
|
|
QString appletname = error.information[i].applet.visibleName();
|
|
QString appletstorageid = error.information[i].applet.storageId;
|
|
QString viewname = visibleViewName(error.information[i].containment.storageId);
|
|
QString containmentname = viewname.isEmpty() ? error.information[i].containment.visibleName() : viewname;
|
|
QString containmentstorageid = error.information[i].containment.storageId;
|
|
message += i18nc("applets with same id error, applet name, applet id, containment name, containment id",
|
|
" • <b>%1</b> [#%2] inside <b>%3</b> [#%4]<br/>",
|
|
appletname,
|
|
appletstorageid,
|
|
containmentname,
|
|
containmentstorageid);
|
|
}
|
|
|
|
message += "<br/>";
|
|
message += i18n("<b>Possible Solutions:</b><br/>");
|
|
message += i18n(" 1. Activate this layout and restart Latte<br/>");
|
|
message += i18n(" 2. Remove the mentioned applets from your layout<br/>");
|
|
message += i18n(" 3. Update manually the applets id when the layout is <b>not active</b><br/>");
|
|
message += i18n(" 4. Remove this layout totally<br/>");
|
|
|
|
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", "<b>Error #%1: %2</b> <br/><br/>", 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.<br/>");
|
|
|
|
message += "<br/>";
|
|
message += i18n("<b>Pseudo Applets:</b><br/>");
|
|
for (int i=0; i<error.information.rowCount(); ++i) {
|
|
if (!error.information[i].applet.isValid()) {
|
|
continue;
|
|
}
|
|
|
|
QString appletname = error.information[i].applet.visibleName();
|
|
QString appletstorageid = error.information[i].applet.storageId;
|
|
QString viewname = visibleViewName(error.information[i].containment.storageId);
|
|
QString containmentname = viewname.isEmpty() ? error.information[i].containment.visibleName() : viewname;
|
|
QString containmentstorageid = error.information[i].containment.storageId;
|
|
message += i18nc("orphaned pseudo applets, applet name, applet id, containment name, containment id",
|
|
" • <b>%1</b> [#%2] inside <b>%3</b> [#%4]<br/>",
|
|
appletname,
|
|
appletstorageid,
|
|
containmentname,
|
|
containmentstorageid);
|
|
}
|
|
|
|
message += "<br/>";
|
|
message += i18n("<b>Orphaned Subcontainments:</b><br/>");
|
|
for (int i=0; i<error.information.rowCount(); ++i) {
|
|
if (error.information[i].applet.isValid()) {
|
|
continue;
|
|
}
|
|
|
|
QString viewname = visibleViewName(error.information[i].containment.storageId);
|
|
QString containmentname = viewname.isEmpty() ? error.information[i].containment.visibleName() : viewname;
|
|
QString containmentstorageid = error.information[i].containment.storageId;
|
|
message += i18nc("orphaned subcontainments, containment name, containment id",
|
|
" • <b>%1</b> [#%2] <br/>",
|
|
containmentname,
|
|
containmentstorageid);
|
|
}
|
|
|
|
message += "<br/>";
|
|
message += i18n("<b>Possible Solutions:</b><br/>");
|
|
message += i18n(" 1. Update manually the subcontainment id inside pseudo applet settings when the layout is <b>not active</b><br/>");
|
|
message += i18n(" 2. Remove this layout totally<br/>");
|
|
|
|
//! 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", "<b>Warning #%1: %2</b> <br/><br/>", 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.<br/>");
|
|
|
|
message += "<br/>";
|
|
message += i18n("<b>Applets:</b><br/>");
|
|
for (int i=0; i<warning.information.rowCount(); ++i) {
|
|
if (!warning.information[i].applet.isValid()) {
|
|
continue;
|
|
}
|
|
|
|
QString appletname = warning.information[i].applet.visibleName();
|
|
QString appletstorageid = warning.information[i].applet.storageId;
|
|
QString viewname = visibleViewName(warning.information[i].containment.storageId);
|
|
QString containmentname = viewname.isEmpty() ? warning.information[i].containment.visibleName() : viewname;
|
|
QString containmentstorageid = warning.information[i].containment.storageId;
|
|
message += i18nc("applets, applet name, applet id, containment name, containment id",
|
|
" • <b>%1</b> [#%2] inside <b>%3</b> [#%4]<br/>",
|
|
appletname,
|
|
appletstorageid,
|
|
containmentname,
|
|
containmentstorageid);
|
|
}
|
|
|
|
message += "<br/>";
|
|
message += i18n("<b>Containments:</b><br/>");
|
|
for (int i=0; i<warning.information.rowCount(); ++i) {
|
|
if (warning.information[i].applet.isValid()) {
|
|
continue;
|
|
}
|
|
|
|
QString viewname = visibleViewName(warning.information[i].containment.storageId);
|
|
QString containmentname = viewname.isEmpty() ? warning.information[i].containment.visibleName() : viewname;
|
|
QString containmentstorageid = warning.information[i].containment.storageId;
|
|
message += i18nc("containments, containment name, containment id",
|
|
" • <b>%1</b> [#%2] <br/>",
|
|
containmentname,
|
|
containmentstorageid);
|
|
}
|
|
|
|
message += "<br/>";
|
|
message += i18n("<b>Possible Solutions:</b><br/>");
|
|
message += i18n(" 1. Update manually the containments or applets id when the layout is <b>not active</b><br/>");
|
|
message += i18n(" 2. Remove any of the containments or applets that conflict with each other<br/>");
|
|
|
|
//! show message
|
|
showDefaultPersistentErrorWarningInlineMessage(message, KMessageWidget::Warning);
|
|
}
|
|
|
|
void Views::messageForWarningOrphanedSubContainments(const Data::Warning &warning)
|
|
{
|
|
if (warning.id != Data::Warning::ORPHANEDSUBCONTAINMENT) {
|
|
return;
|
|
}
|
|
|
|
QList<int> orphaned;
|
|
|
|
//! construct message
|
|
QString message = i18nc("warning id and title", "<b>Warning #%1: %2</b> <br/><br/>", 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.<br/>");
|
|
|
|
message += "<br/>";
|
|
message += i18n("<b>Orphaned Subcontainments:</b><br/>");
|
|
for (int i=0; i<warning.information.rowCount(); ++i) {
|
|
if (warning.information[i].applet.isValid()) {
|
|
continue;
|
|
}
|
|
|
|
QString viewname = visibleViewName(warning.information[i].containment.storageId);
|
|
QString containmentname = viewname.isEmpty() ? warning.information[i].containment.visibleName() : viewname;
|
|
QString containmentstorageid = warning.information[i].containment.storageId;
|
|
message += i18nc("orphaned subcontainments, containment name, containment id",
|
|
" • <b>%1</b> [#%2] <br/>",
|
|
containmentname,
|
|
containmentstorageid);
|
|
|
|
orphaned << warning.information[i].containment.storageId.toInt();
|
|
}
|
|
|
|
message += "<br/>";
|
|
message += i18n("<b>Possible Solutions:</b><br/>");
|
|
message += i18n(" 1. Click <b>Repair</b> button in order to remove orphaned subcontainments<br/>");
|
|
message += i18n(" 2. Remove manually orphaned subcontainments when the layout is <b>not active</b><br/>");
|
|
|
|
//! add extra repair action
|
|
QAction *repairlayoutaction = new QAction(i18n("Repair"), this);
|
|
repairlayoutaction->setIcon(QIcon::fromTheme("dialog-yes"));
|
|
QList<QAction *> 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; i<orphaned.count(); ++i) {
|
|
centrallayout->removeOrphanedSubContainment(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<QString, Data::View> newviewsresponses;
|
|
QHash<QString, Data::View> cuttedpastedviews;
|
|
QHash<QString, Data::View> cuttedpastedactiveviews;
|
|
|
|
m_debugSaveCall++;
|
|
qDebug() << "org.kde.latte ViewsDialog::save() call: " << m_debugSaveCall << "-------- ";
|
|
|
|
//! add new views that are accepted
|
|
for(int i=0; i<newViews.rowCount(); ++i){
|
|
if (newViews[i].isMoveDestination) {
|
|
CentralLayout *originActive = originLayout(newViews[i]);
|
|
bool inmovebetweenactivelayouts = central->isActive() && 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; i<alteredViews.rowCount(); ++i) {
|
|
if (alteredViews[i].state() == Data::View::IsCreated && !alteredViews[i].isMoveOrigin) {
|
|
qDebug() << "org.kde.latte ViewsDialog::save() updating altered view :: " << alteredViews[i];
|
|
central->updateView(alteredViews[i]);
|
|
}
|
|
}
|
|
|
|
//! remove deprecated views that have been removed from user
|
|
Latte::Data::ViewsTable removedViews = originalViews.subtracted(currentViews);
|
|
|
|
for (int i=0; i<removedViews.rowCount(); ++i) {
|
|
qDebug() << "org.kde.latte ViewsDialog::save() real removing view :: " << removedViews[i];
|
|
central->removeView(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()<Model::Views::columnCount()-1)) {
|
|
m_viewColumnWidths.clear();
|
|
for (int i=0; i<Model::Views::columnCount(); ++i) {
|
|
m_viewColumnWidths << "";
|
|
}
|
|
}
|
|
|
|
m_viewColumnWidths[0] = QString::number(m_view->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<Qt::SortOrder>(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);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|