File indexing completed on 2024-04-28 17:03:14

0001 /*
0002  * SPDX-FileCopyrightText: 2006 Peter Penz <peter.penz@gmx.at>
0003  * SPDX-FileCopyrightText: 2018 Elvis Angelaccio <elvis.angelaccio@kde.org>
0004  *
0005  * SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 
0008 #include "viewpropertiesdialog.h"
0009 
0010 #include "dolphin_generalsettings.h"
0011 #include "global.h"
0012 #include "kitemviews/kfileitemmodel.h"
0013 #include "viewpropsprogressinfo.h"
0014 #include "views/dolphinview.h"
0015 
0016 #include <KCollapsibleGroupBox>
0017 #include <KLocalizedString>
0018 #include <KMessageBox>
0019 #include <KWindowConfig>
0020 
0021 #include <kwidgetsaddons_version.h>
0022 
0023 #if HAVE_BALOO
0024 #include <Baloo/IndexerConfig>
0025 #endif
0026 
0027 #include <QButtonGroup>
0028 #include <QCheckBox>
0029 #include <QComboBox>
0030 #include <QFormLayout>
0031 #include <QLabel>
0032 #include <QListWidget>
0033 #include <QPushButton>
0034 #include <QRadioButton>
0035 #include <QSpacerItem>
0036 
0037 #include <views/viewproperties.h>
0038 
0039 ViewPropertiesDialog::ViewPropertiesDialog(DolphinView *dolphinView)
0040     : QDialog(dolphinView)
0041     , m_isDirty(false)
0042     , m_dolphinView(dolphinView)
0043     , m_viewProps(nullptr)
0044     , m_viewMode(nullptr)
0045     , m_sortOrder(nullptr)
0046     , m_sorting(nullptr)
0047     , m_sortFoldersFirst(nullptr)
0048     , m_sortHiddenLast(nullptr)
0049     , m_previewsShown(nullptr)
0050     , m_showInGroups(nullptr)
0051     , m_showHiddenFiles(nullptr)
0052     , m_applyToCurrentFolder(nullptr)
0053     , m_applyToSubFolders(nullptr)
0054     , m_applyToAllFolders(nullptr)
0055     , m_useAsDefault(nullptr)
0056 {
0057     Q_ASSERT(dolphinView);
0058     const bool useGlobalViewProps = GeneralSettings::globalViewProps();
0059 
0060     setWindowTitle(i18nc("@title:window", "View Display Style"));
0061 
0062     const QUrl &url = dolphinView->url();
0063     m_viewProps = new ViewProperties(url);
0064     m_viewProps->setAutoSaveEnabled(false);
0065 
0066     auto layout = new QFormLayout(this);
0067     // Otherwise the dialog won't resize when we collapse the KCollapsibleGroupBox.
0068     layout->setSizeConstraint(QLayout::SetFixedSize);
0069 
0070     // create 'Properties' group containing view mode, sorting, sort order and show hidden files
0071     m_viewMode = new QComboBox();
0072     m_viewMode->addItem(QIcon::fromTheme(QStringLiteral("view-list-icons")), i18nc("@item:inlistbox", "Icons"), DolphinView::IconsView);
0073     m_viewMode->addItem(QIcon::fromTheme(QStringLiteral("view-list-details")), i18nc("@item:inlistbox", "Compact"), DolphinView::CompactView);
0074     m_viewMode->addItem(QIcon::fromTheme(QStringLiteral("view-list-tree")), i18nc("@item:inlistbox", "Details"), DolphinView::DetailsView);
0075 
0076     m_sortOrder = new QComboBox();
0077     m_sortOrder->addItem(i18nc("@item:inlistbox Sort", "Ascending"));
0078     m_sortOrder->addItem(i18nc("@item:inlistbox Sort", "Descending"));
0079 
0080     m_sorting = new QComboBox();
0081     const QList<KFileItemModel::RoleInfo> rolesInfo = KFileItemModel::rolesInformation();
0082     for (const KFileItemModel::RoleInfo &info : rolesInfo) {
0083         m_sorting->addItem(info.translation, info.role);
0084     }
0085 
0086     m_sortFoldersFirst = new QCheckBox(i18nc("@option:check", "Show folders first"));
0087     m_sortHiddenLast = new QCheckBox(i18nc("@option:check", "Show hidden files last"));
0088     m_previewsShown = new QCheckBox(i18nc("@option:check", "Show preview"));
0089     m_showInGroups = new QCheckBox(i18nc("@option:check", "Show in groups"));
0090     m_showHiddenFiles = new QCheckBox(i18nc("@option:check", "Show hidden files"));
0091 
0092     auto additionalInfoBox = new KCollapsibleGroupBox();
0093     additionalInfoBox->setTitle(i18nc("@title:group", "Additional Information"));
0094     auto innerLayout = new QVBoxLayout(additionalInfoBox);
0095 
0096     {
0097         QList<QByteArray> visibleRoles = m_viewProps->visibleRoles();
0098         const bool useDefaultRoles = (m_viewProps->viewMode() == DolphinView::DetailsView) && visibleRoles.isEmpty();
0099         if (useDefaultRoles) {
0100             // Using the details view without any additional information (-> additional column)
0101             // makes no sense and leads to a usability problem as no viewport area is available
0102             // anymore. Hence as fallback provide at least a size and date column.
0103             visibleRoles.clear();
0104             visibleRoles.append("text");
0105             visibleRoles.append("size");
0106             visibleRoles.append("modificationtime");
0107             m_viewProps->setVisibleRoles(visibleRoles);
0108         }
0109 
0110         // Add checkboxes
0111         bool indexingEnabled = false;
0112 #if HAVE_BALOO
0113         Baloo::IndexerConfig config;
0114         indexingEnabled = config.fileIndexingEnabled();
0115 #endif
0116 
0117         m_listWidget = new QListWidget();
0118         connect(m_listWidget, &QListWidget::itemChanged, this, &ViewPropertiesDialog::slotItemChanged);
0119         m_listWidget->setSelectionMode(QAbstractItemView::NoSelection);
0120         const QList<KFileItemModel::RoleInfo> rolesInfo = KFileItemModel::rolesInformation();
0121         for (const KFileItemModel::RoleInfo &info : rolesInfo) {
0122             QListWidgetItem *item = new QListWidgetItem(info.translation, m_listWidget);
0123             item->setCheckState(visibleRoles.contains(info.role) ? Qt::Checked : Qt::Unchecked);
0124 
0125             const bool enable =
0126                 ((!info.requiresBaloo && !info.requiresIndexer) || (info.requiresBaloo) || (info.requiresIndexer && indexingEnabled)) && info.role != "text";
0127 
0128             if (!enable) {
0129                 item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
0130             }
0131         }
0132         QLabel *additionalViewOptionsLabel = new QLabel(i18n("Choose what to see on each file or folder:"));
0133         innerLayout->addWidget(additionalViewOptionsLabel);
0134         innerLayout->addWidget(m_listWidget);
0135     }
0136 
0137     QHBoxLayout *sortingLayout = new QHBoxLayout();
0138     sortingLayout->setContentsMargins(0, 0, 0, 0);
0139     sortingLayout->addWidget(m_sortOrder);
0140     sortingLayout->addWidget(m_sorting);
0141 
0142     layout->addRow(i18nc("@label:listbox", "View mode:"), m_viewMode);
0143     layout->addRow(i18nc("@label:listbox", "Sorting:"), sortingLayout);
0144 
0145     layout->addItem(new QSpacerItem(0, Dolphin::VERTICAL_SPACER_HEIGHT, QSizePolicy::Fixed, QSizePolicy::Fixed));
0146 
0147     layout->addRow(i18n("View options:"), m_sortFoldersFirst);
0148     layout->addRow(QString(), m_previewsShown);
0149     layout->addRow(QString(), m_showInGroups);
0150     layout->addRow(QString(), m_showHiddenFiles);
0151     layout->addRow(QString(), m_sortHiddenLast);
0152 
0153     connect(m_viewMode, &QComboBox::currentIndexChanged, this, &ViewPropertiesDialog::slotViewModeChanged);
0154     connect(m_sorting, &QComboBox::currentIndexChanged, this, &ViewPropertiesDialog::slotSortingChanged);
0155     connect(m_sortOrder, &QComboBox::currentIndexChanged, this, &ViewPropertiesDialog::slotSortOrderChanged);
0156     connect(m_sortFoldersFirst, &QCheckBox::clicked, this, &ViewPropertiesDialog::slotSortFoldersFirstChanged);
0157     connect(m_sortHiddenLast, &QCheckBox::clicked, this, &ViewPropertiesDialog::slotSortHiddenLastChanged);
0158     connect(m_previewsShown, &QCheckBox::clicked, this, &ViewPropertiesDialog::slotShowPreviewChanged);
0159     connect(m_showInGroups, &QCheckBox::clicked, this, &ViewPropertiesDialog::slotGroupedSortingChanged);
0160     connect(m_showHiddenFiles, &QCheckBox::clicked, this, &ViewPropertiesDialog::slotShowHiddenFilesChanged);
0161 
0162     // Only show the following settings if the view properties are remembered
0163     // for each directory:
0164     if (!useGlobalViewProps) {
0165         // create 'Apply View Properties To' group
0166         m_applyToCurrentFolder = new QRadioButton(i18nc("@option:radio Apply View Properties To", "Current folder"));
0167         m_applyToCurrentFolder->setChecked(true);
0168         m_applyToSubFolders = new QRadioButton(i18nc("@option:radio Apply View Properties To", "Current folder and sub-folders"));
0169         m_applyToAllFolders = new QRadioButton(i18nc("@option:radio Apply View Properties To", "All folders"));
0170 
0171         QButtonGroup *applyGroup = new QButtonGroup(this);
0172         applyGroup->addButton(m_applyToCurrentFolder);
0173         applyGroup->addButton(m_applyToSubFolders);
0174         applyGroup->addButton(m_applyToAllFolders);
0175 
0176         layout->addItem(new QSpacerItem(0, Dolphin::VERTICAL_SPACER_HEIGHT, QSizePolicy::Fixed, QSizePolicy::Fixed));
0177 
0178         layout->addRow(i18nc("@title:group", "Apply to:"), m_applyToCurrentFolder);
0179         layout->addRow(QString(), m_applyToSubFolders);
0180         layout->addRow(QString(), m_applyToAllFolders);
0181         layout->addRow(QString(), m_applyToAllFolders);
0182 
0183         m_useAsDefault = new QCheckBox(i18nc("@option:check", "Use as default view settings"), this);
0184         layout->addRow(QString(), m_useAsDefault);
0185 
0186         connect(m_applyToCurrentFolder, &QRadioButton::clicked, this, &ViewPropertiesDialog::markAsDirty);
0187         connect(m_applyToSubFolders, &QRadioButton::clicked, this, &ViewPropertiesDialog::markAsDirty);
0188         connect(m_applyToAllFolders, &QRadioButton::clicked, this, &ViewPropertiesDialog::markAsDirty);
0189         connect(m_useAsDefault, &QCheckBox::clicked, this, &ViewPropertiesDialog::markAsDirty);
0190     }
0191 
0192     layout->addItem(new QSpacerItem(0, Dolphin::VERTICAL_SPACER_HEIGHT, QSizePolicy::Fixed, QSizePolicy::Fixed));
0193 
0194     layout->addRow(additionalInfoBox);
0195 
0196     auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Apply, this);
0197     connect(buttonBox, &QDialogButtonBox::accepted, this, &ViewPropertiesDialog::accept);
0198     connect(buttonBox, &QDialogButtonBox::rejected, this, &ViewPropertiesDialog::reject);
0199     layout->addWidget(buttonBox);
0200 
0201     auto okButton = buttonBox->button(QDialogButtonBox::Ok);
0202     okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
0203     okButton->setDefault(true);
0204 
0205     auto applyButton = buttonBox->button(QDialogButtonBox::Apply);
0206     applyButton->setEnabled(false);
0207     connect(applyButton, &QPushButton::clicked, this, &ViewPropertiesDialog::slotApply);
0208     connect(this, &ViewPropertiesDialog::isDirtyChanged, applyButton, [applyButton](bool isDirty) {
0209         applyButton->setEnabled(isDirty);
0210     });
0211 
0212     const KConfigGroup dialogConfig(KSharedConfig::openConfig(QStringLiteral("dolphinrc")), QStringLiteral("ViewPropertiesDialog"));
0213     KWindowConfig::restoreWindowSize(windowHandle(), dialogConfig);
0214 
0215     loadSettings();
0216 }
0217 
0218 ViewPropertiesDialog::~ViewPropertiesDialog()
0219 {
0220     m_isDirty = false;
0221     delete m_viewProps;
0222     m_viewProps = nullptr;
0223 
0224     KConfigGroup dialogConfig(KSharedConfig::openConfig(QStringLiteral("dolphinrc")), QStringLiteral("ViewPropertiesDialog"));
0225     KWindowConfig::saveWindowSize(windowHandle(), dialogConfig);
0226 }
0227 
0228 void ViewPropertiesDialog::accept()
0229 {
0230     applyViewProperties();
0231     QDialog::accept();
0232 }
0233 
0234 void ViewPropertiesDialog::slotApply()
0235 {
0236     applyViewProperties();
0237     markAsDirty(false);
0238 }
0239 
0240 void ViewPropertiesDialog::slotViewModeChanged(int index)
0241 {
0242     const QVariant itemData = m_viewMode->itemData(index);
0243     const DolphinView::Mode viewMode = static_cast<DolphinView::Mode>(itemData.toInt());
0244     m_viewProps->setViewMode(viewMode);
0245     markAsDirty(true);
0246 }
0247 
0248 void ViewPropertiesDialog::slotSortingChanged(int index)
0249 {
0250     const QByteArray role = m_sorting->itemData(index).toByteArray();
0251     m_viewProps->setSortRole(role);
0252     markAsDirty(true);
0253 }
0254 
0255 void ViewPropertiesDialog::slotSortOrderChanged(int index)
0256 {
0257     const Qt::SortOrder sortOrder = (index == 0) ? Qt::AscendingOrder : Qt::DescendingOrder;
0258     m_viewProps->setSortOrder(sortOrder);
0259     markAsDirty(true);
0260 }
0261 
0262 void ViewPropertiesDialog::slotGroupedSortingChanged()
0263 {
0264     m_viewProps->setGroupedSorting(m_showInGroups->isChecked());
0265     markAsDirty(true);
0266 }
0267 
0268 void ViewPropertiesDialog::slotSortFoldersFirstChanged()
0269 {
0270     const bool foldersFirst = m_sortFoldersFirst->isChecked();
0271     m_viewProps->setSortFoldersFirst(foldersFirst);
0272     markAsDirty(true);
0273 }
0274 
0275 void ViewPropertiesDialog::slotSortHiddenLastChanged()
0276 {
0277     const bool hiddenLast = m_sortHiddenLast->isChecked();
0278     m_viewProps->setSortHiddenLast(hiddenLast);
0279     markAsDirty(true);
0280 }
0281 
0282 void ViewPropertiesDialog::slotShowPreviewChanged()
0283 {
0284     const bool show = m_previewsShown->isChecked();
0285     m_viewProps->setPreviewsShown(show);
0286     markAsDirty(true);
0287 }
0288 
0289 void ViewPropertiesDialog::slotShowHiddenFilesChanged()
0290 {
0291     const bool show = m_showHiddenFiles->isChecked();
0292     m_viewProps->setHiddenFilesShown(show);
0293     markAsDirty(true);
0294 }
0295 
0296 void ViewPropertiesDialog::slotItemChanged(QListWidgetItem *item)
0297 {
0298     Q_UNUSED(item)
0299     markAsDirty(true);
0300 }
0301 
0302 void ViewPropertiesDialog::markAsDirty(bool isDirty)
0303 {
0304     if (m_isDirty != isDirty) {
0305         m_isDirty = isDirty;
0306         Q_EMIT isDirtyChanged(isDirty);
0307     }
0308 }
0309 
0310 void ViewPropertiesDialog::applyViewProperties()
0311 {
0312     // if nothing changed in the dialog, we have nothing to apply
0313     if (!m_isDirty) {
0314         return;
0315     }
0316 
0317     // Update visible roles.
0318     {
0319         QList<QByteArray> visibleRoles;
0320         int index = 0;
0321         const QList<KFileItemModel::RoleInfo> rolesInfo = KFileItemModel::rolesInformation();
0322         for (const KFileItemModel::RoleInfo &info : rolesInfo) {
0323             const QListWidgetItem *item = m_listWidget->item(index);
0324             if (item->checkState() == Qt::Checked) {
0325                 visibleRoles.append(info.role);
0326             }
0327             ++index;
0328         }
0329 
0330         m_viewProps->setVisibleRoles(visibleRoles);
0331     }
0332 
0333     const bool applyToSubFolders = m_applyToSubFolders && m_applyToSubFolders->isChecked();
0334     if (applyToSubFolders) {
0335         const QString text(i18nc("@info", "The view properties of all sub-folders will be changed. Do you want to continue?"));
0336         if (KMessageBox::questionTwoActions(this, text, {}, KStandardGuiItem::cont(), KStandardGuiItem::cancel()) == KMessageBox::SecondaryAction) {
0337             return;
0338         }
0339 
0340         ViewPropsProgressInfo *info = new ViewPropsProgressInfo(m_dolphinView, m_dolphinView->url(), *m_viewProps);
0341         info->setAttribute(Qt::WA_DeleteOnClose);
0342         info->setWindowModality(Qt::NonModal);
0343         info->show();
0344     }
0345 
0346     const bool applyToAllFolders = m_applyToAllFolders && m_applyToAllFolders->isChecked();
0347 
0348     // If the user selected 'Apply To All Folders' the view properties implicitly
0349     // are also used as default for new folders.
0350     const bool useAsDefault = applyToAllFolders || (m_useAsDefault && m_useAsDefault->isChecked());
0351     if (useAsDefault) {
0352         // For directories where no .directory file is available, the .directory
0353         // file stored for the global view properties is used as fallback. To update
0354         // this file we temporary turn on the global view properties mode.
0355         Q_ASSERT(!GeneralSettings::globalViewProps());
0356 
0357         GeneralSettings::setGlobalViewProps(true);
0358         ViewProperties defaultProps(m_dolphinView->url());
0359         defaultProps.setDirProperties(*m_viewProps);
0360         defaultProps.save();
0361         GeneralSettings::setGlobalViewProps(false);
0362     }
0363 
0364     if (applyToAllFolders) {
0365         const QString text(i18nc("@info", "The view properties of all folders will be changed. Do you want to continue?"));
0366         if (KMessageBox::questionTwoActions(this, text, {}, KStandardGuiItem::cont(), KStandardGuiItem::cancel()) == KMessageBox::SecondaryAction) {
0367             return;
0368         }
0369 
0370         // Updating the global view properties time stamp in the general settings makes
0371         // all existing viewproperties invalid, as they have a smaller time stamp.
0372         GeneralSettings *settings = GeneralSettings::self();
0373         settings->setViewPropsTimestamp(QDateTime::currentDateTime());
0374         settings->save();
0375     }
0376 
0377     m_dolphinView->setViewMode(m_viewProps->viewMode());
0378     m_dolphinView->setSortRole(m_viewProps->sortRole());
0379     m_dolphinView->setSortOrder(m_viewProps->sortOrder());
0380     m_dolphinView->setSortFoldersFirst(m_viewProps->sortFoldersFirst());
0381     m_dolphinView->setSortHiddenLast(m_viewProps->sortHiddenLast());
0382     m_dolphinView->setGroupedSorting(m_viewProps->groupedSorting());
0383     m_dolphinView->setVisibleRoles(m_viewProps->visibleRoles());
0384     m_dolphinView->setPreviewsShown(m_viewProps->previewsShown());
0385     m_dolphinView->setHiddenFilesShown(m_viewProps->hiddenFilesShown());
0386 
0387     m_viewProps->save();
0388 
0389     markAsDirty(false);
0390 }
0391 
0392 void ViewPropertiesDialog::loadSettings()
0393 {
0394     // Load view mode
0395     switch (m_viewProps->viewMode()) {
0396     case DolphinView::IconsView:
0397         m_viewMode->setCurrentIndex(0);
0398         break;
0399     case DolphinView::CompactView:
0400         m_viewMode->setCurrentIndex(1);
0401         break;
0402     case DolphinView::DetailsView:
0403         m_viewMode->setCurrentIndex(2);
0404         break;
0405     default:
0406         break;
0407     }
0408 
0409     // Load sort order and sorting
0410     const int sortOrderIndex = (m_viewProps->sortOrder() == Qt::AscendingOrder) ? 0 : 1;
0411     m_sortOrder->setCurrentIndex(sortOrderIndex);
0412 
0413     const QList<KFileItemModel::RoleInfo> rolesInfo = KFileItemModel::rolesInformation();
0414     int sortRoleIndex = 0;
0415     for (int i = 0; i < rolesInfo.count(); ++i) {
0416         if (rolesInfo[i].role == m_viewProps->sortRole()) {
0417             sortRoleIndex = i;
0418             break;
0419         }
0420     }
0421     m_sorting->setCurrentIndex(sortRoleIndex);
0422 
0423     m_sortFoldersFirst->setChecked(m_viewProps->sortFoldersFirst());
0424     m_sortHiddenLast->setChecked(m_viewProps->sortHiddenLast());
0425 
0426     // Load show preview, show in groups and show hidden files settings
0427     m_previewsShown->setChecked(m_viewProps->previewsShown());
0428     m_showInGroups->setChecked(m_viewProps->groupedSorting());
0429     m_showHiddenFiles->setChecked(m_viewProps->hiddenFilesShown());
0430     markAsDirty(false);
0431 }
0432 
0433 #include "moc_viewpropertiesdialog.cpp"