diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp index 53f9826c9..dc5e37ff7 100644 --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -484,6 +484,8 @@ void DolphinMainWindow::openNewTab(const KUrl& url) m_viewTab.append(viewTab); actionCollection()->action("close_tab")->setEnabled(true); + actionCollection()->action("activate_prev_tab")->setEnabled(true); + actionCollection()->action("activate_next_tab")->setEnabled(true); // Provide a split view, if the startup settings are set this way if (GeneralSettings::splitView()) { @@ -1159,6 +1161,8 @@ void DolphinMainWindow::closeTab(int index) if (m_viewTab.count() == 1) { m_tabBar->removeTab(0); actionCollection()->action("close_tab")->setEnabled(false); + actionCollection()->action("activate_prev_tab")->setEnabled(false); + actionCollection()->action("activate_next_tab")->setEnabled(false); } else { m_tabBar->blockSignals(false); } @@ -1638,12 +1642,16 @@ void DolphinMainWindow::setupActions() prevTabKeys.append(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_Tab)); QAction* activateNextTab = actionCollection()->addAction("activate_next_tab"); + activateNextTab->setIconText(i18nc("@action:inmenu", "Next Tab")); activateNextTab->setText(i18nc("@action:inmenu", "Activate Next Tab")); + activateNextTab->setEnabled(false); connect(activateNextTab, &QAction::triggered, this, &DolphinMainWindow::activateNextTab); activateNextTab->setShortcuts(QApplication::isRightToLeft() ? prevTabKeys : nextTabKeys); QAction* activatePrevTab = actionCollection()->addAction("activate_prev_tab"); + activatePrevTab->setIconText(i18nc("@action:inmenu", "Previous Tab")); activatePrevTab->setText(i18nc("@action:inmenu", "Activate Previous Tab")); + activatePrevTab->setEnabled(false); connect(activatePrevTab, &QAction::triggered, this, &DolphinMainWindow::activatePrevTab); activatePrevTab->setShortcuts(QApplication::isRightToLeft() ? nextTabKeys : prevTabKeys); diff --git a/src/dolphinpart.desktop b/src/dolphinpart.desktop index 10339e4bc..bdc3b929d 100644 --- a/src/dolphinpart.desktop +++ b/src/dolphinpart.desktop @@ -213,6 +213,7 @@ Name[gl]=Compacto Name[he]=מרוכז Name[hu]=Kompakt Name[ia]=Compacte +Name[is]=Þjappað Name[it]=Compatta Name[kk]=Ықшамды Name[km]=តូច​ល្មម diff --git a/src/dolphinviewcontainer.cpp b/src/dolphinviewcontainer.cpp index ae9cd93c0..761062585 100644 --- a/src/dolphinviewcontainer.cpp +++ b/src/dolphinviewcontainer.cpp @@ -338,36 +338,18 @@ void DolphinViewContainer::setSearchModeEnabled(bool enabled) m_urlNavigator->setVisible(!enabled); if (enabled) { - KUrl url = m_urlNavigator->locationUrl(); - m_searchBox->setText(QString()); - m_searchBox->setReadOnly(isSearchUrl(url), url); - - // Remember the most recent non-search URL as search path - // of the search-box, so that it can be restored - // when switching back to the URL navigator. - int index = m_urlNavigator->historyIndex(); - const int historySize = m_urlNavigator->historySize(); - while (isSearchUrl(url) && (index < historySize)) { - ++index; - url = m_urlNavigator->locationUrl(index); - } - - if (!isSearchUrl(url)) { - m_searchBox->setSearchPath(url); - } + const KUrl& locationUrl = m_urlNavigator->locationUrl(); + m_searchBox->fromSearchUrl(locationUrl); } else { m_view->setViewPropertiesContext(QString()); // Restore the URL for the URL navigator. If Dolphin has been // started with a search-URL, the home URL is used as fallback. - const KUrl url = m_searchBox->searchPath(); - if (url.isValid() && !url.isEmpty()) { - if (isSearchUrl(url)) { - m_urlNavigator->goHome(); - } else { - m_urlNavigator->setLocationUrl(url); - } + KUrl url = m_searchBox->searchPath(); + if (url.isEmpty() || !url.isValid() || isSearchUrl(url)) { + url = GeneralSettings::self()->homeUrl(); } + m_urlNavigator->setLocationUrl(url); } } diff --git a/src/kitemviews/kfileitemlistwidget.cpp b/src/kitemviews/kfileitemlistwidget.cpp index 688a4da08..fe8c7e997 100644 --- a/src/kitemviews/kfileitemlistwidget.cpp +++ b/src/kitemviews/kfileitemlistwidget.cpp @@ -46,6 +46,15 @@ QString KFileItemListWidgetInformant::itemText(int index, const KItemListView* v return item.text(); } +bool KFileItemListWidgetInformant::itemIsLink(int index, const KItemListView* view) const +{ + Q_ASSERT(qobject_cast(view->model())); + KFileItemModel* fileItemModel = static_cast(view->model()); + + const KFileItem item = fileItemModel->fileItem(index); + return item.isLink(); +} + QString KFileItemListWidgetInformant::roleText(const QByteArray& role, const QHash& values) const { @@ -81,6 +90,15 @@ QString KFileItemListWidgetInformant::roleText(const QByteArray& role, return text; } +QFont KFileItemListWidgetInformant::customizedFontForLinks(const QFont& baseFont) const +{ + // The customized font should be italic if the file is a symbolic link. + QFont font(baseFont); + font.setItalic(true); + return font; +} + + KFileItemListWidget::KFileItemListWidget(KItemListWidgetInformant* informant, QGraphicsItem* parent) : KStandardItemListWidget(informant, parent) { diff --git a/src/kitemviews/kfileitemlistwidget.h b/src/kitemviews/kfileitemlistwidget.h index 1d7bc7f01..8e8958b16 100644 --- a/src/kitemviews/kfileitemlistwidget.h +++ b/src/kitemviews/kfileitemlistwidget.h @@ -32,7 +32,9 @@ public: protected: virtual QString itemText(int index, const KItemListView* view) const; + virtual bool itemIsLink(int index, const KItemListView* view) const; virtual QString roleText(const QByteArray& role, const QHash& values) const; + virtual QFont customizedFontForLinks(const QFont& baseFont) const; }; class LIBDOLPHINPRIVATE_EXPORT KFileItemListWidget : public KStandardItemListWidget diff --git a/src/kitemviews/kfileitemmodel.cpp b/src/kitemviews/kfileitemmodel.cpp index 066af20f7..196172f1d 100644 --- a/src/kitemviews/kfileitemmodel.cpp +++ b/src/kitemviews/kfileitemmodel.cpp @@ -218,7 +218,7 @@ void KFileItemModel::setShowHiddenFiles(bool show) m_dirLister->setShowingDotFiles(show); m_dirLister->emitChanges(); if (show) { - slotCompleted(); + dispatchPendingItemsToInsert(); } } diff --git a/src/kitemviews/kitemlistcontroller.cpp b/src/kitemviews/kitemlistcontroller.cpp index f45537445..e90f301a9 100644 --- a/src/kitemviews/kitemlistcontroller.cpp +++ b/src/kitemviews/kitemlistcontroller.cpp @@ -538,11 +538,10 @@ bool KItemListController::mousePressEvent(QGraphicsSceneMouseEvent* event, const m_pressedIndex = m_view->itemAt(m_pressedMousePos); emit mouseButtonPressed(m_pressedIndex, event->buttons()); - if ((event->buttons() & (Qt::XButton1 | Qt::XButton2)) && m_pressedIndex < 0) { - // Do not select items when clicking the empty part of the view with - // the back/forward buttons, see https://bugs.kde.org/show_bug.cgi?id=327412. - // Note that clicking an item with these buttons selects it, see comment in - // DolphinView::slotMouseButtonPressed(int, Qt::MouseButtons). + // TODO: Qt5: Replace Qt::XButton1 by Qt::BackButton and Qt::XButton2 by Qt::ForwardButton + if (event->buttons() & (Qt::XButton1 | Qt::XButton2)) { + // Do not select items when clicking the back/forward buttons, see + // https://bugs.kde.org/show_bug.cgi?id=327412. return true; } @@ -952,8 +951,13 @@ bool KItemListController::hoverMoveEvent(QGraphicsSceneHoverEvent* event, const if (newHoveredWidget) { newHoveredWidget->setHovered(true); + const QPointF mappedPos = newHoveredWidget->mapFromItem(m_view, pos); + newHoveredWidget->setHoverPosition(mappedPos); emit itemHovered(newHoveredWidget->index()); } + } else if (oldHoveredWidget) { + const QPointF mappedPos = oldHoveredWidget->mapFromItem(m_view, pos); + oldHoveredWidget->setHoverPosition(mappedPos); } return false; diff --git a/src/kitemviews/kitemlistselectionmanager.cpp b/src/kitemviews/kitemlistselectionmanager.cpp index ebff1a30e..1f0a89d06 100644 --- a/src/kitemviews/kitemlistselectionmanager.cpp +++ b/src/kitemviews/kitemlistselectionmanager.cpp @@ -331,6 +331,11 @@ void KItemListSelectionManager::itemsMoved(const KItemRange& itemRange, const QL // Store the current selection (needed in the selectionChanged() signal) const KItemSet previousSelection = selectedItems(); + // endAnchoredSelection() adds all items between m_currentItem and + // m_anchorItem to m_selectedItems. They can then be moved + // individually later in this function. + endAnchoredSelection(); + // Update the current item if (m_currentItem >= itemRange.index && m_currentItem < itemRange.index + itemRange.count) { const int previousCurrentItem = m_currentItem; @@ -342,10 +347,8 @@ void KItemListSelectionManager::itemsMoved(const KItemRange& itemRange, const QL emit currentChanged(newCurrentItem, previousCurrentItem); } - // Update the anchor item - if (m_anchorItem >= itemRange.index && m_anchorItem < itemRange.index + itemRange.count) { - m_anchorItem = movedToIndexes.at(m_anchorItem - itemRange.index); - } + // Start a new anchored selection. + beginAnchoredSelection(m_currentItem); // Update the selections if (!m_selectedItems.isEmpty()) { diff --git a/src/kitemviews/kitemliststyleoption.cpp b/src/kitemviews/kitemliststyleoption.cpp index ac2587962..edd6363c8 100644 --- a/src/kitemviews/kitemliststyleoption.cpp +++ b/src/kitemviews/kitemliststyleoption.cpp @@ -31,7 +31,8 @@ KItemListStyleOption::KItemListStyleOption() : verticalMargin(-1), iconSize(-1), extendedSelectionRegion(false), - maxTextSize() + maxTextLines(0), + maxTextWidth(0) { } @@ -45,7 +46,8 @@ KItemListStyleOption::KItemListStyleOption(const KItemListStyleOption& other) : verticalMargin(other.verticalMargin), iconSize(other.iconSize), extendedSelectionRegion(other.extendedSelectionRegion), - maxTextSize(other.maxTextSize) + maxTextLines(other.maxTextLines), + maxTextWidth(other.maxTextWidth) { } diff --git a/src/kitemviews/kitemliststyleoption.h b/src/kitemviews/kitemliststyleoption.h index 1a304fc28..782dd0ec2 100644 --- a/src/kitemviews/kitemliststyleoption.h +++ b/src/kitemviews/kitemliststyleoption.h @@ -43,7 +43,8 @@ public: int verticalMargin; int iconSize; bool extendedSelectionRegion; - QSize maxTextSize; + int maxTextLines; + int maxTextWidth; }; #endif diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp index abde53904..0090f8620 100644 --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -765,7 +765,8 @@ void KItemListView::setStyleOption(const KItemListStyleOption& option) updateGroupHeaderHeight(); } - if (animate && previousOption.maxTextSize != option.maxTextSize) { + if (animate && + (previousOption.maxTextLines != option.maxTextLines || previousOption.maxTextWidth != option.maxTextWidth)) { // Animating a change of the maximum text size just results in expensive // temporary eliding and clipping operations and does not look good visually. animate = false; @@ -898,11 +899,23 @@ void KItemListView::onTransactionEnd() bool KItemListView::event(QEvent* event) { - // Forward all events to the controller and handle them there - if (!m_editingRole && m_controller && m_controller->processEvent(event, transform())) { - event->accept(); - return true; + switch (event->type()) { + case QEvent::PaletteChange: + updatePalette(); + break; + + case QEvent::FontChange: + updateFont(); + break; + + default: + // Forward all other events to the controller and handle them there + if (!m_editingRole && m_controller && m_controller->processEvent(event, transform())) { + event->accept(); + return true; + } } + return QGraphicsWidget::event(event); } @@ -955,6 +968,27 @@ QList KItemListView::visibleItemListWidgets() const return m_visibleItems.values(); } +void KItemListView::updateFont() +{ + if (scene() && !scene()->views().isEmpty()) { + KItemListStyleOption option = styleOption(); + option.font = scene()->views().first()->font(); + option.fontMetrics = QFontMetrics(option.font); + + setStyleOption(option); + } +} + +void KItemListView::updatePalette() +{ + if (scene() && !scene()->views().isEmpty()) { + KItemListStyleOption option = styleOption(); + option.palette = scene()->views().first()->palette(); + + setStyleOption(option); + } +} + void KItemListView::slotItemsInserted(const KItemRangeList& itemRanges) { if (m_itemSize.isEmpty()) { diff --git a/src/kitemviews/kitemlistview.h b/src/kitemviews/kitemlistview.h index f39e73a97..8a522a686 100644 --- a/src/kitemviews/kitemlistview.h +++ b/src/kitemviews/kitemlistview.h @@ -388,6 +388,9 @@ protected: QList visibleItemListWidgets() const; + virtual void updateFont(); + virtual void updatePalette(); + protected slots: virtual void slotItemsInserted(const KItemRangeList& itemRanges); virtual void slotItemsRemoved(const KItemRangeList& itemRanges); diff --git a/src/kitemviews/kitemlistwidget.cpp b/src/kitemviews/kitemlistwidget.cpp index d02cbe3bb..38f9d0078 100644 --- a/src/kitemviews/kitemlistwidget.cpp +++ b/src/kitemviews/kitemlistwidget.cpp @@ -279,6 +279,13 @@ bool KItemListWidget::isHovered() const return m_hovered; } +void KItemListWidget::setHoverPosition(const QPointF& pos) +{ + if (m_selectionToggle) { + m_selectionToggle->setHovered(m_selectionToggle->contains(pos)); + } +} + void KItemListWidget::setAlternateBackground(bool enable) { if (m_alternateBackground != enable) { diff --git a/src/kitemviews/kitemlistwidget.h b/src/kitemviews/kitemlistwidget.h index 954629ddd..cfb9155eb 100644 --- a/src/kitemviews/kitemlistwidget.h +++ b/src/kitemviews/kitemlistwidget.h @@ -108,6 +108,8 @@ public: void setHovered(bool hovered); bool isHovered() const; + void setHoverPosition(const QPointF& pos); + void setAlternateBackground(bool enable); bool alternateBackground() const; diff --git a/src/kitemviews/kstandarditemlistwidget.cpp b/src/kitemviews/kstandarditemlistwidget.cpp index 18a5391bb..7a9f31a15 100644 --- a/src/kitemviews/kstandarditemlistwidget.cpp +++ b/src/kitemviews/kstandarditemlistwidget.cpp @@ -86,16 +86,22 @@ qreal KStandardItemListWidgetInformant::preferredRoleColumnWidth(const QByteArra const QString text = roleText(role, values); qreal width = KStandardItemListWidget::columnPadding(option); + const QFontMetrics& normalFontMetrics = option.fontMetrics; + const QFontMetrics linkFontMetrics(customizedFontForLinks(option.font)); + if (role == "rating") { width += KStandardItemListWidget::preferredRatingSize(option).width(); } else { - width += option.fontMetrics.width(text); + // If current item is a link, we use the customized link font metrics instead of the normal font metrics. + const QFontMetrics& fontMetrics = itemIsLink(index, view) ? linkFontMetrics : normalFontMetrics; + + width += fontMetrics.width(text); if (role == "text") { if (view->supportsItemExpanding()) { // Increase the width by the expansion-toggle and the current expansion level const int expandedParentsCount = values.value("expandedParentsCount", 0).toInt(); - const qreal height = option.padding * 2 + qMax(option.iconSize, option.fontMetrics.height()); + const qreal height = option.padding * 2 + qMax(option.iconSize, fontMetrics.height()); width += (expandedParentsCount + 1) * height; } @@ -112,6 +118,11 @@ QString KStandardItemListWidgetInformant::itemText(int index, const KItemListVie return view->model()->data(index).value("text").toString(); } +bool KStandardItemListWidgetInformant::itemIsLink(int index, const KItemListView* view) const +{ + return false; +} + QString KStandardItemListWidgetInformant::roleText(const QByteArray& role, const QHash& values) const { @@ -122,18 +133,24 @@ QString KStandardItemListWidgetInformant::roleText(const QByteArray& role, return values.value(role).toString(); } +QFont KStandardItemListWidgetInformant::customizedFontForLinks(const QFont& baseFont) const +{ + return baseFont; +} + void KStandardItemListWidgetInformant::calculateIconsLayoutItemSizeHints(QVector& sizeHints, const KItemListView* view) const { const KItemListStyleOption& option = view->styleOption(); - const QFont& font = option.font; + const QFont& normalFont = option.font; const int additionalRolesCount = qMax(view->visibleRoles().count() - 1, 0); const qreal itemWidth = view->itemSize().width(); const qreal maxWidth = itemWidth - 2 * option.padding; - const qreal maxTextHeight = option.maxTextSize.height(); const qreal additionalRolesSpacing = additionalRolesCount * option.fontMetrics.lineSpacing(); const qreal spacingAndIconHeight = option.iconSize + option.padding * 3; + const QFont linkFont = customizedFontForLinks(normalFont); + QTextOption textOption(Qt::AlignHCenter); textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); @@ -142,6 +159,9 @@ void KStandardItemListWidgetInformant::calculateIconsLayoutItemSizeHints(QVector continue; } + // If the current item is a link, we use the customized link font instead of the normal font. + const QFont& font = itemIsLink(index, view) ? linkFont : normalFont; + const QString& text = KStringHandler::preProcessWrap(itemText(index, view)); // Calculate the number of lines required for wrapping the name @@ -150,20 +170,22 @@ void KStandardItemListWidgetInformant::calculateIconsLayoutItemSizeHints(QVector layout.setTextOption(textOption); layout.beginLayout(); QTextLine line; + int lineCount = 0; while ((line = layout.createLine()).isValid()) { line.setLineWidth(maxWidth); line.naturalTextWidth(); textHeight += line.height(); + + ++lineCount; + if (lineCount == option.maxTextLines) { + break; + } } layout.endLayout(); // Add one line for each additional information textHeight += additionalRolesSpacing; - if (maxTextHeight > 0 && textHeight > maxTextHeight) { - textHeight = maxTextHeight; - } - sizeHints[index] = QSizeF(itemWidth, textHeight + spacingAndIconHeight); } } @@ -171,20 +193,25 @@ void KStandardItemListWidgetInformant::calculateIconsLayoutItemSizeHints(QVector void KStandardItemListWidgetInformant::calculateCompactLayoutItemSizeHints(QVector& sizeHints, const KItemListView* view) const { const KItemListStyleOption& option = view->styleOption(); - const QFontMetrics& fontMetrics = option.fontMetrics; + const QFontMetrics& normalFontMetrics = option.fontMetrics; const int additionalRolesCount = qMax(view->visibleRoles().count() - 1, 0); const QList& visibleRoles = view->visibleRoles(); const bool showOnlyTextRole = (visibleRoles.count() == 1) && (visibleRoles.first() == "text"); - const qreal maxWidth = option.maxTextSize.width(); + const qreal maxWidth = option.maxTextWidth; const qreal paddingAndIconWidth = option.padding * 4 + option.iconSize; - const qreal height = option.padding * 2 + qMax(option.iconSize, (1 + additionalRolesCount) * option.fontMetrics.lineSpacing()); + const qreal height = option.padding * 2 + qMax(option.iconSize, (1 + additionalRolesCount) * normalFontMetrics.lineSpacing()); + + const QFontMetrics linkFontMetrics(customizedFontForLinks(option.font)); for (int index = 0; index < sizeHints.count(); ++index) { if (!sizeHints.at(index).isEmpty()) { continue; } + // If the current item is a link, we use the customized link font metrics instead of the normal font metrics. + const QFontMetrics& fontMetrics = itemIsLink(index, view) ? linkFontMetrics : normalFontMetrics; + // For each row exactly one role is shown. Calculate the maximum required width that is necessary // to show all roles without horizontal clipping. qreal maximumRequiredWidth = 0.0; @@ -631,6 +658,12 @@ void KStandardItemListWidget::dataChanged(const QHash& cur dirtyRoles = roles; } + // The URL might have changed (i.e., if the sort order of the items has + // been changed). Therefore, the "is cut" state must be updated. + KFileItemClipboard* clipboard = KFileItemClipboard::instance(); + const KUrl itemUrl = data().value("url").value(); + m_isCut = clipboard->isCut(itemUrl); + // The icon-state might depend from other roles and hence is // marked as dirty whenever a role has been changed dirtyRoles.insert("iconPixmap"); @@ -1066,9 +1099,6 @@ void KStandardItemListWidget::updateIconsLayoutTextCache() qreal nameHeight = 0; QTextLine line; - const int additionalRolesCount = qMax(visibleRoles().count() - 1, 0); - const int maxNameLines = (option.maxTextSize.height() / int(lineSpacing)) - additionalRolesCount; - QTextLayout layout(nameTextInfo->staticText.text(), m_customizedFont); layout.setTextOption(nameTextInfo->staticText.textOption()); layout.beginLayout(); @@ -1079,7 +1109,7 @@ void KStandardItemListWidget::updateIconsLayoutTextCache() nameHeight += line.height(); ++nameLineIndex; - if (nameLineIndex == maxNameLines) { + if (nameLineIndex == option.maxTextLines) { // The maximum number of textlines has been reached. If this is // the case provide an elided text if necessary. const int textLength = line.textStart() + line.textLength(); @@ -1101,6 +1131,7 @@ void KStandardItemListWidget::updateIconsLayoutTextCache() layout.endLayout(); // Use one line for each additional information + const int additionalRolesCount = qMax(visibleRoles().count() - 1, 0); nameTextInfo->staticText.setTextWidth(maxWidth); nameTextInfo->pos = QPointF(padding, widgetHeight - nameHeight - diff --git a/src/kitemviews/kstandarditemlistwidget.h b/src/kitemviews/kstandarditemlistwidget.h index ca198c36b..ba426d054 100644 --- a/src/kitemviews/kstandarditemlistwidget.h +++ b/src/kitemviews/kstandarditemlistwidget.h @@ -53,6 +53,13 @@ protected: */ virtual QString itemText(int index, const KItemListView* view) const; + /** + * @return The value of the "isLink" role. The default implementation returns false. + * The derived class should reimplement this function, when information about + * links is available and in usage. + */ + virtual bool itemIsLink(int index, const KItemListView* view) const; + /** * @return String representation of the role \a role. The representation of * a role might depend on other roles, so the values of all roles @@ -61,6 +68,11 @@ protected: virtual QString roleText(const QByteArray& role, const QHash& values) const; + /** + * @return A font based on baseFont which is customized for symlinks. + */ + virtual QFont customizedFontForLinks(const QFont& baseFont) const; + void calculateIconsLayoutItemSizeHints(QVector& sizeHints, const KItemListView* view) const; void calculateCompactLayoutItemSizeHints(QVector& sizeHints, const KItemListView* view) const; void calculateDetailsLayoutItemSizeHints(QVector& sizeHints, const KItemListView* view) const; diff --git a/src/kitemviews/private/kdirectorycontentscounter.cpp b/src/kitemviews/private/kdirectorycontentscounter.cpp index 0e43dea2e..cd448e233 100644 --- a/src/kitemviews/private/kdirectorycontentscounter.cpp +++ b/src/kitemviews/private/kdirectorycontentscounter.cpp @@ -60,14 +60,23 @@ KDirectoryContentsCounter::~KDirectoryContentsCounter() { --m_workersCount; - if (m_workersCount == 0) { + if (m_workersCount > 0) { + // The worker thread will continue running. It could even be running + // a method of m_worker at the moment, so we delete it using + // deleteLater() to prevent a crash. + m_worker->deleteLater(); + } else { + // There are no remaining workers -> stop the worker thread. m_workerThread->quit(); m_workerThread->wait(); delete m_workerThread; m_workerThread = 0; - } - delete m_worker; + // The worker thread has finished running now, so it's safe to delete + // m_worker. deleteLater() would not work at all because the event loop + // which would deliver the event to m_worker is not running any more. + delete m_worker; + } } void KDirectoryContentsCounter::addDirectory(const QString& path) diff --git a/src/kitemviews/private/kitemlistselectiontoggle.cpp b/src/kitemviews/private/kitemlistselectiontoggle.cpp index 6bbf3c2ec..accbe5181 100644 --- a/src/kitemviews/private/kitemlistselectiontoggle.cpp +++ b/src/kitemviews/private/kitemlistselectiontoggle.cpp @@ -30,7 +30,6 @@ KItemListSelectionToggle::KItemListSelectionToggle(QGraphicsItem* parent) : m_checked(false), m_hovered(false) { - setAcceptHoverEvents(true); } KItemListSelectionToggle::~KItemListSelectionToggle() @@ -51,6 +50,15 @@ bool KItemListSelectionToggle::isChecked() const return m_checked; } +void KItemListSelectionToggle::setHovered(bool hovered) +{ + if (m_hovered != hovered) { + m_hovered = hovered; + m_pixmap = QPixmap(); + update(); + } +} + void KItemListSelectionToggle::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { Q_UNUSED(option); @@ -65,20 +73,6 @@ void KItemListSelectionToggle::paint(QPainter* painter, const QStyleOptionGraphi painter->drawPixmap(x, y, m_pixmap); } -void KItemListSelectionToggle::hoverEnterEvent(QGraphicsSceneHoverEvent* event) -{ - QGraphicsWidget::hoverEnterEvent(event); - m_hovered = true; - m_pixmap = QPixmap(); -} - -void KItemListSelectionToggle::hoverLeaveEvent(QGraphicsSceneHoverEvent* event) -{ - QGraphicsWidget::hoverLeaveEvent(event); - m_hovered = false; - m_pixmap = QPixmap(); -} - void KItemListSelectionToggle::resizeEvent(QGraphicsSceneResizeEvent* event) { QGraphicsWidget::resizeEvent(event); @@ -97,12 +91,9 @@ void KItemListSelectionToggle::resizeEvent(QGraphicsSceneResizeEvent* event) void KItemListSelectionToggle::updatePixmap() { - const char* icon = m_checked ? "list-remove" : "list-add"; - m_pixmap = KIconLoader::global()->loadIcon(QLatin1String(icon), KIconLoader::NoGroup, iconSize()); - - if (m_hovered) { - KIconLoader::global()->iconEffect()->apply(m_pixmap, KIconLoader::Desktop, KIconLoader::ActiveState); - } + const QString icon = m_checked ? "list-remove" : "list-add"; + const KIconLoader::States state = m_hovered ? KIconLoader::ActiveState : KIconLoader::DisabledState; + m_pixmap = KIconLoader::global()->loadIcon(icon, KIconLoader::Desktop, iconSize(), state); } int KItemListSelectionToggle::iconSize() const diff --git a/src/kitemviews/private/kitemlistselectiontoggle.h b/src/kitemviews/private/kitemlistselectiontoggle.h index ba29293f6..758dc63bb 100644 --- a/src/kitemviews/private/kitemlistselectiontoggle.h +++ b/src/kitemviews/private/kitemlistselectiontoggle.h @@ -41,11 +41,11 @@ public: void setChecked(bool checked); bool isChecked() const; + void setHovered(bool hovered); + virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0); protected: - virtual void hoverEnterEvent(QGraphicsSceneHoverEvent* event); - virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent* event); virtual void resizeEvent(QGraphicsSceneResizeEvent* event); private: diff --git a/src/kitemviews/private/kitemlistviewanimation.cpp b/src/kitemviews/private/kitemlistviewanimation.cpp index 1ddeb2b19..43eed98c5 100644 --- a/src/kitemviews/private/kitemlistviewanimation.cpp +++ b/src/kitemviews/private/kitemlistviewanimation.cpp @@ -225,13 +225,13 @@ void KItemListViewAnimation::slotFinished() { QPropertyAnimation* finishedAnim = qobject_cast(sender()); for (int type = 0; type < AnimationTypeCount; ++type) { - QHashIterator it(m_animation[type]); + QMutableHashIterator it(m_animation[type]); while (it.hasNext()) { it.next(); QPropertyAnimation* propertyAnim = it.value(); if (propertyAnim == finishedAnim) { QGraphicsWidget* widget = it.key(); - m_animation[type].remove(widget); + it.remove(); finishedAnim->deleteLater(); emit finished(widget, static_cast(type)); diff --git a/src/panels/information/informationpanelcontent.cpp b/src/panels/information/informationpanelcontent.cpp index fd58eb608..9dc59db13 100644 --- a/src/panels/information/informationpanelcontent.cpp +++ b/src/panels/information/informationpanelcontent.cpp @@ -276,6 +276,10 @@ bool InformationPanelContent::eventFilter(QObject* obj, QEvent* event) adjustWidgetSizes(parentWidget()->width()); break; + case QEvent::FontChange: + m_metaDataWidget->setFont(KGlobalSettings::smallestReadableFont()); + break; + default: break; } diff --git a/src/panels/places/placesitemmodel.cpp b/src/panels/places/placesitemmodel.cpp index 1f8a213e3..6ba91c5ba 100644 --- a/src/panels/places/placesitemmodel.cpp +++ b/src/panels/places/placesitemmodel.cpp @@ -651,6 +651,7 @@ void PlacesItemModel::updateBookmarks() found = true; if (newBookmark.metaDataItem("UDI").isEmpty()) { item->setBookmark(newBookmark); + item->setText(i18nc("KFile System Bookmarks", newBookmark.text().toUtf8().data())); } break; } diff --git a/src/panels/places/placespanel.cpp b/src/panels/places/placespanel.cpp index 1f825426e..d3614c9ce 100644 --- a/src/panels/places/placespanel.cpp +++ b/src/panels/places/placespanel.cpp @@ -286,8 +286,9 @@ void PlacesPanel::slotItemContextMenuRequested(int index, const QPointF& pos) } else if (action == hideAction) { item->setHidden(hideAction->isChecked()); } else if (action == openInNewTabAction) { - const KUrl url = m_model->item(index)->dataValue("url").value(); - emit placeMiddleClicked(url); + // TriggerItem does set up the storage first and then it will + // emit the slotItemMiddleClicked signal, because of Qt::MiddleButton. + triggerItem(index, Qt::MiddleButton); } else if (action == teardownAction) { m_model->requestTeardown(index); } else if (action == ejectAction) { diff --git a/src/search/dolphinfacetswidget.cpp b/src/search/dolphinfacetswidget.cpp index 4fd2eb30b..fa46a50e8 100644 --- a/src/search/dolphinfacetswidget.cpp +++ b/src/search/dolphinfacetswidget.cpp @@ -46,13 +46,16 @@ DolphinFacetsWidget::DolphinFacetsWidget(QWidget* parent) : m_fourOrMore(0), m_maxRating(0) { - m_documents = createCheckBox(i18nc("@option:check", "Documents")); - m_images = createCheckBox(i18nc("@option:check", "Images")); - m_audio = createCheckBox(i18nc("@option:check", "Audio Files")); - m_videos = createCheckBox(i18nc("@option:check", "Videos")); + QButtonGroup* filetypeGroup = new QButtonGroup(this); + m_anyType = createRadioButton(i18nc("@option:check", "Any"), filetypeGroup); + m_documents = createRadioButton(i18nc("@option:check", "Documents"), filetypeGroup); + m_images = createRadioButton(i18nc("@option:check", "Images"), filetypeGroup); + m_audio = createRadioButton(i18nc("@option:check", "Audio Files"), filetypeGroup); + m_videos = createRadioButton(i18nc("@option:check", "Videos"), filetypeGroup); QVBoxLayout* typeLayout = new QVBoxLayout(); typeLayout->setSpacing(0); + typeLayout->addWidget(m_anyType); typeLayout->addWidget(m_documents); typeLayout->addWidget(m_images); typeLayout->addWidget(m_audio); @@ -100,6 +103,7 @@ DolphinFacetsWidget::DolphinFacetsWidget(QWidget* parent) : topLayout->addLayout(ratingLayout); topLayout->addStretch(); + m_anyType->setChecked(true); m_anytime->setChecked(true); m_anyRating->setChecked(true); } @@ -111,6 +115,9 @@ DolphinFacetsWidget::~DolphinFacetsWidget() #ifdef HAVE_BALOO Baloo::Term DolphinFacetsWidget::ratingTerm() const { + Baloo::Term ratingTerm; + Baloo::Term modifiedTerm; + if (!m_anyRating->isChecked()) { int stars = 1; // represents m_oneOrMore if (m_twoOrMore->isChecked()) { @@ -124,15 +131,9 @@ Baloo::Term DolphinFacetsWidget::ratingTerm() const } const int rating = stars * 2; - - Baloo::Term term("rating", rating, Baloo::Term::GreaterEqual); - return term; + ratingTerm = Baloo::Term("rating", rating, Baloo::Term::GreaterEqual); } - return Baloo::Term(); - - /* - // FIXME: Handle date time filters if (!m_anytime->isChecked()) { QDate date = QDate::currentDate(); // represents m_today if (m_yesterday->isChecked()) { @@ -145,44 +146,149 @@ Baloo::Term DolphinFacetsWidget::ratingTerm() const date = date.addDays(1 - date.dayOfYear()); } - Nepomuk2::Query::ComparisonTerm term(Nepomuk2::Vocabulary::NIE::lastModified(), - Nepomuk2::Query::LiteralTerm(QDateTime(date)), - Nepomuk2::Query::ComparisonTerm::GreaterOrEqual); - andTerm.addSubTerm(term); + modifiedTerm = Baloo::Term("modified", date, Baloo::Term::GreaterEqual); } - */ + + if (ratingTerm.isValid() && modifiedTerm.isValid()) { + Baloo::Term term(Baloo::Term::And); + term.addSubTerm(ratingTerm); + term.addSubTerm(modifiedTerm); + + return term; + } else if (modifiedTerm.isValid()) { + return modifiedTerm; + } else if (ratingTerm.isValid()) { + return ratingTerm; + } + + return Baloo::Term(); } -QStringList DolphinFacetsWidget::facetTypes() const +QString DolphinFacetsWidget::facetType() const { - QStringList types; if (m_documents->isChecked()) { - types << "Document"; + return QLatin1String("Document"); + } else if (m_images->isChecked()) { + return QLatin1String("Image"); + } else if (m_audio->isChecked()) { + return QLatin1String("Audio"); + } else if (m_videos->isChecked()) { + return QLatin1String("Video"); } - if (m_images->isChecked()) { - types << "Image"; + return QString(); +} + +bool DolphinFacetsWidget::isRatingTerm(const Baloo::Term& term) const +{ + const QList subTerms = term.subTerms(); + if (subTerms.isEmpty()) { + // If term has no sub terms, then the term itself is either a "rating" term + // or a "modified" term. + return term.property() == QLatin1String("modified") || + term.property() == QLatin1String("rating"); + + } else if (subTerms.size() == 2) { + // If term has sub terms, then the sub terms are always "rating" and "modified" terms. + + QStringList properties; + foreach (const Baloo::Term& subTerm, subTerms) { + properties << subTerm.property(); + } + + return properties.contains(QLatin1String("modified")) && + properties.contains(QLatin1String("rating")); } - if (m_audio->isChecked()) { - types << "Audio"; + return false; +} + +void DolphinFacetsWidget::setRatingTerm(const Baloo::Term& term) +{ + // If term has sub terms, then the sub terms are always "rating" and "modified" terms. + // If term has no sub terms, then the term itself is either a "rating" term or a "modified" + // term. To avoid code duplication we add term to subTerms list, if the list is empty. + QList subTerms = term.subTerms(); + if (subTerms.isEmpty()) { + subTerms << term; } - if (m_videos->isChecked()) { - types << "Video"; - } + foreach (const Baloo::Term& subTerm, subTerms) { + const QString property = subTerm.property(); - return types; + if (property == QLatin1String("modified")) { + const QDate date = subTerm.value().toDate(); + setTimespan(date); + } else if (property == QLatin1String("rating")) { + const int stars = subTerm.value().toInt() / 2; + setRating(stars); + } + } } #endif - -QCheckBox* DolphinFacetsWidget::createCheckBox(const QString& text) +void DolphinFacetsWidget::setFacetType(const QString& type) { - QCheckBox* checkBox = new QCheckBox(text); - connect(checkBox, &QCheckBox::clicked, this, &DolphinFacetsWidget::facetChanged); - return checkBox; + if (type == QLatin1String("Document")) { + m_documents->setChecked(true); + } else if (type == QLatin1String("Image")) { + m_images->setChecked(true); + } else if (type == QLatin1String("Audio")) { + m_audio->setChecked(true); + } else if (type == QLatin1String("Video")) { + m_videos->setChecked(true); + } else { + m_anyType->setChecked(true); + } +} + +void DolphinFacetsWidget::setRating(const int stars) +{ + switch (stars) { + case 5: + m_maxRating->setChecked(true); + break; + + case 4: + m_fourOrMore->setChecked(true); + break; + + case 3: + m_threeOrMore->setChecked(true); + break; + + case 2: + m_twoOrMore->setChecked(true); + break; + + case 1: + m_oneOrMore->setChecked(true); + break; + + default: + m_anyRating->setChecked(true); + } +} + +void DolphinFacetsWidget::setTimespan(const QDate& date) +{ + const QDate currentDate = QDate::currentDate(); + const int days = date.daysTo(currentDate); + + if (days <= 0) { + m_today->setChecked(true); + } else if (days <= 1) { + m_yesterday->setChecked(true); + } else if (days <= currentDate.dayOfWeek()) { + m_thisWeek->setChecked(true); + } else if (days <= currentDate.day()) { + m_thisMonth->setChecked(true); + } else if (days <= currentDate.dayOfYear()) { + m_thisYear->setChecked(true); + } else { + m_anytime->setChecked(true); + } } QRadioButton* DolphinFacetsWidget::createRadioButton(const QString& text, diff --git a/src/search/dolphinfacetswidget.h b/src/search/dolphinfacetswidget.h index 526fe1c79..757dcd482 100644 --- a/src/search/dolphinfacetswidget.h +++ b/src/search/dolphinfacetswidget.h @@ -29,6 +29,7 @@ class QButtonGroup; class QCheckBox; +class QDate; class QRadioButton; /** @@ -57,19 +58,20 @@ public: #ifdef HAVE_BALOO Baloo::Term ratingTerm() const; - QStringList facetTypes() const; + QString facetType() const; + + bool isRatingTerm(const Baloo::Term& term) const; + void setRatingTerm(const Baloo::Term& term); #endif + void setFacetType(const QString& type); + signals: void facetChanged(); private: - /** - * @return New checkbox which is connected to the - * slotFacedChanged() slot whenever it has - * been toggled. - */ - QCheckBox* createCheckBox(const QString& text); + void setRating(const int stars); + void setTimespan(const QDate& date); /** * @return New radiobutton which is connected to the @@ -80,10 +82,11 @@ private: QButtonGroup* group); private: - QCheckBox* m_documents; - QCheckBox* m_images; - QCheckBox* m_audio; - QCheckBox* m_videos; + QRadioButton* m_anyType; + QRadioButton* m_documents; + QRadioButton* m_images; + QRadioButton* m_audio; + QRadioButton* m_videos; QRadioButton* m_anytime; QRadioButton* m_today; diff --git a/src/search/dolphinsearchbox.cpp b/src/search/dolphinsearchbox.cpp index d47996a78..f9942f98e 100644 --- a/src/search/dolphinsearchbox.cpp +++ b/src/search/dolphinsearchbox.cpp @@ -50,7 +50,6 @@ DolphinSearchBox::DolphinSearchBox(QWidget* parent) : QWidget(parent), m_startedSearching(false), - m_readOnly(false), m_active(true), m_topLayout(0), m_searchLabel(0), @@ -64,7 +63,6 @@ DolphinSearchBox::DolphinSearchBox(QWidget* parent) : m_facetsToggleButton(0), m_facetsWidget(0), m_searchPath(), - m_readOnlyQuery(), m_startSearchTimer(0) { } @@ -103,7 +101,7 @@ void DolphinSearchBox::setSearchPath(const KUrl& url) const QString elidedLocation = metrics.elidedText(location, Qt::ElideMiddle, maxWidth); m_fromHereButton->setText(i18nc("action:button", "From Here (%1)", elidedLocation)); - const bool showSearchFromButtons = url.isLocalFile() && !m_readOnly; + const bool showSearchFromButtons = url.isLocalFile(); m_separator->setVisible(showSearchFromButtons); m_fromHereButton->setVisible(showSearchFromButtons); m_everywhereButton->setVisible(showSearchFromButtons); @@ -153,23 +151,24 @@ KUrl DolphinSearchBox::urlForSearching() const return url; } -void DolphinSearchBox::selectAll() +void DolphinSearchBox::fromSearchUrl(const KUrl& url) { - m_searchInput->selectAll(); -} - -void DolphinSearchBox::setReadOnly(bool readOnly, const KUrl& query) -{ - if (m_readOnly != readOnly || m_readOnlyQuery != query) { - m_readOnly = readOnly; - m_readOnlyQuery = query; - applyReadOnlyState(); + if (url.protocol() == "baloosearch") { + fromBalooSearchUrl(url); + } else if (url.protocol() == "filenamesearch") { + const QMap& queryItems = url.queryItems(); + setText(queryItems.value("search")); + setSearchPath(queryItems.value("url")); + m_contentButton->setChecked(queryItems.value("checkContent") == "yes"); + } else { + setText(QString()); + setSearchPath(url); } } -bool DolphinSearchBox::isReadOnly() const +void DolphinSearchBox::selectAll() { - return m_readOnly; + m_searchInput->selectAll(); } void DolphinSearchBox::setActive(bool active) @@ -427,7 +426,6 @@ void DolphinSearchBox::init() connect(m_startSearchTimer, &QTimer::timeout, this, &DolphinSearchBox::emitSearchRequest); updateFacetsToggleButton(); - applyReadOnlyState(); } KUrl DolphinSearchBox::balooUrlForSearching() const @@ -437,7 +435,7 @@ KUrl DolphinSearchBox::balooUrlForSearching() const Baloo::Query query; query.addType("File"); - query.addTypes(m_facetsWidget->facetTypes()); + query.addType(m_facetsWidget->facetType()); Baloo::Term term(Baloo::Term::And); @@ -448,14 +446,16 @@ KUrl DolphinSearchBox::balooUrlForSearching() const if (m_contentButton->isChecked()) { query.setSearchString(text); - } else { - term.addSubTerm(Baloo::Term("filename", text)); + } else if (!text.isEmpty()) { + term.addSubTerm(Baloo::Term(QLatin1String("filename"), text)); } if (m_fromHereButton->isChecked()) { query.addCustomOption("includeFolder", m_searchPath.toLocalFile()); } + query.setTerm(term); + return query.toSearchUrl(i18nc("@title UDS_DISPLAY_NAME for a KIO directory listing. %1 is the query the user entered.", "Query Results from '%1'", text)); #else @@ -463,26 +463,46 @@ KUrl DolphinSearchBox::balooUrlForSearching() const #endif } -void DolphinSearchBox::applyReadOnlyState() +void DolphinSearchBox::fromBalooSearchUrl(const KUrl& url) { #ifdef HAVE_BALOO - if (m_readOnly) { - m_searchLabel->setText(Baloo::Query::titleFromQueryUrl(m_readOnlyQuery)); + const Baloo::Query query = Baloo::Query::fromSearchUrl(url); + const Baloo::Term term = query.term(); + + // Block all signals to avoid unnecessary "searchRequest" signals + // while we adjust the search text and the facet widget. + blockSignals(true); + + const QVariantHash customOptions = query.customOptions(); + if (customOptions.contains("includeFolder")) { + setSearchPath(customOptions.value("includeFolder").toString()); } else { -#else - { + setSearchPath(QDir::homePath()); + } + + if (!query.searchString().isEmpty()) { + setText(query.searchString()); + } + + QStringList types = query.types(); + types.removeOne("File"); // We are only interested in facet widget types + if (!types.isEmpty()) { + m_facetsWidget->setFacetType(types.first()); + } + + foreach (const Baloo::Term& subTerm, term.subTerms()) { + const QString property = subTerm.property(); + + if (property == QLatin1String("filename")) { + setText(subTerm.value().toString()); + } else if (m_facetsWidget->isRatingTerm(subTerm)) { + m_facetsWidget->setRatingTerm(subTerm); + } + } + + m_startSearchTimer->stop(); + blockSignals(false); #endif - m_searchLabel->setText(i18nc("@label:textbox", "Find:")); - } - - m_searchInput->setVisible(!m_readOnly); - m_optionsScrollArea->setVisible(!m_readOnly); - - if (m_readOnly) { - m_facetsWidget->hide(); - } else { - m_facetsWidget->setVisible(SearchSettings::showFacetsWidget()); - } } void DolphinSearchBox::updateFacetsToggleButton() diff --git a/src/search/dolphinsearchbox.h b/src/search/dolphinsearchbox.h index 6dc09f19e..53b12ffab 100644 --- a/src/search/dolphinsearchbox.h +++ b/src/search/dolphinsearchbox.h @@ -71,22 +71,17 @@ public: /** @return URL that will start the searching of files. */ KUrl urlForSearching() const; + /** + * Extracts information from the given search \a url to + * initialize the search box properly. + */ + void fromSearchUrl(const KUrl& url); + /** * Selects the whole text of the search box. */ void selectAll(); - /** - * @param readOnly If set to true the searchbox cannot be modified - * by the user and acts as visual indicator for - * an externally triggered search query. - * @param query If readOnly is true this URL will be used - * to show a human readable information about the - * query. - */ - void setReadOnly(bool readOnly, const KUrl& query = KUrl()); - bool isReadOnly() const; - /** * Set the search box to the active mode, if \a active * is true. The active mode is default. The inactive mode only differs @@ -155,12 +150,15 @@ private: */ KUrl balooUrlForSearching() const; - void applyReadOnlyState(); + /** + * Extracts information from the given Baloo search \a url to + * initialize the search box properly. + */ + void fromBalooSearchUrl(const KUrl& url); void updateFacetsToggleButton(); private: bool m_startedSearching; - bool m_readOnly; bool m_active; QVBoxLayout* m_topLayout; @@ -177,7 +175,6 @@ private: DolphinFacetsWidget* m_facetsWidget; KUrl m_searchPath; - KUrl m_readOnlyQuery; QTimer* m_startSearchTimer; }; diff --git a/src/search/filenamesearchprotocol.cpp b/src/search/filenamesearchprotocol.cpp index fd56f68b7..3333dcc07 100644 --- a/src/search/filenamesearchprotocol.cpp +++ b/src/search/filenamesearchprotocol.cpp @@ -92,8 +92,11 @@ void FileNameSearchProtocol::searchDirectory(const KUrl& directory) bool addItem = false; if (!m_regExp || item.name().contains(*m_regExp)) { addItem = true; - } else if (m_checkContent && item.mimetype().startsWith(QLatin1String("text/"))) { + } else if (m_checkContent && item.determineMimeType().inherits(QLatin1String("text/plain"))) { + qDebug() << "### Checking" << item; addItem = contentContainsPattern(item.url()); + } else { + qDebug() << "### NOT Checking" << item; } if (addItem) { diff --git a/src/settings/kcm/kcmdolphingeneral.desktop b/src/settings/kcm/kcmdolphingeneral.desktop index 5a79ad619..b0620ac74 100644 --- a/src/settings/kcm/kcmdolphingeneral.desktop +++ b/src/settings/kcm/kcmdolphingeneral.desktop @@ -314,6 +314,7 @@ X-KDE-Keywords[gl]=xestor de ficheiros X-KDE-Keywords[he]=מנהל קבצים X-KDE-Keywords[hu]=fájlkezelő X-KDE-Keywords[ia]=gerente de file +X-KDE-Keywords[is]=skráastjóri X-KDE-Keywords[it]=gestore dei file X-KDE-Keywords[kk]=file manager X-KDE-Keywords[km]=កម្មវិធី​គ្រប់គ្រង​ឯកសារ diff --git a/src/settings/kcm/kcmdolphinnavigation.desktop b/src/settings/kcm/kcmdolphinnavigation.desktop index 4cf793a35..8636058cd 100644 --- a/src/settings/kcm/kcmdolphinnavigation.desktop +++ b/src/settings/kcm/kcmdolphinnavigation.desktop @@ -314,6 +314,7 @@ X-KDE-Keywords[gl]=xestor de ficheiros X-KDE-Keywords[he]=מנהל קבצים X-KDE-Keywords[hu]=fájlkezelő X-KDE-Keywords[ia]=gerente de file +X-KDE-Keywords[is]=skráastjóri X-KDE-Keywords[it]=gestore dei file X-KDE-Keywords[kk]=file manager X-KDE-Keywords[km]=កម្មវិធី​គ្រប់គ្រង​ឯកសារ diff --git a/src/settings/kcm/kcmdolphinservices.desktop b/src/settings/kcm/kcmdolphinservices.desktop index aa93e6d28..34867305a 100644 --- a/src/settings/kcm/kcmdolphinservices.desktop +++ b/src/settings/kcm/kcmdolphinservices.desktop @@ -263,6 +263,7 @@ X-KDE-Keywords[gl]=xestor de ficheiros X-KDE-Keywords[he]=מנהל קבצים X-KDE-Keywords[hu]=fájlkezelő X-KDE-Keywords[ia]=gerente de file +X-KDE-Keywords[is]=skráastjóri X-KDE-Keywords[it]=gestore dei file X-KDE-Keywords[kk]=file manager X-KDE-Keywords[km]=កម្មវិធី​គ្រប់គ្រង​ឯកសារ diff --git a/src/settings/kcm/kcmdolphinviewmodes.desktop b/src/settings/kcm/kcmdolphinviewmodes.desktop index ce8401228..a4b4e058b 100644 --- a/src/settings/kcm/kcmdolphinviewmodes.desktop +++ b/src/settings/kcm/kcmdolphinviewmodes.desktop @@ -312,6 +312,7 @@ X-KDE-Keywords[gl]=xestor de ficheiros X-KDE-Keywords[he]=מנהל קבצים X-KDE-Keywords[hu]=fájlkezelő X-KDE-Keywords[ia]=gerente de file +X-KDE-Keywords[is]=skráastjóri X-KDE-Keywords[it]=gestore dei file X-KDE-Keywords[kk]=file manager X-KDE-Keywords[km]=កម្មវិធី​គ្រប់គ្រង​ឯកសារ diff --git a/src/statusbar/dolphinstatusbar.cpp b/src/statusbar/dolphinstatusbar.cpp index 79355fb55..9f17c8ecd 100644 --- a/src/statusbar/dolphinstatusbar.cpp +++ b/src/statusbar/dolphinstatusbar.cpp @@ -73,6 +73,7 @@ DolphinStatusBar::DolphinStatusBar(QWidget* parent) : m_zoomSlider->setRange(ZoomLevelInfo::minimumLevel(), ZoomLevelInfo::maximumLevel()); connect(m_zoomSlider, &QSlider::valueChanged, this, &DolphinStatusBar::zoomLevelChanged); + connect(m_zoomSlider, &QSlider::valueChanged, this, &DolphinStatusBar::updateZoomSliderToolTip); connect(m_zoomSlider, &QSlider::sliderMoved, this, &DolphinStatusBar::showZoomSliderToolTip); // Initialize space information @@ -240,7 +241,6 @@ void DolphinStatusBar::setZoomLevel(int zoomLevel) { if (zoomLevel != m_zoomSlider->value()) { m_zoomSlider->setValue(zoomLevel); - updateZoomSliderToolTip(zoomLevel); } } @@ -338,6 +338,12 @@ void DolphinStatusBar::slotResetToDefaultText() updateLabelText(); } +void DolphinStatusBar::updateZoomSliderToolTip(int zoomLevel) +{ + const int size = ZoomLevelInfo::iconSizeForZoomLevel(zoomLevel); + m_zoomSlider->setToolTip(i18ncp("@info:tooltip", "Size: 1 pixel", "Size: %1 pixels", size)); +} + void DolphinStatusBar::setExtensionsVisible(bool visible) { bool showSpaceInfo = visible; @@ -350,10 +356,4 @@ void DolphinStatusBar::setExtensionsVisible(bool visible) m_zoomSlider->setVisible(showZoomSlider); } -void DolphinStatusBar::updateZoomSliderToolTip(int zoomLevel) -{ - const int size = ZoomLevelInfo::iconSizeForZoomLevel(zoomLevel); - m_zoomSlider->setToolTip(i18ncp("@info:tooltip", "Size: 1 pixel", "Size: %1 pixels", size)); -} - #include "dolphinstatusbar.moc" diff --git a/src/statusbar/dolphinstatusbar.h b/src/statusbar/dolphinstatusbar.h index b2afe2eb9..4d6dbb20f 100644 --- a/src/statusbar/dolphinstatusbar.h +++ b/src/statusbar/dolphinstatusbar.h @@ -122,6 +122,12 @@ private slots: */ void slotResetToDefaultText(); + /** + * Updates the text of the zoom slider tooltip to show + * the currently used size. + */ + void updateZoomSliderToolTip(int zoomLevel); + private: /** * Makes the space information widget and zoom slider widget @@ -131,12 +137,6 @@ private: */ void setExtensionsVisible(bool visible); - /** - * Updates the text of the zoom slider tooltip to show - * the currently used size. - */ - void updateZoomSliderToolTip(int zoomLevel); - private: QString m_text; QString m_defaultText; diff --git a/src/tests/kitemlistselectionmanagertest.cpp b/src/tests/kitemlistselectionmanagertest.cpp index af2610d8c..492d0234f 100644 --- a/src/tests/kitemlistselectionmanagertest.cpp +++ b/src/tests/kitemlistselectionmanagertest.cpp @@ -78,6 +78,7 @@ private slots: void testChangeSelection(); void testDeleteCurrentItem_data(); void testDeleteCurrentItem(); + void testAnchoredSelectionAfterMovingItems(); private: void verifySelectionChange(QSignalSpy& spy, const KItemSet& currentSelection, const KItemSet& previousSelection) const; @@ -413,6 +414,15 @@ void KItemListSelectionManagerTest::testChangeSelection_data() << QVariant::fromValue(QList() << 4 << 5 << 2 << 3)) << (KItemSet() << 0 << 1 << 4 << 5); + QTest::newRow("Move items with active anchored selection") + << KItemSet() + << 0 << 3 + << (KItemSet() << 0 << 1 << 2 << 3) + << MoveItems + << (QList() << QVariant::fromValue(KItemRange(2, 4)) + << QVariant::fromValue(QList() << 4 << 5 << 2 << 3)) + << (KItemSet() << 0 << 1 << 4 << 5); + // Revert sort order QTest::newRow("Revert sort order") << (KItemSet() << 0 << 1) @@ -519,6 +529,22 @@ void KItemListSelectionManagerTest::testDeleteCurrentItem() QCOMPARE(m_selectionManager->currentItem(), newCurrentItemIndex); } +void KItemListSelectionManagerTest::testAnchoredSelectionAfterMovingItems() +{ + m_selectionManager->setCurrentItem(4); + m_selectionManager->beginAnchoredSelection(4); + + // Reverse the items between 0 and 5. + m_selectionManager->itemsMoved(KItemRange(0, 6), QList() << 5 << 4 << 3 << 2 << 1 << 0); + + QCOMPARE(m_selectionManager->currentItem(), 1); + QCOMPARE(m_selectionManager->m_anchorItem, 1); + + // Make 2 the current item -> 1 and 2 should be selected. + m_selectionManager->setCurrentItem(2); + QCOMPARE(m_selectionManager->selectedItems(), KItemSet() << 1 << 2); +} + void KItemListSelectionManagerTest::verifySelectionChange(QSignalSpy& spy, const KItemSet& currentSelection, const KItemSet& previousSelection) const diff --git a/src/views/dolphinitemlistview.cpp b/src/views/dolphinitemlistview.cpp index 26148f61f..9f600e43f 100644 --- a/src/views/dolphinitemlistview.cpp +++ b/src/views/dolphinitemlistview.cpp @@ -145,6 +145,26 @@ void DolphinItemListView::onVisibleRolesChanged(const QList& current updateGridSize(); } +void DolphinItemListView::updateFont() +{ + const ViewModeSettings settings(viewMode()); + + if (settings.useSystemFont()) { + KItemListView::updateFont(); + } else { + QFont font(settings.fontFamily(), qRound(settings.fontSize())); + font.setItalic(settings.italicFont()); + font.setWeight(settings.fontWeight()); + font.setPointSizeF(settings.fontSize()); + + KItemListStyleOption option = styleOption(); + option.font = font; + option.fontMetrics = QFontMetrics(font); + + setStyleOption(option); + } +} + void DolphinItemListView::updateGridSize() { const ViewModeSettings settings(viewMode()); @@ -161,7 +181,8 @@ void DolphinItemListView::updateGridSize() // Calculate the item-width and item-height int itemWidth; int itemHeight; - QSize maxTextSize; + int maxTextLines = 0; + int maxTextWidth = 0; switch (itemLayout()) { case KFileItemListView::IconsLayout: { @@ -181,16 +202,10 @@ void DolphinItemListView::updateGridSize() } itemHeight = padding * 3 + iconSize + option.fontMetrics.lineSpacing(); - if (IconsModeSettings::maximumTextLines() > 0) { - // A restriction is given for the maximum number of textlines (0 means - // having no restriction) - const int additionalInfoCount = visibleRoles().count() - 1; - const int maxAdditionalLines = additionalInfoCount + IconsModeSettings::maximumTextLines(); - maxTextSize.rheight() = option.fontMetrics.lineSpacing() * maxAdditionalLines; - } horizontalMargin = 4; verticalMargin = 8; + maxTextLines = IconsModeSettings::maximumTextLines(); break; } case KFileItemListView::CompactLayout: { @@ -201,8 +216,7 @@ void DolphinItemListView::updateGridSize() if (CompactModeSettings::maximumTextWidthIndex() > 0) { // A restriction is given for the maximum width of the text (0 means // having no restriction) - maxTextSize.rwidth() = option.fontMetrics.height() * 10 * - CompactModeSettings::maximumTextWidthIndex(); + maxTextWidth = option.fontMetrics.height() * 10 * CompactModeSettings::maximumTextWidthIndex(); } horizontalMargin = 8; @@ -225,30 +239,14 @@ void DolphinItemListView::updateGridSize() option.horizontalMargin = horizontalMargin; option.verticalMargin = verticalMargin; option.iconSize = iconSize; - option.maxTextSize = maxTextSize; + option.maxTextLines = maxTextLines; + option.maxTextWidth = maxTextWidth; beginTransaction(); setStyleOption(option); setItemSize(QSizeF(itemWidth, itemHeight)); endTransaction(); } -void DolphinItemListView::updateFont() -{ - KItemListStyleOption option = styleOption(); - - const ViewModeSettings settings(viewMode()); - - QFont font(settings.fontFamily(), qRound(settings.fontSize())); - font.setItalic(settings.italicFont()); - font.setWeight(settings.fontWeight()); - font.setPointSizeF(settings.fontSize()); - - option.font = font; - option.fontMetrics = QFontMetrics(font); - - setStyleOption(option); -} - ViewModeSettings::ViewMode DolphinItemListView::viewMode() const { ViewModeSettings::ViewMode mode; diff --git a/src/views/dolphinitemlistview.h b/src/views/dolphinitemlistview.h index 18bb284ac..67302e44d 100644 --- a/src/views/dolphinitemlistview.h +++ b/src/views/dolphinitemlistview.h @@ -56,9 +56,10 @@ protected: virtual void onVisibleRolesChanged(const QList& current, const QList& previous); + virtual void updateFont(); + private: void updateGridSize(); - void updateFont(); ViewModeSettings::ViewMode viewMode() const; diff --git a/src/views/dolphinview.cpp b/src/views/dolphinview.cpp index 247b10bc8..0e43dcda1 100644 --- a/src/views/dolphinview.cpp +++ b/src/views/dolphinview.cpp @@ -1050,6 +1050,7 @@ void DolphinView::slotItemDropEvent(int index, QGraphicsSceneDragDropEvent* even if (op && destUrl == url()) { // Mark the dropped urls as selected. m_clearSelectionBeforeSelectingNewItems = true; + m_markFirstNewlySelectedItemAsCurrent = true; connect(op, static_cast(&KonqOperations::aboutToCreate), this, &DolphinView::slotAboutToCreate); } @@ -1075,17 +1076,15 @@ void DolphinView::slotModelChanged(KItemModelBase* current, KItemModelBase* prev void DolphinView::slotMouseButtonPressed(int itemIndex, Qt::MouseButtons buttons) { + Q_UNUSED(itemIndex); + hideToolTip(); - if (itemIndex < 0) { - // Trigger the history navigation only when clicking on the viewport: - // Above an item the XButtons provide a simple way to select items in - // the singleClick mode. - if (buttons & Qt::XButton1) { - emit goBackRequested(); - } else if (buttons & Qt::XButton2) { - emit goForwardRequested(); - } + // TODO: Qt5: Replace Qt::XButton1 by Qt::BackButton and Qt::XButton2 by Qt::ForwardButton + if (buttons & Qt::XButton1) { + emit goBackRequested(); + } else if (buttons & Qt::XButton2) { + emit goForwardRequested(); } } @@ -1359,16 +1358,6 @@ void DolphinView::calculateItemCount(int& fileCount, } } -void DolphinView::showHoverInformation(const KFileItem& item) -{ - emit requestItemInfo(item); -} - -void DolphinView::clearHoverInformation() -{ - emit requestItemInfo(KFileItem()); -} - void DolphinView::slotDeleteFileFinished(KJob* job) { if (job->error() == 0) { diff --git a/src/views/dolphinview.h b/src/views/dolphinview.h index 0da9fa549..4ba10293a 100644 --- a/src/views/dolphinview.h +++ b/src/views/dolphinview.h @@ -614,20 +614,6 @@ private slots: */ void updateSortFoldersFirst(bool foldersFirst); - /** - * Updates the status bar to show hover information for the - * item \a item. If currently other items are selected, - * no hover information is shown. - * @see DolphinView::clearHoverInformation() - */ - void showHoverInformation(const KFileItem& item); - - /** - * Clears the hover information shown in the status bar. - * @see DolphinView::showHoverInformation(). - */ - void clearHoverInformation(); - /** * Indicates in the status bar that the delete operation * of the job \a job has been finished. diff --git a/src/views/renamedialog.cpp b/src/views/renamedialog.cpp index 67f90a5da..3b94e01e5 100644 --- a/src/views/renamedialog.cpp +++ b/src/views/renamedialog.cpp @@ -31,15 +31,6 @@ #include #include -/** - * Helper function for sorting items with qSort() in - * DolphinView::renameSelectedItems(). - */ -bool lessThan(const KFileItem& item1, const KFileItem& item2) -{ - return KStringHandler::naturalCompare(item1.name(), item2.name()) < 0; -} - RenameDialog::RenameDialog(QWidget *parent, const KFileItemList& items) : KDialog(parent), m_renameOneItem(false), diff --git a/src/views/versioncontrol/updateitemstatesthread.cpp b/src/views/versioncontrol/updateitemstatesthread.cpp index 8472d7dd7..51a277831 100644 --- a/src/views/versioncontrol/updateitemstatesthread.cpp +++ b/src/views/versioncontrol/updateitemstatesthread.cpp @@ -65,9 +65,9 @@ void UpdateItemStatesThread::run() items[i].version = static_cast(state); } } - - m_plugin->endRetrieval(); } + + m_plugin->endRetrieval(); } } diff --git a/src/views/versioncontrol/versioncontrolobserver.cpp b/src/views/versioncontrol/versioncontrolobserver.cpp index 2c966e186..9033e19da 100644 --- a/src/views/versioncontrol/versioncontrolobserver.cpp +++ b/src/views/versioncontrol/versioncontrolobserver.cpp @@ -317,11 +317,18 @@ KVersionControlPlugin* VersionControlObserver::searchPlugin(const KUrl& director } } + // We use the number of upUrl() calls to find the best matching plugin + // for the given directory. The smaller value, the better it is (0 is best). + KVersionControlPlugin* bestPlugin = 0; + int bestScore = INT_MAX; + // Verify whether the current directory contains revision information // like .svn, .git, ... foreach (KVersionControlPlugin* plugin, plugins) { const QString fileName = directory.path(KUrl::AddTrailingSlash) + plugin->fileName(); if (QFile::exists(fileName)) { + // The score of this plugin is 0 (best), so we can just return this plugin, + // instead of going through the plugin scoring procedure, we can't find a better one ;) return plugin; } @@ -334,18 +341,24 @@ KVersionControlPlugin* VersionControlObserver::searchPlugin(const KUrl& director if (m_versionedDirectory) { KUrl dirUrl(directory); KUrl upUrl = dirUrl.upUrl(); - while (upUrl != dirUrl) { + int upUrlCounter = 1; + while ((upUrlCounter < bestScore) && (upUrl != dirUrl)) { const QString fileName = dirUrl.path(KUrl::AddTrailingSlash) + plugin->fileName(); if (QFile::exists(fileName)) { - return plugin; + if (upUrlCounter < bestScore) { + bestPlugin = plugin; + bestScore = upUrlCounter; + } + break; } dirUrl = upUrl; upUrl = dirUrl.upUrl(); + ++upUrlCounter; } } } - return 0; + return bestPlugin; } bool VersionControlObserver::isVersioned() const