diff options
31 files changed, 346 insertions, 216 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index ee77c5a5a..707160f53 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 3.0) # KDE Application Version, managed by release script set (KDE_APPLICATIONS_VERSION_MAJOR "18") -set (KDE_APPLICATIONS_VERSION_MINOR "04") -set (KDE_APPLICATIONS_VERSION_MICRO "1") +set (KDE_APPLICATIONS_VERSION_MINOR "07") +set (KDE_APPLICATIONS_VERSION_MICRO "70") set (KDE_APPLICATIONS_VERSION "${KDE_APPLICATIONS_VERSION_MAJOR}.${KDE_APPLICATIONS_VERSION_MINOR}.${KDE_APPLICATIONS_VERSION_MICRO}") project(Dolphin VERSION ${KDE_APPLICATIONS_VERSION}) @@ -77,7 +77,7 @@ set_package_properties(KF5Baloo PROPERTIES DESCRIPTION "Baloo Core libraries" PURPOSE "For adding desktop-wide search and tagging support to dolphin" ) -find_package(KF5BalooWidgets 4.97) +find_package(KF5BalooWidgets 18.07.70) set_package_properties(KF5BalooWidgets PROPERTIES DESCRIPTION "Baloos Widgets" URL "http://www.kde.org" TYPE OPTIONAL diff --git a/doc/index.docbook b/doc/index.docbook index 44af99503..c2ed2854f 100644 --- a/doc/index.docbook +++ b/doc/index.docbook @@ -70,8 +70,8 @@ <legalnotice>&FDLNotice;</legalnotice> -<date>2016-06-01</date> -<releaseinfo>Applications 16.04</releaseinfo> +<date>2018-03-26</date> +<releaseinfo>Applications 18.04</releaseinfo> <abstract> <para> @@ -281,6 +281,9 @@ the toolbar can be used to navigate in the history. </mediaobject> </screenshot> +<para>If you click with the &MMB; the item in the history is opened in a new tab +thus keeping the current tab with its content. +</para> </sect2> <sect2 id="dolphin-view-appearance"> @@ -359,8 +362,8 @@ The details view allows you to view the current folder in a tree-like fashion if <link linkend="preferences-dialog-viewmodes-details"> <guilabel>Expandable folders</guilabel></link> are enabled: Each subfolder of the current folder can be -<quote>expanded</quote> or <quote>collapsed</quote> by clicking on the <guiicon>+</guiicon> -or <guiicon>-</guiicon> icon next to it.</para></listitem> +<quote>expanded</quote> or <quote>collapsed</quote> by clicking on the <guiicon>></guiicon> +or <guiicon>v</guiicon> icon next to it.</para></listitem> </itemizedlist> </para> @@ -723,7 +726,7 @@ over with the mouse, including size, type, and date of last modification. It als features a large preview of the selected item and allows you to assign a rating, tags, and comments to it. </para> - +<!--FIXME panel context menu--> </sect2> <sect2 id="folders-panel"> @@ -733,9 +736,10 @@ tags, and comments to it. The <guilabel>Folders</guilabel> panel shows a tree view structure of the file system. It only shows folders. Clicking a folder with the &LMB; opens this folder in the &dolphin; view. - </para> - +<para>Use <guilabel>Limit to Home Directory</guilabel> to hide all folders from +the tree view except your <guilabel>Home</guilabel>. +</para> </sect2> <sect2 id="terminal-panel"> @@ -803,10 +807,6 @@ a KIOSlave is launched to provide the search results.</para> <para>The option from <guilabel>Everywhere</guilabel> with activated Baloo services searches in all indexed folders, without Baloo this option starts the search from the user's <replaceable>Home</replaceable> folder.</para> -<!--FIXME 16.12 -https://git.reviewboard.kde.org/r/123883/ -Add prototype of a "More search tools..." button ---> <screenshot> <screeninfo>Search with More Options</screeninfo> <mediaobject> @@ -832,6 +832,14 @@ the user to shrink the number of search results.</para> together with the <guilabel>Filter</guilabel> bar to find files using Baloo or limit the search to files matching the filter expression.</para> +<para>Use the Save icon to save a search to the <guilabel>Search For</guilabel> +section in the <guilabel>Places</guilabel> panel to quickly access it again in the future. +</para> +<!--FIXME 16.12 +https://git.reviewboard.kde.org/r/123883/ +Add prototype of a "More search tools..." button +--> + </sect2> <sect2 id="mounting-storage-media"> @@ -856,7 +864,7 @@ in the menu, ⪚ <guimenuitem>Undo: Rename</guimenuitem>. </para> </sect2> - +<!-- FIXME https://phabricator.kde.org/D10698--> <sect2 id="batch-rename"> <title>Renaming A Batch Of Files</title> <para> @@ -864,7 +872,7 @@ in the menu, ⪚ <guimenuitem>Undo: Rename</guimenuitem>. will have the file name specified, including a number, ⪚, Image1.jpg, Image2.jpg, Image3.jpg. This can be useful, ⪚, for pictures taken with a digital camera. </para> - +<!--double click--> <para> If you wish to rename a batch of files, first select the files to be renamed. This can be done by pressing the &LMB; and drawing a rectangle around the files @@ -1024,6 +1032,10 @@ startup or not. See the <link linkend="filter-files">section on the filter bar</ for details. </para></listitem> +<listitem><para> +<guilabel>Show full path in title bar</guilabel> makes it easy to distinguish +between files or folders with the same name in different folders. +</para></listitem> </itemizedlist> </para> @@ -1325,6 +1337,10 @@ Enable <guilabel>Rename inline</guilabel> to use this mode if only one item is c If this option is disabled or several items are selected, a dialog will be displayed for renaming. </para></listitem> +<listitem><para><guilabel>Use tab for switching between left and right split view</guilabel> +allows to switch without using the mouse. +</para></listitem> + </itemizedlist> </para> @@ -1353,8 +1369,8 @@ are shown before potentially harmful actions . <warning><para>The confirmation settings for <guilabel>Moving files or folders to trash</guilabel> and <guilabel>Deleting files or folders</guilabel> affect file operations in &dolphin;, &konqueror;, <application>Gwenview</application> and all &kde; applications using the default &kde; file dialog, -whereas <guilabel>Closing Dolphin windows - with multiple tabs</guilabel> is a &dolphin; <!--and &konqueror;--> specific setting.</para></warning> +whereas <guilabel>Closing Dolphin windows +with multiple tabs</guilabel> is a &dolphin; specific setting.</para></warning> </sect3> <sect3 id="preferences-dialog-general-statusbar"> @@ -1577,6 +1593,15 @@ to the trash and cannot be restored.</action></para></listitem> <varlistentry> <term><menuchoice> +<guimenu>File</guimenu> +<guimenuitem>Show Target</guimenuitem> +</menuchoice></term> +<listitem><para>This action highlights a link target in a new &dolphin; window. +</para></listitem> +</varlistentry> + +<varlistentry> +<term><menuchoice> <shortcut> <keycombo action="simul">&Alt;<keycap>Return</keycap></keycombo> </shortcut> @@ -1786,7 +1811,8 @@ current folder grouped by the option selected in <guimenuitem>Sort By</guimenuit <guimenuitem>Hidden Files</guimenuitem> </menuchoice></term> <listitem><para><action>Shows all the hidden files and sub-folders within the current -folder.</action></para></listitem> +folder.</action>There is an alternate shortcut <keycombo action="simul">&Ctrl;<keycap>H</keycap></keycombo> +for this action.</para></listitem> </varlistentry> <varlistentry> @@ -1954,7 +1980,9 @@ be reopened.</action></para></listitem> <guimenu>Tools</guimenu> <guimenuitem>Show Filter Bar</guimenuitem> </menuchoice></term> -<listitem><para><action>Enables and disables the <link linkend="filter-files">filter bar</link>.</action></para></listitem> +<listitem><para><action>Enables and disables the <link linkend="filter-files">filter bar</link>.</action> +You can also use the alternate shortcut <keycombo action="simul">&Shift;<keycap>/</keycap></keycombo> +for this action.</para></listitem> </varlistentry> <varlistentry> diff --git a/src/dolphincontextmenu.cpp b/src/dolphincontextmenu.cpp index bedc835c2..befe98677 100644 --- a/src/dolphincontextmenu.cpp +++ b/src/dolphincontextmenu.cpp @@ -192,13 +192,29 @@ void DolphinContextMenu::openItemContextMenu() QAction* addToPlacesAction = nullptr; const KFileItemListProperties& selectedItemsProps = selectedItemsProperties(); + KFileItemActions fileItemActions; + fileItemActions.setParentWidget(m_mainWindow); + fileItemActions.setItemListProperties(selectedItemsProps); + if (m_selectedItems.count() == 1) { - if (m_fileInfo.isLink()) { - addAction(m_mainWindow->actionCollection()->action(QStringLiteral("show_target"))); - addSeparator(); - } if (m_fileInfo.isDir()) { - // setup 'Create New' menu + // insert 'Open in new window' and 'Open in new tab' entries + addAction(m_mainWindow->actionCollection()->action(QStringLiteral("open_in_new_window"))); + addAction(m_mainWindow->actionCollection()->action(QStringLiteral("open_in_new_tab"))); + + // Insert 'Open With' entries + addOpenWithActions(fileItemActions); + + // insert 'Add to Places' entry + if (!placeExists(m_fileInfo.url())) { + addToPlacesAction = addAction(QIcon::fromTheme(QStringLiteral("bookmark-new")), + i18nc("@action:inmenu Add selected folder to places", + "Add to Places")); + } + + addSeparator(); + + // set up 'Create New' menu DolphinNewFileMenu* newFileMenu = new DolphinNewFileMenu(m_mainWindow->actionCollection(), m_mainWindow); const DolphinView* view = m_mainWindow->activeViewContainer()->view(); newFileMenu->setViewShowsHiddenFiles(view->hiddenFilesShown()); @@ -212,18 +228,6 @@ void DolphinContextMenu::openItemContextMenu() menu->setTitle(i18nc("@title:menu Create new folder, file, link, etc.", "Create New")); menu->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); addMenu(menu); - addSeparator(); - - // insert 'Open in new window' and 'Open in new tab' entries - addAction(m_mainWindow->actionCollection()->action(QStringLiteral("open_in_new_window"))); - addAction(m_mainWindow->actionCollection()->action(QStringLiteral("open_in_new_tab"))); - - // insert 'Add to Places' entry - if (!placeExists(m_fileInfo.url())) { - addToPlacesAction = addAction(QIcon::fromTheme(QStringLiteral("bookmark-new")), - i18nc("@action:inmenu Add selected folder to places", - "Add to Places")); - } addSeparator(); } else if (m_baseUrl.scheme().contains(QStringLiteral("search")) || m_baseUrl.scheme().contains(QStringLiteral("timeline"))) { @@ -247,11 +251,21 @@ void DolphinContextMenu::openItemContextMenu() addSeparator(); } else if (!DolphinView::openItemAsFolderUrl(m_fileInfo).isEmpty()) { + // Insert 'Open With" entries + addOpenWithActions(fileItemActions); + // insert 'Open in new window' and 'Open in new tab' entries addAction(m_mainWindow->actionCollection()->action(QStringLiteral("open_in_new_window"))); addAction(m_mainWindow->actionCollection()->action(QStringLiteral("open_in_new_tab"))); addSeparator(); + } else { + // Insert 'Open With" entries + addOpenWithActions(fileItemActions); + } + if (m_fileInfo.isLink()) { + addAction(m_mainWindow->actionCollection()->action(QStringLiteral("show_target"))); + addSeparator(); } } else { bool selectionHasOnlyDirs = true; @@ -266,18 +280,16 @@ void DolphinContextMenu::openItemContextMenu() if (selectionHasOnlyDirs) { // insert 'Open in new tab' entry addAction(m_mainWindow->actionCollection()->action(QStringLiteral("open_in_new_tabs"))); - addSeparator(); } + // Insert 'Open With" entries + addOpenWithActions(fileItemActions); } insertDefaultItemActions(selectedItemsProps); addSeparator(); - KFileItemActions fileItemActions; - fileItemActions.setItemListProperties(selectedItemsProps); - addServiceActions(fileItemActions); - + fileItemActions.addServiceActionsTo(this); fileItemActions.addPluginActionsTo(this); addVersionControlPluginActions(); @@ -324,6 +336,13 @@ void DolphinContextMenu::openViewportContextMenu() addMenu(newFileMenu->menu()); addSeparator(); + // Insert 'Open With' entries + const KFileItemListProperties baseUrlProperties(KFileItemList() << baseFileItem()); + KFileItemActions fileItemActions; + fileItemActions.setParentWidget(m_mainWindow); + fileItemActions.setItemListProperties(baseUrlProperties); + addOpenWithActions(fileItemActions); + // Insert 'New Window' and 'New Tab' entries. Don't use "open_in_new_window" and // "open_in_new_tab" here, as the current selection should get ignored. addAction(m_mainWindow->actionCollection()->action(QStringLiteral("new_window"))); @@ -343,11 +362,7 @@ void DolphinContextMenu::openViewportContextMenu() addSeparator(); // Insert service actions - const KFileItemListProperties baseUrlProperties(KFileItemList() << baseFileItem()); - KFileItemActions fileItemActions; - fileItemActions.setItemListProperties(baseUrlProperties); - addServiceActions(fileItemActions); - + fileItemActions.addServiceActionsTo(this); fileItemActions.addPluginActionsTo(this); addVersionControlPluginActions(); @@ -469,15 +484,10 @@ KFileItem DolphinContextMenu::baseFileItem() return *m_baseFileItem; } -void DolphinContextMenu::addServiceActions(KFileItemActions& fileItemActions) +void DolphinContextMenu::addOpenWithActions(KFileItemActions& fileItemActions) { - fileItemActions.setParentWidget(m_mainWindow); - // insert 'Open With...' action or sub menu fileItemActions.addOpenWithActionsTo(this, QStringLiteral("DesktopEntryName != '%1'").arg(qApp->desktopFileName())); - - // insert 'Actions' sub menu - fileItemActions.addServiceActionsTo(this); } void DolphinContextMenu::addVersionControlPluginActions() diff --git a/src/dolphincontextmenu.h b/src/dolphincontextmenu.h index 9ebdb1a56..bf0cf2c97 100644 --- a/src/dolphincontextmenu.h +++ b/src/dolphincontextmenu.h @@ -116,10 +116,9 @@ private: KFileItem baseFileItem(); /** - * Adds actions that have been installed as service-menu. - * (see http://techbase.kde.org/index.php?title=Development/Tutorials/Creating_Konqueror_Service_Menus) + * Adds "Open With" actions */ - void addServiceActions(KFileItemActions& fileItemActions); + void addOpenWithActions(KFileItemActions& fileItemActions); /** * Adds actions that are provided by a KVersionControlPlugin. diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp index d112007bc..a0509ad47 100644 --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -104,7 +104,7 @@ DolphinMainWindow::DolphinMainWindow() : m_tearDownFromPlacesRequested(false) { Q_INIT_RESOURCE(dolphin); - + setComponentName(QStringLiteral("dolphin"), QGuiApplication::applicationDisplayName()); setObjectName(QStringLiteral("Dolphin#")); connect(&DolphinNewFileMenuObserver::instance(), &DolphinNewFileMenuObserver::errorMessage, @@ -287,13 +287,13 @@ void DolphinMainWindow::updateHistory() const KUrlNavigator* urlNavigator = m_activeViewContainer->urlNavigator(); const int index = urlNavigator->historyIndex(); - QAction* backAction = actionCollection()->action(QStringLiteral("go_back")); + QAction* backAction = actionCollection()->action(KStandardAction::name(KStandardAction::Back)); if (backAction) { backAction->setToolTip(i18nc("@info", "Go back")); backAction->setEnabled(index < urlNavigator->historySize() - 1); } - QAction* forwardAction = actionCollection()->action(QStringLiteral("go_forward")); + QAction* forwardAction = actionCollection()->action(KStandardAction::name(KStandardAction::Forward)); if (forwardAction) { forwardAction->setToolTip(i18nc("@info", "Go forward")); forwardAction->setEnabled(index > 0); @@ -402,7 +402,7 @@ void DolphinMainWindow::closeEvent(QCloseEvent* event) dialog->setWindowTitle(i18nc("@title:window", "Confirmation")); dialog->setModal(true); QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Yes | QDialogButtonBox::No | QDialogButtonBox::Cancel); - KGuiItem::assign(buttons->button(QDialogButtonBox::Yes), KStandardGuiItem::quit()); + KGuiItem::assign(buttons->button(QDialogButtonBox::Yes), KGuiItem(i18nc("@action:button 'Quit Dolphin' button", "&Quit %1", QGuiApplication::applicationDisplayName()), QIcon::fromTheme(QStringLiteral("application-exit")))); KGuiItem::assign(buttons->button(QDialogButtonBox::No), KGuiItem(i18n("C&lose Current Tab"), QIcon::fromTheme(QStringLiteral("tab-close")))); KGuiItem::assign(buttons->button(QDialogButtonBox::Cancel), KStandardGuiItem::cancel()); buttons->button(QDialogButtonBox::Yes)->setDefault(true); @@ -457,6 +457,10 @@ void DolphinMainWindow::updateNewMenu() m_newFileMenu->setViewShowsHiddenFiles(activeViewContainer()->view()->hiddenFilesShown()); m_newFileMenu->checkUpToDate(); m_newFileMenu->setPopupFiles(activeViewContainer()->url()); + + // If we're in the trash, also disable all the 'create new' items + // TODO: remove this once https://phabricator.kde.org/T8234 is implemented + slotWriteStateChanged(m_activeViewContainer->view()->url().scheme() != QLatin1String("trash")); } void DolphinMainWindow::createDirectory() @@ -534,9 +538,9 @@ void DolphinMainWindow::slotDirectoryLoadingCompleted() void DolphinMainWindow::slotToolBarActionMiddleClicked(QAction *action) { - if (action == actionCollection()->action(QStringLiteral("go_back"))) { + if (action == actionCollection()->action(KStandardAction::name(KStandardAction::Back))) { goBackInNewTab(); - } else if (action == actionCollection()->action(QStringLiteral("go_forward"))) { + } else if (action == actionCollection()->action(KStandardAction::name(KStandardAction::Forward))) { goForwardInNewTab(); } else if (action == actionCollection()->action(QStringLiteral("go_up"))) { goUpInNewTab(); @@ -804,7 +808,10 @@ void DolphinMainWindow::slotHandleUrlStatFinished(KJob* job) void DolphinMainWindow::slotWriteStateChanged(bool isFolderWritable) { - newFileMenu()->setEnabled(isFolderWritable); + const auto actions = m_newFileMenu->menu()->actions(); + for (auto menuItem : actions) { + menuItem->setEnabled(isFolderWritable); + } } void DolphinMainWindow::openContextMenu(const QPoint& pos, @@ -819,10 +826,12 @@ void DolphinMainWindow::openContextMenu(const QPoint& pos, switch (command) { case DolphinContextMenu::OpenParentFolder: changeUrl(KIO::upUrl(item.url())); + m_activeViewContainer->view()->markUrlsAsSelected({item.url()}); + m_activeViewContainer->view()->markUrlAsCurrent(item.url()); break; case DolphinContextMenu::OpenParentFolderInNewWindow: - Dolphin::openNewWindow({KIO::upUrl(item.url())}, this); + Dolphin::openNewWindow({item.url()}, this, Dolphin::OpenNewWindowFlag::Select); break; case DolphinContextMenu::OpenParentFolderInNewTab: @@ -854,7 +863,7 @@ void DolphinMainWindow::updateControlMenu() // Add "Edit" actions bool added = addActionToMenu(ac->action(KStandardAction::name(KStandardAction::Undo)), menu) | addActionToMenu(ac->action(KStandardAction::name(KStandardAction::Find)), menu) | - addActionToMenu(ac->action(QStringLiteral("select_all")), menu) | + addActionToMenu(ac->action(KStandardAction::name(KStandardAction::SelectAll)), menu) | addActionToMenu(ac->action(QStringLiteral("invert_selection")), menu); if (added) { @@ -880,7 +889,7 @@ void DolphinMainWindow::updateControlMenu() } added = addActionToMenu(ac->action(QStringLiteral("split_view")), menu) | - addActionToMenu(ac->action(QStringLiteral("reload")), menu) | + addActionToMenu(ac->action(KStandardAction::name(KStandardAction::Redisplay)), menu) | addActionToMenu(ac->action(QStringLiteral("view_properties")), menu); if (added) { menu->addSeparator(); @@ -987,7 +996,7 @@ void DolphinMainWindow::activeViewChanged(DolphinViewContainer* viewContainer) void DolphinMainWindow::tabCountChanged(int count) { const bool enableTabActions = (count > 1); - actionCollection()->action(QStringLiteral("close_tab"))->setEnabled(enableTabActions); + actionCollection()->action(KStandardAction::name(KStandardAction::Close))->setEnabled(enableTabActions); actionCollection()->action(QStringLiteral("activate_next_tab"))->setEnabled(enableTabActions); actionCollection()->action(QStringLiteral("activate_prev_tab"))->setEnabled(enableTabActions); } @@ -1064,24 +1073,19 @@ void DolphinMainWindow::setupActions() connect(menu, &QMenu::aboutToShow, this, &DolphinMainWindow::updateNewMenu); - QAction* newWindow = actionCollection()->addAction(QStringLiteral("new_window")); - newWindow->setIcon(QIcon::fromTheme(QStringLiteral("window-new"))); + QAction* newWindow = KStandardAction::openNew(this, &DolphinMainWindow::openNewMainWindow, actionCollection()); newWindow->setText(i18nc("@action:inmenu File", "New &Window")); - actionCollection()->setDefaultShortcut(newWindow, Qt::CTRL + Qt::Key_N); - connect(newWindow, &QAction::triggered, this, &DolphinMainWindow::openNewMainWindow); QAction* newTab = actionCollection()->addAction(QStringLiteral("new_tab")); newTab->setIcon(QIcon::fromTheme(QStringLiteral("tab-new"))); newTab->setText(i18nc("@action:inmenu File", "New Tab")); - actionCollection()->setDefaultShortcuts(newTab, {Qt::CTRL + Qt::Key_T, Qt::CTRL + Qt::SHIFT + Qt::Key_N}); + actionCollection()->setDefaultShortcuts(newTab, {Qt::CTRL + Qt::Key_T, QKeySequence::AddTab}); connect(newTab, &QAction::triggered, this, static_cast<void(DolphinMainWindow::*)()>(&DolphinMainWindow::openNewActivatedTab)); - QAction* closeTab = actionCollection()->addAction(QStringLiteral("close_tab")); - closeTab->setIcon(QIcon::fromTheme(QStringLiteral("tab-close"))); + QAction* closeTab = KStandardAction::close( + m_tabWidget, static_cast<void(DolphinTabWidget::*)()>(&DolphinTabWidget::closeTab), actionCollection()); closeTab->setText(i18nc("@action:inmenu File", "Close Tab")); - actionCollection()->setDefaultShortcut(closeTab, Qt::CTRL + Qt::Key_W); closeTab->setEnabled(false); - connect(closeTab, &QAction::triggered, m_tabWidget, static_cast<void(DolphinTabWidget::*)()>(&DolphinTabWidget::closeTab)); KStandardAction::quit(this, &DolphinMainWindow::quit, actionCollection()); @@ -1101,11 +1105,7 @@ void DolphinMainWindow::setupActions() KStandardAction::find(this, &DolphinMainWindow::find, actionCollection()); - QAction* selectAll = actionCollection()->addAction(QStringLiteral("select_all")); - selectAll->setText(i18nc("@action:inmenu Edit", "Select All")); - selectAll->setIcon(QIcon::fromTheme(QStringLiteral("edit-select-all"))); - actionCollection()->setDefaultShortcut(selectAll, Qt::CTRL + Qt::Key_A); - connect(selectAll, &QAction::triggered, this, &DolphinMainWindow::selectAll); + KStandardAction::selectAll(this, &DolphinMainWindow::selectAll, actionCollection()); QAction* invertSelection = actionCollection()->addAction(QStringLiteral("invert_selection")); invertSelection->setText(i18nc("@action:inmenu Edit", "Invert Selection")); @@ -1129,11 +1129,7 @@ void DolphinMainWindow::setupActions() stashSplit->setVisible(KProtocolInfo::isKnownProtocol("stash")); connect(stashSplit, &QAction::triggered, this, &DolphinMainWindow::toggleSplitStash); - QAction* reload = actionCollection()->addAction(QStringLiteral("reload")); - reload->setText(i18nc("@action:inmenu View", "Reload")); - actionCollection()->setDefaultShortcut(reload, Qt::Key_F5); - reload->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); - connect(reload, &QAction::triggered, this, &DolphinMainWindow::reloadView); + KStandardAction::redisplay(this, &DolphinMainWindow::reloadView, actionCollection()); QAction* stop = actionCollection()->addAction(QStringLiteral("stop")); stop->setText(i18nc("@action:inmenu View", "Stop")); diff --git a/src/dolphinpart.cpp b/src/dolphinpart.cpp index e0f06bc5f..2e7f7639f 100644 --- a/src/dolphinpart.cpp +++ b/src/dolphinpart.cpp @@ -180,7 +180,7 @@ void DolphinPart::createActions() unselectItemsMatching->setText(i18nc("@action:inmenu Edit", "Unselect Items Matching...")); connect(unselectItemsMatching, &QAction::triggered, this, &DolphinPart::slotUnselectItemsMatchingPattern); - actionCollection()->addAction(KStandardAction::SelectAll, QStringLiteral("select_all"), m_view, SLOT(selectAll())); + KStandardAction::selectAll(m_view, &DolphinView::selectAll, actionCollection()); QAction* unselectAll = actionCollection()->addAction(QStringLiteral("unselect_all")); unselectAll->setText(i18nc("@action:inmenu Edit", "Unselect All")); @@ -216,11 +216,8 @@ void DolphinPart::createActions() goActionGroup); // Tools menu - m_findFileAction = actionCollection()->addAction(QStringLiteral("find_file")); + m_findFileAction = KStandardAction::find(this, &DolphinPart::slotFindFile, actionCollection()); m_findFileAction->setText(i18nc("@action:inmenu Tools", "Find File...")); - actionCollection()->setDefaultShortcut(m_findFileAction, Qt::CTRL + Qt::Key_F); - m_findFileAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-find"))); - connect(m_findFileAction, &QAction::triggered, this, &DolphinPart::slotFindFile); #ifndef Q_OS_WIN if (KAuthorized::authorize(QStringLiteral("shell_access"))) { diff --git a/src/dolphintabpage.cpp b/src/dolphintabpage.cpp index a96c8b6a3..b2bb5c896 100644 --- a/src/dolphintabpage.cpp +++ b/src/dolphintabpage.cpp @@ -312,6 +312,9 @@ void DolphinTabPage::slotViewActivated() m_primaryViewActive = !m_primaryViewActive; } else { m_primaryViewActive = true; + if (m_secondaryViewContainer) { + m_secondaryViewContainer->setActive(false); + } } } diff --git a/src/dolphintabwidget.cpp b/src/dolphintabwidget.cpp index 0271ed568..a5c2f8c98 100644 --- a/src/dolphintabwidget.cpp +++ b/src/dolphintabwidget.cpp @@ -34,7 +34,7 @@ DolphinTabWidget::DolphinTabWidget(QWidget* parent) : QTabWidget(parent), m_placesSelectorVisible(true), - m_previousTab(0) + m_lastViewedTab(0) { connect(this, &DolphinTabWidget::tabCloseRequested, this, static_cast<void (DolphinTabWidget::*)(int)>(&DolphinTabWidget::closeTab)); @@ -61,6 +61,18 @@ DolphinTabPage* DolphinTabWidget::currentTabPage() const return tabPageAt(currentIndex()); } +DolphinTabPage* DolphinTabWidget::nextTabPage() const +{ + const int index = currentIndex() + 1; + return tabPageAt(index < count() ? index : 0); +} + +DolphinTabPage* DolphinTabWidget::prevTabPage() const +{ + const int index = currentIndex() - 1; + return tabPageAt(index >= 0 ? index : (count() - 1)); +} + DolphinTabPage* DolphinTabWidget::tabPageAt(const int index) const { return static_cast<DolphinTabPage*>(widget(index)); @@ -305,8 +317,8 @@ void DolphinTabWidget::tabUrlChanged(const QUrl& url) void DolphinTabWidget::currentTabChanged(int index) { - // previous tab deactivation - if (DolphinTabPage* tabPage = tabPageAt(m_previousTab)) { + // last-viewed tab deactivation + if (DolphinTabPage* tabPage = tabPageAt(m_lastViewedTab)) { tabPage->setActive(false); } DolphinTabPage* tabPage = tabPageAt(index); @@ -314,7 +326,7 @@ void DolphinTabWidget::currentTabChanged(int index) emit activeViewChanged(viewContainer); emit currentUrlChanged(viewContainer->url()); tabPage->setActive(true); - m_previousTab = index; + m_lastViewedTab = index; } void DolphinTabWidget::tabInserted(int index) diff --git a/src/dolphintabwidget.h b/src/dolphintabwidget.h index ba2fd4867..b4493f7ed 100644 --- a/src/dolphintabwidget.h +++ b/src/dolphintabwidget.h @@ -40,6 +40,18 @@ public: DolphinTabPage* currentTabPage() const; /** + * @return the next tab page. If the current active tab is the last tab, + * it returns the first tab. If there is only one tab, returns nullptr + */ + DolphinTabPage* nextTabPage() const; + + /** + * @return the previous tab page. If the current active tab is the first tab, + * it returns the last tab. If there is only one tab, returns nullptr + */ + DolphinTabPage* prevTabPage() const; + + /** * @return Tab page at the given \a index (can be 0 if the index is out-of-range) */ DolphinTabPage* tabPageAt(const int index) const; @@ -187,7 +199,7 @@ private: /** Caches the (negated) places panel visibility */ bool m_placesSelectorVisible; - int m_previousTab; + int m_lastViewedTab; }; #endif diff --git a/src/dolphinui.rc b/src/dolphinui.rc index 566f50fc8..ea3609c64 100644 --- a/src/dolphinui.rc +++ b/src/dolphinui.rc @@ -1,11 +1,11 @@ <!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> -<kpartgui name="dolphin" version="19"> +<kpartgui name="dolphin" version="20"> <MenuBar> <Menu name="file"> <Action name="new_menu" /> - <Action name="new_window" /> + <Action name="file_new" /> <Action name="new_tab" /> - <Action name="close_tab" /> + <Action name="file_close" /> <Action name="undo_close_tab" /> <Separator/> <Action name="renamefile" /> @@ -17,7 +17,7 @@ <Action name="properties" /> </Menu> <Menu name="edit"> - <Action name="select_all" /> + <Action name="edit_select_all" /> <Action name="invert_selection" /> </Menu> <Menu name="view"> @@ -30,7 +30,7 @@ <Separator/> <Action name="split_view" /> <Action name="split_stash" /> - <Action name="reload" /> + <Action name="redisplay" /> <Action name="stop" /> <Separator/> <Action name="panels" /> diff --git a/src/kitemviews/kfileitemmodel.cpp b/src/kitemviews/kfileitemmodel.cpp index b6a001642..844954d6a 100644 --- a/src/kitemviews/kfileitemmodel.cpp +++ b/src/kitemviews/kfileitemmodel.cpp @@ -1846,16 +1846,10 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b, const break; } - case RatingRole: { - result = a->values.value("rating").toInt() - b->values.value("rating").toInt(); - break; - } - - case ImageSizeRole: { - // Alway use a natural comparing to interpret the numbers of a string like - // "1600 x 1200" for having a correct sorting. - result = collator.compare(a->values.value("imageSize").toString(), - b->values.value("imageSize").toString()); + case RatingRole: + case WidthRole: + case HeightRole: { + result = a->values.value(roleForType(m_sortRole)).toInt() - b->values.value(roleForType(m_sortRole)).toInt(); break; } @@ -2305,7 +2299,8 @@ const KFileItemModel::RoleInfoMap* KFileItemModel::rolesInfoMap(int& count) { "wordCount", WordCountRole, I18N_NOOP2_NOSTRIP("@label", "Word Count"), I18N_NOOP2_NOSTRIP("@label", "Document"), true, true }, { "lineCount", LineCountRole, I18N_NOOP2_NOSTRIP("@label", "Line Count"), I18N_NOOP2_NOSTRIP("@label", "Document"), true, true }, { "imageDateTime", ImageDateTimeRole, I18N_NOOP2_NOSTRIP("@label", "Date Photographed"), I18N_NOOP2_NOSTRIP("@label", "Image"), true, true }, - { "imageSize", ImageSizeRole, I18N_NOOP2_NOSTRIP("@label", "Image Size"), I18N_NOOP2_NOSTRIP("@label", "Image"), true, true }, + { "width", WidthRole, I18N_NOOP2_NOSTRIP("@label", "Width"), I18N_NOOP2_NOSTRIP("@label", "Image"), true, true }, + { "height", HeightRole, I18N_NOOP2_NOSTRIP("@label", "Height"), I18N_NOOP2_NOSTRIP("@label", "Image"), true, true }, { "orientation", OrientationRole, I18N_NOOP2_NOSTRIP("@label", "Orientation"), I18N_NOOP2_NOSTRIP("@label", "Image"), true, true }, { "artist", ArtistRole, I18N_NOOP2_NOSTRIP("@label", "Artist"), I18N_NOOP2_NOSTRIP("@label", "Audio"), true, true }, { "genre", GenreRole, I18N_NOOP2_NOSTRIP("@label", "Genre"), I18N_NOOP2_NOSTRIP("@label", "Audio"), true, true }, diff --git a/src/kitemviews/kfileitemmodel.h b/src/kitemviews/kfileitemmodel.h index 75953f0b7..134c50245 100644 --- a/src/kitemviews/kfileitemmodel.h +++ b/src/kitemviews/kfileitemmodel.h @@ -286,7 +286,7 @@ private: NoRole, NameRole, SizeRole, ModificationTimeRole, CreationTimeRole, AccessTimeRole, PermissionsRole, OwnerRole, GroupRole, TypeRole, DestinationRole, PathRole, DeletionTimeRole, // User visible roles available with Baloo: - CommentRole, TagsRole, RatingRole, ImageSizeRole, ImageDateTimeRole, OrientationRole, + CommentRole, TagsRole, RatingRole, WidthRole, HeightRole, ImageDateTimeRole, OrientationRole, WordCountRole, TitleRole, LineCountRole, ArtistRole, GenreRole, AlbumRole, DurationRole, TrackRole, ReleaseYearRole, BitrateRole, OriginUrlRole, // Non-visible roles: diff --git a/src/kitemviews/kfileitemmodelrolesupdater.cpp b/src/kitemviews/kfileitemmodelrolesupdater.cpp index 6c96a08d1..544d88040 100644 --- a/src/kitemviews/kfileitemmodelrolesupdater.cpp +++ b/src/kitemviews/kfileitemmodelrolesupdater.cpp @@ -497,7 +497,7 @@ void KFileItemModelRolesUpdater::slotGotPreview(const KFileItem& item, const QPi const QString mimeType = item.mimetype(); const int slashIndex = mimeType.indexOf(QLatin1Char('/')); - const bool isFontPreview = mimeType.right(slashIndex).contains(QLatin1String("font")); + const bool isFontPreview = mimeType.rightRef(slashIndex).contains(QLatin1String("font")); const bool isFolderPreview = item.isDir(); const bool isWindowsExePreview = mimeType == QLatin1String("application/x-ms-dos-executable") || mimeType == QLatin1String("application/x-msdownload"); diff --git a/src/kitemviews/kitemlistgroupheader.cpp b/src/kitemviews/kitemlistgroupheader.cpp index fb9298989..06a32484a 100644 --- a/src/kitemviews/kitemlistgroupheader.cpp +++ b/src/kitemviews/kitemlistgroupheader.cpp @@ -78,6 +78,10 @@ QVariant KItemListGroupHeader::data() const void KItemListGroupHeader::setStyleOption(const KItemListStyleOption& option) { + if (m_styleOption == option) { + return; + } + const KItemListStyleOption previous = m_styleOption; m_styleOption = option; m_dirtyCache = true; diff --git a/src/kitemviews/kitemlistselectionmanager.cpp b/src/kitemviews/kitemlistselectionmanager.cpp index efc256e1e..f5e097c02 100644 --- a/src/kitemviews/kitemlistselectionmanager.cpp +++ b/src/kitemviews/kitemlistselectionmanager.cpp @@ -235,6 +235,9 @@ void KItemListSelectionManager::itemsInserted(const KItemRangeList& itemRanges) // Calling setCurrentItem would trigger the selectionChanged signal, but we want to // emit it only once in this function -> change the current item manually and emit currentChanged m_currentItem += inc; + if (m_currentItem >= m_model->count()) { + m_currentItem = -1; + } emit currentChanged(m_currentItem, previousCurrent); } diff --git a/src/kitemviews/kitemliststyleoption.cpp b/src/kitemviews/kitemliststyleoption.cpp index 1ebcad141..bcfb86064 100644 --- a/src/kitemviews/kitemliststyleoption.cpp +++ b/src/kitemviews/kitemliststyleoption.cpp @@ -53,3 +53,23 @@ KItemListStyleOption::KItemListStyleOption(const KItemListStyleOption& other) : KItemListStyleOption::~KItemListStyleOption() { } + +bool KItemListStyleOption::operator==(const KItemListStyleOption& other) const +{ + return rect == other.rect + && font == other.font + && fontMetrics == other.fontMetrics + && palette == other.palette + && padding == other.padding + && horizontalMargin == other.horizontalMargin + && verticalMargin == other.verticalMargin + && iconSize == other.iconSize + && extendedSelectionRegion == other.extendedSelectionRegion + && maxTextLines == other.maxTextLines + && maxTextWidth == other.maxTextWidth; +} + +bool KItemListStyleOption::operator!=(const KItemListStyleOption& other) const +{ + return !(*this == other); +} diff --git a/src/kitemviews/kitemliststyleoption.h b/src/kitemviews/kitemliststyleoption.h index 09b787c27..93aafac1f 100644 --- a/src/kitemviews/kitemliststyleoption.h +++ b/src/kitemviews/kitemliststyleoption.h @@ -45,6 +45,11 @@ public: bool extendedSelectionRegion; int maxTextLines; int maxTextWidth; + + bool operator==(const KItemListStyleOption& other) const; + bool operator!=(const KItemListStyleOption& other) const; + + }; #endif diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp index 489c6f9b6..f0647fb3e 100644 --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -752,6 +752,10 @@ void KItemListView::setItemSize(const QSizeF& size) void KItemListView::setStyleOption(const KItemListStyleOption& option) { + if (m_styleOption == option) { + return; + } + const KItemListStyleOption previousOption = m_styleOption; m_styleOption = option; diff --git a/src/kitemviews/kitemlistwidget.cpp b/src/kitemviews/kitemlistwidget.cpp index 61dd7256e..28b374620 100644 --- a/src/kitemviews/kitemlistwidget.cpp +++ b/src/kitemviews/kitemlistwidget.cpp @@ -191,10 +191,13 @@ qreal KItemListWidget::columnWidth(const QByteArray& role) const void KItemListWidget::setStyleOption(const KItemListStyleOption& option) { + if (m_styleOption == option) { + return; + } + const KItemListStyleOption previous = m_styleOption; clearHoverCache(); m_styleOption = option; - styleOptionChanged(option, previous); update(); } diff --git a/src/kitemviews/kstandarditemlistview.cpp b/src/kitemviews/kstandarditemlistview.cpp index ee1c06103..929ee1da8 100644 --- a/src/kitemviews/kstandarditemlistview.cpp +++ b/src/kitemviews/kstandarditemlistview.cpp @@ -146,27 +146,20 @@ void KStandardItemListView::applyDefaultStyleOption(int iconSize, { KItemListStyleOption option = styleOption(); - bool changed = false; if (option.iconSize < 0) { option.iconSize = iconSize; - changed = true; } if (option.padding < 0) { option.padding = padding; - changed = true; } if (option.horizontalMargin < 0) { option.horizontalMargin = horizontalMargin; - changed = true; } if (option.verticalMargin < 0) { option.verticalMargin = verticalMargin; - changed = true; } - if (changed) { - setStyleOption(option); - } + setStyleOption(option); } void KStandardItemListView::updateLayoutOfVisibleItems() diff --git a/src/kitemviews/kstandarditemlistwidget.cpp b/src/kitemviews/kstandarditemlistwidget.cpp index 1aca250dd..bc3bb29de 100644 --- a/src/kitemviews/kstandarditemlistwidget.cpp +++ b/src/kitemviews/kstandarditemlistwidget.cpp @@ -1015,15 +1015,21 @@ void KStandardItemListWidget::updatePixmapCache() if (iconOnTop) { // Center horizontally and align on bottom within the icon-area - m_pixmapPos.setX((widgetSize.width() - m_scaledPixmapSize.width()) / 2); + m_pixmapPos.setX((widgetSize.width() - m_scaledPixmapSize.width()) / 2.0); m_pixmapPos.setY(padding + scaledIconSize - m_scaledPixmapSize.height()); } else { // Center horizontally and vertically within the icon-area const TextInfo* textInfo = m_textInfo.value("text"); - m_pixmapPos.setX(textInfo->pos.x() - 2 * padding - - (scaledIconSize + m_scaledPixmapSize.width()) / 2); - m_pixmapPos.setY(padding - + (scaledIconSize - m_scaledPixmapSize.height()) / 2); + m_pixmapPos.setX(textInfo->pos.x() - 2.0 * padding + - (scaledIconSize + m_scaledPixmapSize.width()) / 2.0); + + // Derive icon's vertical center from the center of the text frame, including + // any necessary adjustment if the font's midline is offset from the frame center + const qreal midlineShift = m_customizedFontMetrics.height() / 2.0 + - m_customizedFontMetrics.descent() + - m_customizedFontMetrics.capHeight() / 2.0; + m_pixmapPos.setY(m_textRect.center().y() + midlineShift - m_scaledPixmapSize.height() / 2.0); + } m_iconRect = QRectF(m_pixmapPos, QSizeF(m_scaledPixmapSize)); diff --git a/src/kitemviews/private/kbaloorolesprovider.cpp b/src/kitemviews/private/kbaloorolesprovider.cpp index bbd0927f2..3d3923b1b 100644 --- a/src/kitemviews/private/kbaloorolesprovider.cpp +++ b/src/kitemviews/private/kbaloorolesprovider.cpp @@ -56,9 +56,6 @@ QHash<QByteArray, QVariant> KBalooRolesProvider::roleValues(const Baloo::File& f { QHash<QByteArray, QVariant> values; - int width = -1; - int height = -1; - QMapIterator<KFileMetaData::Property::Property, QVariant> it(file.properties()); while (it.hasNext()) { it.next(); @@ -72,23 +69,7 @@ QHash<QByteArray, QVariant> KBalooRolesProvider::roleValues(const Baloo::File& f const QVariant value = it.value(); - if (role == "imageSize") { - // Merge the two properties for width and height - // as one string into the "imageSize" role - if (property == QLatin1String("width")) { - width = value.toInt(); - } - else if (property == QLatin1String("height")) { - height = value.toInt(); - } - - if (width >= 0 && height >= 0) { - QString widthAndHeight = QString::number(width); - widthAndHeight += QLatin1String(" x "); - widthAndHeight += QString::number(height); - values.insert(role, widthAndHeight); - } - } else if (role == "orientation") { + if (role == "orientation") { const QString orientation = orientationFromValue(value.toInt()); values.insert(role, orientation); } else if (role == "duration") { @@ -135,8 +116,7 @@ KBalooRolesProvider::KBalooRolesProvider() : }; // Mapping from the URIs to the KFileItemModel roles. Note that this must not be - // a 1:1 mapping: One role may contain several URI-values (e.g. the URIs for height and - // width of an image are mapped to the role "imageSize") + // a 1:1 mapping: One role may contain several URI-values static const PropertyInfo propertyInfoList[] = { { "rating", "rating" }, { "tag", "tags" }, @@ -144,8 +124,8 @@ KBalooRolesProvider::KBalooRolesProvider() : { "title", "title" }, { "wordCount", "wordCount" }, { "lineCount", "lineCount" }, - { "width", "imageSize" }, - { "height", "imageSize" }, + { "width", "width" }, + { "height", "height" }, { "imageDateTime", "imageDateTime"}, { "nexif.orientation", "orientation", }, { "artist", "artist" }, diff --git a/src/panels/information/dolphin_informationpanelsettings.kcfg b/src/panels/information/dolphin_informationpanelsettings.kcfg index 53c756d24..dbc1ab6d2 100644 --- a/src/panels/information/dolphin_informationpanelsettings.kcfg +++ b/src/panels/information/dolphin_informationpanelsettings.kcfg @@ -10,5 +10,13 @@ <label>Previews shown</label> <default>true</default> </entry> + <entry name="dateFormat" type="Enum"> + <label>Date display format</label> + <choices> + <choice name="LongFormat" /> + <choice name="ShortFormat" /> + </choices> + <default>0</default> + </entry> </group> </kcfg> diff --git a/src/panels/information/informationpanelcontent.cpp b/src/panels/information/informationpanelcontent.cpp index f44a3feb7..0cba0cdf0 100644 --- a/src/panels/information/informationpanelcontent.cpp +++ b/src/panels/information/informationpanelcontent.cpp @@ -112,12 +112,13 @@ InformationPanelContent::InformationPanelContent(QWidget* parent) : this, &InformationPanelContent::urlActivated); #else m_metaDataWidget = new Baloo::FileMetaDataWidget(parent); + m_metaDataWidget->setDateFormat(static_cast<Baloo::DateFormats>(InformationPanelSettings::dateFormat())); connect(m_metaDataWidget, &Baloo::FileMetaDataWidget::urlActivated, this, &InformationPanelContent::urlActivated); #endif m_metaDataWidget->setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont)); m_metaDataWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); - + // Encapsulate the MetaDataWidget inside a container that has a dummy widget // at the bottom. This prevents that the meta data widget gets vertically stretched // in the case where the height of m_metaDataArea > m_metaDataWidget. @@ -160,41 +161,42 @@ void InformationPanelContent::showItem(const KFileItem& item) const QUrl itemUrl = item.url(); const bool isSearchUrl = itemUrl.scheme().contains(QStringLiteral("search")) && item.localPath().isEmpty(); - if (!applyPlace(itemUrl)) { - setNameLabelText(item.text()); - if (isSearchUrl) { - // in the case of a search-URL the URL is not readable for humans - // (at least not useful to show in the Information Panel) - m_preview->setPixmap( - QIcon::fromTheme(QStringLiteral("nepomuk")).pixmap(KIconLoader::SizeEnormous, KIconLoader::SizeEnormous) - ); - } else { - // try to get a preview pixmap from the item... - - // Mark the currently shown preview as outdated. This is done - // with a small delay to prevent a flickering when the next preview - // can be shown within a short timeframe. This timer is not started - // for directories, as directory previews might fail and return the - // same icon. - if (!item.isDir()) { - m_outdatedPreviewTimer->start(); - } + setNameLabelText(item.text()); + if (isSearchUrl) { + // in the case of a search-URL the URL is not readable for humans + // (at least not useful to show in the Information Panel) + m_preview->setPixmap( + QIcon::fromTheme(QStringLiteral("nepomuk")).pixmap(KIconLoader::SizeEnormous, KIconLoader::SizeEnormous) + ); + } else { + // try to get a preview pixmap from the item... - m_previewJob = new KIO::PreviewJob(KFileItemList() << item, QSize(m_preview->width(), m_preview->height())); - m_previewJob->setScaleType(KIO::PreviewJob::Unscaled); - m_previewJob->setIgnoreMaximumSize(item.isLocalFile()); - if (m_previewJob->uiDelegate()) { - KJobWidgets::setWindow(m_previewJob, this); - } + // Mark the currently shown preview as outdated. This is done + // with a small delay to prevent a flickering when the next preview + // can be shown within a short timeframe. This timer is not started + // for directories, as directory previews might fail and return the + // same icon. + if (!item.isDir()) { + m_outdatedPreviewTimer->start(); + } - connect(m_previewJob.data(), &KIO::PreviewJob::gotPreview, - this, &InformationPanelContent::showPreview); - connect(m_previewJob.data(), &KIO::PreviewJob::failed, - this, &InformationPanelContent::showIcon); + m_previewJob = new KIO::PreviewJob(KFileItemList() << item, QSize(m_preview->width(), m_preview->height())); + m_previewJob->setScaleType(KIO::PreviewJob::Unscaled); + m_previewJob->setIgnoreMaximumSize(item.isLocalFile()); + if (m_previewJob->uiDelegate()) { + KJobWidgets::setWindow(m_previewJob, this); } + + connect(m_previewJob.data(), &KIO::PreviewJob::gotPreview, + this, &InformationPanelContent::showPreview); + connect(m_previewJob.data(), &KIO::PreviewJob::failed, + this, &InformationPanelContent::showIcon); } if (m_metaDataWidget) { +#ifdef HAVE_BALOO + m_metaDataWidget->setDateFormat(static_cast<Baloo::DateFormats>(InformationPanelSettings::dateFormat())); +#endif m_metaDataWidget->show(); m_metaDataWidget->setItems(KFileItemList() << item); } @@ -283,6 +285,12 @@ void InformationPanelContent::configureSettings(const QList<QAction*>& customCon QAction* configureAction = popup.addAction(i18nc("@action:inmenu", "Configure...")); configureAction->setIcon(QIcon::fromTheme(QStringLiteral("configure"))); +#ifdef HAVE_BALOO + QAction* dateformatAction = popup.addAction(i18nc("@action:inmenu", "Condensed Date")); + dateformatAction->setIcon(QIcon::fromTheme(QStringLiteral("change-date-symbolic"))); + dateformatAction->setCheckable(true); + dateformatAction->setChecked(InformationPanelSettings::dateFormat() == static_cast<int>(Baloo::DateFormats::ShortFormat)); +#endif popup.addSeparator(); foreach (QAction* action, customContextMenuActions) { popup.addAction(action); @@ -308,16 +316,22 @@ void InformationPanelContent::configureSettings(const QList<QAction*>& customCon dialog->show(); connect(dialog, &FileMetaDataConfigurationDialog::destroyed, this, &InformationPanelContent::refreshMetaData); } +#ifdef HAVE_BALOO + if (action == dateformatAction) { + int dateFormat = static_cast<int>(isChecked ? Baloo::DateFormats::ShortFormat : Baloo::DateFormats::LongFormat); + + InformationPanelSettings::setDateFormat(dateFormat); + refreshMetaData(); + } +#endif } void InformationPanelContent::showIcon(const KFileItem& item) { m_outdatedPreviewTimer->stop(); - if (!applyPlace(item.targetUrl())) { - QPixmap pixmap = QIcon::fromTheme(item.iconName()).pixmap(KIconLoader::SizeEnormous, KIconLoader::SizeEnormous); - KIconLoader::global()->drawOverlays(item.overlays(), pixmap, KIconLoader::Desktop); - m_preview->setPixmap(pixmap); - } + QPixmap pixmap = QIcon::fromTheme(item.iconName()).pixmap(KIconLoader::SizeEnormous, KIconLoader::SizeEnormous); + KIconLoader::global()->drawOverlays(item.overlays(), pixmap, KIconLoader::Desktop); + m_preview->setPixmap(pixmap); } void InformationPanelContent::showPreview(const KFileItem& item, @@ -352,21 +366,6 @@ void InformationPanelContent::refreshMetaData() } } -bool InformationPanelContent::applyPlace(const QUrl& url) -{ - const int count = m_placesItemModel->count(); - for (int i = 0; i < count; ++i) { - const PlacesItem* item = m_placesItemModel->placesItem(i); - if (item->url().matches(url, QUrl::StripTrailingSlash)) { - setNameLabelText(item->text()); - m_preview->setPixmap(QIcon::fromTheme(item->icon()).pixmap(128, 128)); - return true; - } - } - - return false; -} - void InformationPanelContent::setNameLabelText(const QString& text) { QTextOption textOption; diff --git a/src/panels/information/informationpanelcontent.h b/src/panels/information/informationpanelcontent.h index 80f3c8e22..9223fcc5a 100644 --- a/src/panels/information/informationpanelcontent.h +++ b/src/panels/information/informationpanelcontent.h @@ -116,14 +116,6 @@ private slots: private: /** - * Checks whether the an URL is repesented by a place. If yes, - * then the place icon and name are shown instead of a preview. - * @return True, if the URL represents exactly a place. - * @param url The url to check. - */ - bool applyPlace(const QUrl& url); - - /** * Sets the text for the label \a m_nameLabel and assures that the * text is split in a way that it can be wrapped within the * label width (QLabel::setWordWrap() does not work if the diff --git a/src/panels/places/placesitemmodel.cpp b/src/panels/places/placesitemmodel.cpp index 3641b3e42..7e313482d 100644 --- a/src/panels/places/placesitemmodel.cpp +++ b/src/panels/places/placesitemmodel.cpp @@ -453,7 +453,7 @@ void PlacesItemModel::initializeDefaultViewProperties() const } else if (path == QLatin1String("/images")) { props.setViewMode(DolphinView::IconsView); props.setPreviewsShown(true); - props.setVisibleRoles({"text", "imageSize"}); + props.setVisibleRoles({"text", "height", "width"}); } else if (path == QLatin1String("/audio")) { props.setViewMode(DolphinView::DetailsView); props.setPreviewsShown(false); @@ -597,7 +597,8 @@ void PlacesItemModel::onSourceModelDataChanged(const QModelIndex &topLeft, const void PlacesItemModel::onSourceModelGroupHiddenChanged(KFilePlacesModel::GroupType group, bool hidden) { - for(const QModelIndex &sourceIndex : m_sourceModel->groupIndexes(group)) { + const auto groupIndexes = m_sourceModel->groupIndexes(group); + for (const QModelIndex &sourceIndex : groupIndexes) { PlacesItem *item = placesItem(mapFromSource(sourceIndex)); if (item) { item->setGroupHidden(hidden); diff --git a/src/panels/places/placespanel.cpp b/src/panels/places/placespanel.cpp index 1f81a1eaa..00d8735c3 100644 --- a/src/panels/places/placespanel.cpp +++ b/src/panels/places/placespanel.cpp @@ -291,7 +291,7 @@ void PlacesPanel::slotViewContextMenuRequested(const QPointF& pos) {KIconLoader::SizeLarge, I18N_NOOP2_NOSTRIP("Huge icon size", "Huge (%1x%2)")} }; - QMap<QAction*, int> iconSizeActionMap; + QHash<QAction*, int> iconSizeActionMap; QActionGroup* iconSizeGroup = new QActionGroup(iconSizeSubMenu); for (int i = 0; i < iconSizeCount; ++i) { diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index c656173a8..07e4257a0 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -54,10 +54,14 @@ TEST_NAME viewpropertiestest LINK_LIBRARIES dolphinprivate dolphinstatic Qt5::Test) # DolphinMainWindowTest -ecm_add_test(dolphinmainwindowtest.cpp +set(dolphinmainwindowtest_SRCS dolphinmainwindowtest.cpp) +qt5_add_resources(dolphinmainwindowtest_SRCS ${CMAKE_SOURCE_DIR}/src/dolphin.qrc) + +ecm_add_test(${dolphinmainwindowtest_SRCS} TEST_NAME dolphinmainwindowtest LINK_LIBRARIES dolphinprivate dolphinstatic Qt5::Test) +# DragAndDropHelperTest ecm_add_test(draganddrophelpertest.cpp LINK_LIBRARIES dolphinprivate Qt5::Test) # PlacesItemModelTest diff --git a/src/tests/dolphinmainwindowtest.cpp b/src/tests/dolphinmainwindowtest.cpp index a31237f3c..70ec8dba0 100644 --- a/src/tests/dolphinmainwindowtest.cpp +++ b/src/tests/dolphinmainwindowtest.cpp @@ -34,6 +34,8 @@ class DolphinMainWindowTest : public QObject private slots: void init(); void testClosingTabsWithSearchBoxVisible(); + void testActiveViewAfterClosingSplitView_data(); + void testActiveViewAfterClosingSplitView(); void testUpdateWindowTitleAfterClosingSplitView(); private: @@ -68,6 +70,58 @@ void DolphinMainWindowTest::testClosingTabsWithSearchBoxVisible() QCOMPARE(tabWidget->count(), 1); } +void DolphinMainWindowTest::testActiveViewAfterClosingSplitView_data() +{ + QTest::addColumn<bool>("closeLeftView"); + + QTest::newRow("close left view") << true; + QTest::newRow("close right view") << false; +} + +void DolphinMainWindowTest::testActiveViewAfterClosingSplitView() +{ + m_mainWindow->openDirectories({ QUrl::fromLocalFile(QDir::homePath()) }, false); + m_mainWindow->show(); + QVERIFY(QTest::qWaitForWindowExposed(m_mainWindow.data())); + QVERIFY(m_mainWindow->isVisible()); + + auto tabWidget = m_mainWindow->findChild<DolphinTabWidget*>("tabWidget"); + QVERIFY(tabWidget); + QVERIFY(tabWidget->currentTabPage()->primaryViewContainer()); + QVERIFY(!tabWidget->currentTabPage()->secondaryViewContainer()); + + // Open split view. + m_mainWindow->actionCollection()->action(QStringLiteral("split_view"))->trigger(); + QVERIFY(tabWidget->currentTabPage()->splitViewEnabled()); + QVERIFY(tabWidget->currentTabPage()->secondaryViewContainer()); + + // Make sure the right view is the active one. + auto leftViewContainer = tabWidget->currentTabPage()->primaryViewContainer(); + auto rightViewContainer = tabWidget->currentTabPage()->secondaryViewContainer(); + QVERIFY(!leftViewContainer->isActive()); + QVERIFY(rightViewContainer->isActive()); + + QFETCH(bool, closeLeftView); + if (closeLeftView) { + // Activate left view. + leftViewContainer->setActive(true); + QVERIFY(leftViewContainer->isActive()); + QVERIFY(!rightViewContainer->isActive()); + + // Close left view. The secondary view (which was on the right) will become the primary one and must be active. + m_mainWindow->actionCollection()->action(QStringLiteral("split_view"))->trigger(); + QVERIFY(!leftViewContainer->isActive()); + QVERIFY(rightViewContainer->isActive()); + QCOMPARE(rightViewContainer, tabWidget->currentTabPage()->activeViewContainer()); + } else { + // Close right view. The left view will become active. + m_mainWindow->actionCollection()->action(QStringLiteral("split_view"))->trigger(); + QVERIFY(leftViewContainer->isActive()); + QVERIFY(!rightViewContainer->isActive()); + QCOMPARE(leftViewContainer, tabWidget->currentTabPage()->activeViewContainer()); + } +} + // Test case for bug #385111 void DolphinMainWindowTest::testUpdateWindowTitleAfterClosingSplitView() { @@ -99,6 +153,7 @@ void DolphinMainWindowTest::testUpdateWindowTitleAfterClosingSplitView() // Close split view. The secondary view (which was on the right) will become the primary one and must be active. m_mainWindow->actionCollection()->action(QStringLiteral("split_view"))->trigger(); + QVERIFY(!leftViewContainer->isActive()); QVERIFY(rightViewContainer->isActive()); QCOMPARE(rightViewContainer, tabWidget->currentTabPage()->activeViewContainer()); diff --git a/src/tests/placesitemmodeltest.cpp b/src/tests/placesitemmodeltest.cpp index 3263537f9..fc21ce055 100644 --- a/src/tests/placesitemmodeltest.cpp +++ b/src/tests/placesitemmodeltest.cpp @@ -228,7 +228,8 @@ void PlacesItemModelTest::init() void PlacesItemModelTest::cleanup() { - for (int i : m_tobeRemoved) { + const auto tobeRemoved = m_tobeRemoved; + for (const int i : tobeRemoved) { int before = m_model->count(); m_model->deleteItem(i); QTRY_COMPARE(m_model->count(), before - 1); diff --git a/src/views/dolphinviewactionhandler.cpp b/src/views/dolphinviewactionhandler.cpp index 2b3a241a3..95c140cc5 100644 --- a/src/views/dolphinviewactionhandler.cpp +++ b/src/views/dolphinviewactionhandler.cpp @@ -122,7 +122,7 @@ void DolphinViewActionHandler::createActions() QAction* deleteWithTrashShortcut = m_actionCollection->addAction(QStringLiteral("delete_shortcut")); // The descriptive text is just for the shortcuts editor. deleteWithTrashShortcut->setText(i18nc("@action \"Move to Trash\" for non-local files, etc.", "Delete (using shortcut for Trash)")); - m_actionCollection->setDefaultShortcut(deleteWithTrashShortcut, QKeySequence::Delete); + m_actionCollection->setDefaultShortcuts(deleteWithTrashShortcut, KStandardShortcut::moveToTrash()); deleteWithTrashShortcut->setEnabled(false); connect(deleteWithTrashShortcut, &QAction::triggered, this, &DolphinViewActionHandler::slotDeleteItems); |
