From 6c3d9acbc22ea9463ba40ef84c9e8c8419dfacf3 Mon Sep 17 00:00:00 2001 From: Peter Penz Date: Wed, 11 Apr 2012 16:06:18 +0200 Subject: KItemViews: Internal directory restructuration - Move all private headers from the kitemviews-directory into the 'private' subdirectory. - Get rid of DolphinDirLister and just use a directory-lister internally in KFileItemModel. - Minor interface-cleanups for signals --- src/CMakeLists.txt | 28 +- src/dolphinmainwindow.cpp | 4 +- src/dolphinpart.cpp | 6 +- src/dolphinviewcontainer.cpp | 47 +- src/dolphinviewcontainer.h | 15 +- src/kitemviews/kfileitemclipboard.cpp | 76 --- src/kitemviews/kfileitemclipboard_p.h | 62 -- src/kitemviews/kfileitemlistview.cpp | 2 +- src/kitemviews/kfileitemlistwidget.cpp | 31 +- src/kitemviews/kfileitemmodel.cpp | 127 ++--- src/kitemviews/kfileitemmodel.h | 82 ++- src/kitemviews/kfileitemmodelfilter.cpp | 71 --- src/kitemviews/kfileitemmodelfilter_p.h | 70 --- src/kitemviews/kfileitemmodelrolesupdater.cpp | 18 +- src/kitemviews/kfileitemmodelrolesupdater.h | 2 +- src/kitemviews/kfileitemmodelsortalgorithm.cpp | 148 ----- src/kitemviews/kfileitemmodelsortalgorithm_p.h | 70 --- src/kitemviews/kitemlistcontainer.cpp | 3 +- src/kitemviews/kitemlistcontroller.cpp | 11 +- src/kitemviews/kitemlistheader.cpp | 3 +- src/kitemviews/kitemlistheaderwidget.cpp | 535 ----------------- src/kitemviews/kitemlistheaderwidget_p.h | 171 ------ src/kitemviews/kitemlistkeyboardsearchmanager.cpp | 78 --- src/kitemviews/kitemlistkeyboardsearchmanager_p.h | 81 --- src/kitemviews/kitemlistrubberband.cpp | 75 --- src/kitemviews/kitemlistrubberband_p.h | 60 -- src/kitemviews/kitemlistselectiontoggle.cpp | 106 ---- src/kitemviews/kitemlistselectiontoggle_p.h | 61 -- src/kitemviews/kitemlistsizehintresolver.cpp | 88 --- src/kitemviews/kitemlistsizehintresolver_p.h | 53 -- src/kitemviews/kitemlistsmoothscroller.cpp | 207 ------- src/kitemviews/kitemlistsmoothscroller_p.h | 103 ---- src/kitemviews/kitemlistview.cpp | 11 +- src/kitemviews/kitemlistview.h | 2 +- src/kitemviews/kitemlistviewanimation.cpp | 245 -------- src/kitemviews/kitemlistviewanimation_p.h | 106 ---- src/kitemviews/kitemlistviewlayouter.cpp | 630 --------------------- src/kitemviews/kitemlistviewlayouter_p.h | 235 -------- src/kitemviews/kitemlistwidget.cpp | 3 +- src/kitemviews/knepomukdatamanagement_export_p.h | 40 -- src/kitemviews/knepomukresourcewatcher_p.h | 288 ---------- src/kitemviews/knepomukrolesprovider.cpp | 181 ------ src/kitemviews/knepomukrolesprovider_p.h | 82 --- src/kitemviews/kpixmapmodifier.cpp | 400 ------------- src/kitemviews/kpixmapmodifier_p.h | 38 -- src/kitemviews/private/kfileitemclipboard.cpp | 76 +++ src/kitemviews/private/kfileitemclipboard.h | 62 ++ src/kitemviews/private/kfileitemmodeldirlister.cpp | 44 ++ src/kitemviews/private/kfileitemmodeldirlister.h | 47 ++ src/kitemviews/private/kfileitemmodelfilter.cpp | 71 +++ src/kitemviews/private/kfileitemmodelfilter.h | 70 +++ .../private/kfileitemmodelsortalgorithm.cpp | 148 +++++ .../private/kfileitemmodelsortalgorithm.h | 70 +++ src/kitemviews/private/kitemlistheaderwidget.cpp | 535 +++++++++++++++++ src/kitemviews/private/kitemlistheaderwidget.h | 171 ++++++ .../private/kitemlistkeyboardsearchmanager.cpp | 78 +++ src/kitemviews/private/kitemlistrubberband.cpp | 75 +++ .../private/kitemlistselectiontoggle.cpp | 106 ++++ src/kitemviews/private/kitemlistselectiontoggle.h | 61 ++ .../private/kitemlistsizehintresolver.cpp | 88 +++ src/kitemviews/private/kitemlistsizehintresolver.h | 53 ++ src/kitemviews/private/kitemlistsmoothscroller.cpp | 207 +++++++ src/kitemviews/private/kitemlistsmoothscroller.h | 103 ++++ src/kitemviews/private/kitemlistviewanimation.cpp | 245 ++++++++ src/kitemviews/private/kitemlistviewanimation.h | 106 ++++ src/kitemviews/private/kitemlistviewlayouter.cpp | 630 +++++++++++++++++++++ src/kitemviews/private/kitemlistviewlayouter.h | 235 ++++++++ .../private/knepomukdatamanagement_export.h | 40 ++ src/kitemviews/private/knepomukresourcewatcher.h | 288 ++++++++++ src/kitemviews/private/knepomukrolesprovider.cpp | 181 ++++++ src/kitemviews/private/knepomukrolesprovider.h | 82 +++ src/kitemviews/private/kpixmapmodifier.cpp | 400 +++++++++++++ src/kitemviews/private/kpixmapmodifier.h | 38 ++ src/panels/folders/folderspanel.cpp | 28 +- src/panels/folders/folderspanel.h | 2 - src/tests/CMakeLists.txt | 2 +- src/tests/kfileitemmodeltest.cpp | 76 ++- src/tests/kitemlistcontrollertest.cpp | 14 +- src/tests/kitemlistkeyboardsearchmanagertest.cpp | 2 +- src/views/dolphindirlister.cpp | 48 -- src/views/dolphindirlister.h | 49 -- src/views/dolphinitemlistcontainer.cpp | 6 +- src/views/dolphinitemlistcontainer.h | 4 +- src/views/dolphinview.cpp | 105 ++-- src/views/dolphinview.h | 46 +- .../versioncontrol/versioncontrolobserver.cpp | 3 +- 86 files changed, 4672 insertions(+), 4778 deletions(-) delete mode 100644 src/kitemviews/kfileitemclipboard.cpp delete mode 100644 src/kitemviews/kfileitemclipboard_p.h delete mode 100644 src/kitemviews/kfileitemmodelfilter.cpp delete mode 100644 src/kitemviews/kfileitemmodelfilter_p.h delete mode 100644 src/kitemviews/kfileitemmodelsortalgorithm.cpp delete mode 100644 src/kitemviews/kfileitemmodelsortalgorithm_p.h delete mode 100644 src/kitemviews/kitemlistheaderwidget.cpp delete mode 100644 src/kitemviews/kitemlistheaderwidget_p.h delete mode 100644 src/kitemviews/kitemlistkeyboardsearchmanager.cpp delete mode 100644 src/kitemviews/kitemlistkeyboardsearchmanager_p.h delete mode 100644 src/kitemviews/kitemlistrubberband.cpp delete mode 100644 src/kitemviews/kitemlistrubberband_p.h delete mode 100644 src/kitemviews/kitemlistselectiontoggle.cpp delete mode 100644 src/kitemviews/kitemlistselectiontoggle_p.h delete mode 100644 src/kitemviews/kitemlistsizehintresolver.cpp delete mode 100644 src/kitemviews/kitemlistsizehintresolver_p.h delete mode 100644 src/kitemviews/kitemlistsmoothscroller.cpp delete mode 100644 src/kitemviews/kitemlistsmoothscroller_p.h delete mode 100644 src/kitemviews/kitemlistviewanimation.cpp delete mode 100644 src/kitemviews/kitemlistviewanimation_p.h delete mode 100644 src/kitemviews/kitemlistviewlayouter.cpp delete mode 100644 src/kitemviews/kitemlistviewlayouter_p.h delete mode 100644 src/kitemviews/knepomukdatamanagement_export_p.h delete mode 100644 src/kitemviews/knepomukresourcewatcher_p.h delete mode 100644 src/kitemviews/knepomukrolesprovider.cpp delete mode 100644 src/kitemviews/knepomukrolesprovider_p.h delete mode 100644 src/kitemviews/kpixmapmodifier.cpp delete mode 100644 src/kitemviews/kpixmapmodifier_p.h create mode 100644 src/kitemviews/private/kfileitemclipboard.cpp create mode 100644 src/kitemviews/private/kfileitemclipboard.h create mode 100644 src/kitemviews/private/kfileitemmodeldirlister.cpp create mode 100644 src/kitemviews/private/kfileitemmodeldirlister.h create mode 100644 src/kitemviews/private/kfileitemmodelfilter.cpp create mode 100644 src/kitemviews/private/kfileitemmodelfilter.h create mode 100644 src/kitemviews/private/kfileitemmodelsortalgorithm.cpp create mode 100644 src/kitemviews/private/kfileitemmodelsortalgorithm.h create mode 100644 src/kitemviews/private/kitemlistheaderwidget.cpp create mode 100644 src/kitemviews/private/kitemlistheaderwidget.h create mode 100644 src/kitemviews/private/kitemlistkeyboardsearchmanager.cpp create mode 100644 src/kitemviews/private/kitemlistrubberband.cpp create mode 100644 src/kitemviews/private/kitemlistselectiontoggle.cpp create mode 100644 src/kitemviews/private/kitemlistselectiontoggle.h create mode 100644 src/kitemviews/private/kitemlistsizehintresolver.cpp create mode 100644 src/kitemviews/private/kitemlistsizehintresolver.h create mode 100644 src/kitemviews/private/kitemlistsmoothscroller.cpp create mode 100644 src/kitemviews/private/kitemlistsmoothscroller.h create mode 100644 src/kitemviews/private/kitemlistviewanimation.cpp create mode 100644 src/kitemviews/private/kitemlistviewanimation.h create mode 100644 src/kitemviews/private/kitemlistviewlayouter.cpp create mode 100644 src/kitemviews/private/kitemlistviewlayouter.h create mode 100644 src/kitemviews/private/knepomukdatamanagement_export.h create mode 100644 src/kitemviews/private/knepomukresourcewatcher.h create mode 100644 src/kitemviews/private/knepomukrolesprovider.cpp create mode 100644 src/kitemviews/private/knepomukrolesprovider.h create mode 100644 src/kitemviews/private/kpixmapmodifier.cpp create mode 100644 src/kitemviews/private/kpixmapmodifier.h delete mode 100644 src/views/dolphindirlister.cpp delete mode 100644 src/views/dolphindirlister.h (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6ac4464e8..e9079569a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -18,38 +18,38 @@ add_subdirectory(tests) ########### next target ############### set(dolphinprivate_LIB_SRCS - kitemviews/kfileitemclipboard.cpp kitemviews/kfileitemlistgroupheader.cpp kitemviews/kfileitemlistview.cpp kitemviews/kfileitemlistwidget.cpp kitemviews/kfileitemmodel.cpp - kitemviews/kfileitemmodelsortalgorithm.cpp - kitemviews/kfileitemmodelfilter.cpp kitemviews/kfileitemmodelrolesupdater.cpp kitemviews/kitemlistcontainer.cpp kitemviews/kitemlistcontroller.cpp kitemviews/kitemlistgroupheader.cpp kitemviews/kitemlistheader.cpp - kitemviews/kitemlistheaderwidget.cpp - kitemviews/kitemlistkeyboardsearchmanager.cpp - kitemviews/kitemlistrubberband.cpp kitemviews/kitemlistselectionmanager.cpp - kitemviews/kitemlistselectiontoggle.cpp - kitemviews/kitemlistsizehintresolver.cpp - kitemviews/kitemlistsmoothscroller.cpp kitemviews/kitemliststyleoption.cpp kitemviews/kitemlistview.cpp - kitemviews/kitemlistviewanimation.cpp - kitemviews/kitemlistviewlayouter.cpp kitemviews/kitemlistwidget.cpp kitemviews/kitemmodelbase.cpp - kitemviews/kpixmapmodifier.cpp + kitemviews/private/kfileitemclipboard.cpp + kitemviews/private/kfileitemmodeldirlister.cpp + kitemviews/private/kfileitemmodelsortalgorithm.cpp + kitemviews/private/kfileitemmodelfilter.cpp + kitemviews/private/kitemlistheaderwidget.cpp + kitemviews/private/kitemlistkeyboardsearchmanager.cpp + kitemviews/private/kitemlistrubberband.cpp + kitemviews/private/kitemlistselectiontoggle.cpp + kitemviews/private/kitemlistsizehintresolver.cpp + kitemviews/private/kitemlistsmoothscroller.cpp + kitemviews/private/kitemlistviewanimation.cpp + kitemviews/private/kitemlistviewlayouter.cpp + kitemviews/private/kpixmapmodifier.cpp settings/additionalinfodialog.cpp settings/applyviewpropsjob.cpp settings/viewmodes/viewmodesettings.cpp settings/viewpropertiesdialog.cpp settings/viewpropsprogressinfo.cpp - views/dolphindirlister.cpp views/dolphinfileitemlistwidget.cpp views/dolphinitemlistcontainer.cpp views/dolphinnewfilemenuobserver.cpp @@ -71,7 +71,7 @@ set(dolphinprivate_LIB_SRCS if (Nepomuk_FOUND) set(dolphinprivate_LIB_SRCS ${dolphinprivate_LIB_SRCS} - kitemviews/knepomukrolesprovider.cpp + kitemviews/private/knepomukrolesprovider.cpp ) endif (Nepomuk_FOUND) diff --git a/src/dolphinmainwindow.cpp b/src/dolphinmainwindow.cpp index 3aff015c5..22d8af3c3 100644 --- a/src/dolphinmainwindow.cpp +++ b/src/dolphinmainwindow.cpp @@ -2088,9 +2088,9 @@ void DolphinMainWindow::connectViewSignals(DolphinViewContainer* container) this, SLOT(openNewTab(KUrl))); connect(view, SIGNAL(requestContextMenu(QPoint,KFileItem,KUrl,QList)), this, SLOT(openContextMenu(QPoint,KFileItem,KUrl,QList))); - connect(view, SIGNAL(startedPathLoading(KUrl)), + connect(view, SIGNAL(startedDirLoading(KUrl)), this, SLOT(enableStopAction())); - connect(view, SIGNAL(finishedPathLoading(KUrl)), + connect(view, SIGNAL(finishedDirLoading(KUrl)), this, SLOT(disableStopAction())); connect(view, SIGNAL(goBackRequested()), this, SLOT(goBack())); diff --git a/src/dolphinpart.cpp b/src/dolphinpart.cpp index 8720e0ce2..bb944bad0 100644 --- a/src/dolphinpart.cpp +++ b/src/dolphinpart.cpp @@ -45,11 +45,11 @@ #include "views/dolphinviewactionhandler.h" #include "views/dolphinnewfilemenuobserver.h" #include "views/dolphinremoteencoding.h" -#include "views/dolphindirlister.h" #include #include #include +#include K_PLUGIN_FACTORY(DolphinPartFactory, registerPlugin();) K_EXPORT_PLUGIN(DolphinPartFactory("dolphinpart", "dolphin")) @@ -69,8 +69,8 @@ DolphinPart::DolphinPart(QWidget* parentWidget, QObject* parent, const QVariantL m_view->setTabsForFilesEnabled(true); setWidget(m_view); - connect(m_view, SIGNAL(finishedPathLoading(KUrl)), this, SLOT(slotCompleted(KUrl))); - connect(m_view, SIGNAL(pathLoadingProgress(int)), this, SLOT(updateProgress(int))); + connect(m_view, SIGNAL(finishedDirLoading(KUrl)), this, SLOT(slotCompleted(KUrl))); + connect(m_view, SIGNAL(dirLoadingProgress(int)), this, SLOT(updateProgress(int))); connect(m_view, SIGNAL(errorMessage(QString)), this, SLOT(slotErrorMessage(QString))); setXMLFile("dolphinpart.rc"); diff --git a/src/dolphinviewcontainer.cpp b/src/dolphinviewcontainer.cpp index 1c15c88a9..a6049992f 100644 --- a/src/dolphinviewcontainer.cpp +++ b/src/dolphinviewcontainer.cpp @@ -92,21 +92,20 @@ DolphinViewContainer::DolphinViewContainer(const KUrl& url, QWidget* parent) : connect(m_searchBox, SIGNAL(returnPressed(QString)), this, SLOT(requestFocus())); m_view = new DolphinView(url, this); - connect(m_view, SIGNAL(urlChanged(KUrl)), m_urlNavigator, SLOT(setUrl(KUrl))); - connect(m_view, SIGNAL(writeStateChanged(bool)), this, SIGNAL(writeStateChanged(bool))); - connect(m_view, SIGNAL(requestItemInfo(KFileItem)), this, SLOT(showItemInfo(KFileItem))); - connect(m_view, SIGNAL(errorMessage(QString)), this, SLOT(showErrorMessage(QString))); - connect(m_view, SIGNAL(infoMessage(QString)), this, SLOT(showInfoMessage(QString))); - connect(m_view, SIGNAL(itemActivated(KFileItem)), this, SLOT(slotItemActivated(KFileItem))); - connect(m_view, SIGNAL(redirection(KUrl,KUrl)), this, SLOT(redirect(KUrl,KUrl))); - connect(m_view, SIGNAL(startedPathLoading(KUrl)), this, SLOT(slotStartedPathLoading())); - connect(m_view, SIGNAL(finishedPathLoading(KUrl)), this, SLOT(slotFinishedPathLoading())); - connect(m_view, SIGNAL(itemCountChanged()), this, SLOT(delayedStatusBarUpdate())); - connect(m_view, SIGNAL(pathLoadingProgress(int)), this, SLOT(updateLoadingProgress(int))); - connect(m_view, SIGNAL(sortProgress(int)), this, SLOT(updateSortProgress(int))); - connect(m_view, SIGNAL(infoMessage(QString)), this, SLOT(showInfoMessage(QString))); - connect(m_view, SIGNAL(errorMessage(QString)), this, SLOT(showErrorMessage(QString))); - connect(m_view, SIGNAL(urlIsFileError(KUrl)), this, SLOT(openFile(KUrl))); + connect(m_view, SIGNAL(urlChanged(KUrl)), m_urlNavigator, SLOT(setUrl(KUrl))); + connect(m_view, SIGNAL(writeStateChanged(bool)), this, SIGNAL(writeStateChanged(bool))); + connect(m_view, SIGNAL(requestItemInfo(KFileItem)), this, SLOT(showItemInfo(KFileItem))); + connect(m_view, SIGNAL(errorMessage(QString)), this, SLOT(showErrorMessage(QString))); + connect(m_view, SIGNAL(infoMessage(QString)), this, SLOT(showInfoMessage(QString))); + connect(m_view, SIGNAL(itemActivated(KFileItem)), this, SLOT(slotItemActivated(KFileItem))); + connect(m_view, SIGNAL(redirection(KUrl,KUrl)), this, SLOT(redirect(KUrl,KUrl))); + connect(m_view, SIGNAL(startedDirLoading(KUrl)), this, SLOT(slotStartedDirLoading())); + connect(m_view, SIGNAL(finishedDirLoading(KUrl)), this, SLOT(slotFinishedDirLoading())); + connect(m_view, SIGNAL(itemCountChanged()), this, SLOT(delayedStatusBarUpdate())); + connect(m_view, SIGNAL(dirLoadingProgress(int)), this, SLOT(updateDirLoadingProgress(int))); + connect(m_view, SIGNAL(dirSortingProgress(int)), this, SLOT(updateSortingProgress(int))); + connect(m_view, SIGNAL(infoMessage(QString)), this, SLOT(showInfoMessage(QString))); + connect(m_view, SIGNAL(errorMessage(QString)), this, SLOT(showErrorMessage(QString))); connect(m_view, SIGNAL(selectionChanged(KFileItemList)), this, SLOT(delayedStatusBarUpdate())); connect(m_view, SIGNAL(operationCompletedMessage(QString)), this, SLOT(showOperationCompletedMessage(QString))); connect(m_view, SIGNAL(urlAboutToBeChanged(KUrl)), this, SLOT(slotViewUrlAboutToBeChanged(KUrl))); @@ -333,7 +332,7 @@ void DolphinViewContainer::updateStatusBar() } } -void DolphinViewContainer::updateLoadingProgress(int percent) +void DolphinViewContainer::updateDirLoadingProgress(int percent) { if (m_statusBar->progressText().isEmpty()) { m_statusBar->setProgressText(i18nc("@info:progress", "Loading folder...")); @@ -341,7 +340,7 @@ void DolphinViewContainer::updateLoadingProgress(int percent) m_statusBar->setProgress(percent); } -void DolphinViewContainer::updateSortProgress(int percent) +void DolphinViewContainer::updateSortingProgress(int percent) { if (m_statusBar->progressText().isEmpty()) { m_statusBar->setProgressText(i18nc("@info:progress", "Sorting...")); @@ -349,7 +348,7 @@ void DolphinViewContainer::updateSortProgress(int percent) m_statusBar->setProgress(percent); } -void DolphinViewContainer::slotStartedPathLoading() +void DolphinViewContainer::slotStartedDirLoading() { if (isSearchUrl(url())) { // Search KIO-slaves usually don't provide any progress information. Give @@ -361,18 +360,18 @@ void DolphinViewContainer::slotStartedPathLoading() // Trigger an undetermined progress indication. The progress // information in percent will be triggered by the percent() signal // of the directory lister later. - updateLoadingProgress(-1); + updateDirLoadingProgress(-1); } } -void DolphinViewContainer::slotFinishedPathLoading() +void DolphinViewContainer::slotFinishedDirLoading() { if (!m_statusBar->progressText().isEmpty()) { m_statusBar->setProgressText(QString()); m_statusBar->setProgress(100); } - if (isSearchUrl(url()) && m_view->items().isEmpty()) { + if (isSearchUrl(url()) && m_view->itemsCount() == 0) { // The dir lister has been completed on a Nepomuk-URI and no items have been found. Instead // of showing the default status bar information ("0 items") a more helpful information is given: m_statusBar->setMessage(i18nc("@info:status", "No items found."), DolphinStatusBar::Information); @@ -422,12 +421,6 @@ void DolphinViewContainer::slotItemActivated(const KFileItem& item) item.run(); } -void DolphinViewContainer::openFile(const KUrl& url) -{ - const KFileItem item(KFileItem::Unknown, KFileItem::Unknown, url); - slotItemActivated(item); -} - void DolphinViewContainer::showItemInfo(const KFileItem& item) { if (item.isNull()) { diff --git a/src/dolphinviewcontainer.h b/src/dolphinviewcontainer.h index 734021aa9..de3bd60a6 100644 --- a/src/dolphinviewcontainer.h +++ b/src/dolphinviewcontainer.h @@ -154,21 +154,21 @@ private slots: */ void updateStatusBar(); - void updateLoadingProgress(int percent); + void updateDirLoadingProgress(int percent); - void updateSortProgress(int percent); + void updateSortingProgress(int percent); /** * Updates the statusbar to show an undetermined progress with the correct * context information whether a searching or a directory loading is done. */ - void slotStartedPathLoading(); + void slotStartedDirLoading(); /** * Assures that the viewport position is restored and updates the * statusbar to reflect the current content. */ - void slotFinishedPathLoading(); + void slotFinishedDirLoading(); /** * Handles clicking on an item. If the item is a directory, the @@ -177,13 +177,6 @@ private slots: */ void slotItemActivated(const KFileItem& item); - /** - * Opens a the file \a url by opening the corresponding application. - * Is connected with the signal urlIsFile() from DolphinDirLister and will - * get invoked if the user manually has entered a file into the URL navigator. - */ - void openFile(const KUrl& url); - /** * Shows the information for the item \a item inside the statusbar. If the * item is null, the default statusbar information is shown. diff --git a/src/kitemviews/kfileitemclipboard.cpp b/src/kitemviews/kfileitemclipboard.cpp deleted file mode 100644 index fb63f9530..000000000 --- a/src/kitemviews/kfileitemclipboard.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "kfileitemclipboard_p.h" - -#include -#include -#include -#include - -class KFileItemClipboardSingleton -{ -public: - KFileItemClipboard instance; -}; -K_GLOBAL_STATIC(KFileItemClipboardSingleton, s_KFileItemClipboard) - - - -KFileItemClipboard* KFileItemClipboard::instance() -{ - return &s_KFileItemClipboard->instance; -} - -bool KFileItemClipboard::isCut(const KUrl& url) const -{ - return m_cutItems.contains(url); -} - -QList KFileItemClipboard::cutItems() const -{ - return m_cutItems.toList(); -} - -KFileItemClipboard::~KFileItemClipboard() -{ -} - -void KFileItemClipboard::updateCutItems() -{ - const QMimeData* mimeData = QApplication::clipboard()->mimeData(); - const QByteArray data = mimeData->data("application/x-kde-cutselection"); - const bool isCutSelection = (!data.isEmpty() && data.at(0) == QLatin1Char('1')); - if (isCutSelection) { - m_cutItems = KUrl::List::fromMimeData(mimeData).toSet(); - emit cutItemsChanged(); - } -} - -KFileItemClipboard::KFileItemClipboard() : - QObject(0), - m_cutItems() -{ - updateCutItems(); - - connect(QApplication::clipboard(), SIGNAL(dataChanged()), - this, SLOT(updateCutItems())); -} - -#include "kfileitemclipboard_p.moc" diff --git a/src/kitemviews/kfileitemclipboard_p.h b/src/kitemviews/kfileitemclipboard_p.h deleted file mode 100644 index 86eb8e9fc..000000000 --- a/src/kitemviews/kfileitemclipboard_p.h +++ /dev/null @@ -1,62 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef KFILEITEMCLIPBOARD_H -#define KFILEITEMCLIPBOARD_H - -#include -#include -#include -#include - -#include "libdolphin_export.h" - -/** - * @brief Wrapper for QClipboard to provide fast access for checking - * whether a KFileItem has been clipped. - */ -class LIBDOLPHINPRIVATE_EXPORT KFileItemClipboard : public QObject -{ - Q_OBJECT - -public: - static KFileItemClipboard* instance(); - - bool isCut(const KUrl& url) const; - - QList cutItems() const; - -signals: - void cutItemsChanged(); - -protected: - virtual ~KFileItemClipboard(); - -private slots: - void updateCutItems(); - -private: - KFileItemClipboard(); - - QSet m_cutItems; - - friend class KFileItemClipboardSingleton; -}; - -#endif diff --git a/src/kitemviews/kfileitemlistview.cpp b/src/kitemviews/kfileitemlistview.cpp index 11760fed1..6464ec38a 100644 --- a/src/kitemviews/kfileitemlistview.cpp +++ b/src/kitemviews/kfileitemlistview.cpp @@ -23,9 +23,9 @@ #include "kfileitemmodelrolesupdater.h" #include "kfileitemlistwidget.h" #include "kfileitemmodel.h" -#include "kpixmapmodifier_p.h" #include #include +#include "private/kpixmapmodifier.h" #include #include diff --git a/src/kitemviews/kfileitemlistwidget.cpp b/src/kitemviews/kfileitemlistwidget.cpp index 14ec1ec22..f3b4da892 100644 --- a/src/kitemviews/kfileitemlistwidget.cpp +++ b/src/kitemviews/kfileitemlistwidget.cpp @@ -19,10 +19,8 @@ #include "kfileitemlistwidget.h" -#include "kfileitemclipboard_p.h" #include "kfileitemlistview.h" #include "kfileitemmodel.h" -#include "kpixmapmodifier_p.h" #include #include @@ -32,6 +30,9 @@ #include #include +#include "private/kfileitemclipboard.h" +#include "private/kpixmapmodifier.h" + #include #include #include @@ -193,12 +194,15 @@ QRectF KFileItemListWidget::textRect() const QRectF KFileItemListWidget::textFocusRect() const { + // In the compact- and details-layout a larger textRect() is returned to be aligned + // with the iconRect(). This is useful to have a larger selection/hover-area + // when having a quite large icon size but only one line of text. Still the + // focus rectangle should be shown as narrow as possible around the text. + const_cast(this)->triggerCacheRefreshing(); - if (m_layout == CompactLayout) { - // In the compact layout a larger textRect() is returned to be aligned - // with the iconRect(). This is useful to have a larger selection/hover-area - // when having a quite large icon size but only one line of text. Still the - // focus rectangle should be shown as narrow as possible around the text. + + switch (m_layout) { + case CompactLayout: { QRectF rect = m_textRect; const TextInfo* topText = m_textInfo.value(m_sortedVisibleRoles.first()); const TextInfo* bottomText = m_textInfo.value(m_sortedVisibleRoles.last()); @@ -206,6 +210,19 @@ QRectF KFileItemListWidget::textFocusRect() const rect.setBottom(bottomText->pos.y() + bottomText->staticText.size().height()); return rect; } + + case DetailsLayout: { + QRectF rect = m_textRect; + const TextInfo* textInfo = m_textInfo.value(m_sortedVisibleRoles.first()); + rect.setTop(textInfo->pos.y()); + rect.setBottom(textInfo->pos.y() + textInfo->staticText.size().height()); + return rect; + } + + default: + break; + } + return m_textRect; } diff --git a/src/kitemviews/kfileitemmodel.cpp b/src/kitemviews/kfileitemmodel.cpp index 685af8972..409b5cd52 100644 --- a/src/kitemviews/kfileitemmodel.cpp +++ b/src/kitemviews/kfileitemmodel.cpp @@ -19,26 +19,27 @@ #include "kfileitemmodel.h" -#include #include -#include "kfileitemmodelsortalgorithm_p.h" #include #include #include #include +#include "private/kfileitemmodelsortalgorithm.h" +#include "private/kfileitemmodeldirlister.h" + #include #include // #define KFILEITEMMODEL_DEBUG -KFileItemModel::KFileItemModel(KDirLister* dirLister, QObject* parent) : +KFileItemModel::KFileItemModel(QObject* parent) : KItemModelBase("name", parent), - m_dirLister(dirLister), + m_dirLister(0), m_naturalSorting(KGlobalSettings::naturalSorting()), m_sortFoldersFirst(true), m_sortRole(NameRole), - m_sortProgressPercent(-1), + m_sortingProgressPercent(-1), m_roles(), m_caseSensitivity(Qt::CaseInsensitive), m_itemData(), @@ -54,6 +55,22 @@ KFileItemModel::KFileItemModel(KDirLister* dirLister, QObject* parent) : m_expandedUrls(), m_urlsToExpand() { + m_dirLister = new KFileItemModelDirLister(this); + m_dirLister->setAutoUpdate(true); + m_dirLister->setDelayedMimeTypes(true); + + connect(m_dirLister, SIGNAL(started(KUrl)), this, SIGNAL(dirLoadingStarted())); + connect(m_dirLister, SIGNAL(canceled()), this, SLOT(slotCanceled())); + connect(m_dirLister, SIGNAL(completed(KUrl)), this, SLOT(slotCompleted())); + connect(m_dirLister, SIGNAL(newItems(KFileItemList)), this, SLOT(slotNewItems(KFileItemList))); + connect(m_dirLister, SIGNAL(itemsDeleted(KFileItemList)), this, SLOT(slotItemsDeleted(KFileItemList))); + connect(m_dirLister, SIGNAL(refreshItems(QList >)), this, SLOT(slotRefreshItems(QList >))); + connect(m_dirLister, SIGNAL(clear()), this, SLOT(slotClear())); + connect(m_dirLister, SIGNAL(clear(KUrl)), this, SLOT(slotClear(KUrl))); + connect(m_dirLister, SIGNAL(infoMessage(QString)), this, SIGNAL(infoMessage(QString))); + connect(m_dirLister, SIGNAL(errorMessage(QString)), this, SIGNAL(errorMessage(QString))); + connect(m_dirLister, SIGNAL(redirection(KUrl,KUrl)), this, SIGNAL(redirection(KUrl,KUrl))); + // Apply default roles that should be determined resetRoles(); m_requestRole[NameRole] = true; @@ -61,16 +78,6 @@ KFileItemModel::KFileItemModel(KDirLister* dirLister, QObject* parent) : m_roles.insert("name"); m_roles.insert("isDir"); - Q_ASSERT(dirLister); - - connect(dirLister, SIGNAL(canceled()), this, SLOT(slotCanceled())); - connect(dirLister, SIGNAL(completed(KUrl)), this, SLOT(slotCompleted())); - connect(dirLister, SIGNAL(newItems(KFileItemList)), this, SLOT(slotNewItems(KFileItemList))); - connect(dirLister, SIGNAL(itemsDeleted(KFileItemList)), this, SLOT(slotItemsDeleted(KFileItemList))); - connect(dirLister, SIGNAL(refreshItems(QList >)), this, SLOT(slotRefreshItems(QList >))); - connect(dirLister, SIGNAL(clear()), this, SLOT(slotClear())); - connect(dirLister, SIGNAL(clear(KUrl)), this, SLOT(slotClear(KUrl))); - // For slow KIO-slaves like used for searching it makes sense to show results periodically even // before the completed() or canceled() signal has been emitted. m_maximumUpdateIntervalTimer = new QTimer(this); @@ -96,6 +103,21 @@ KFileItemModel::~KFileItemModel() m_itemData.clear(); } +void KFileItemModel::loadDir(const KUrl& url) +{ + m_dirLister->openUrl(url); +} + +void KFileItemModel::refreshDir(const KUrl& url) +{ + m_dirLister->openUrl(url, KDirLister::Reload); +} + +KUrl KFileItemModel::dir() const +{ + return m_dirLister->url(); +} + int KFileItemModel::count() const { return m_itemData.count(); @@ -160,34 +182,26 @@ bool KFileItemModel::sortFoldersFirst() const void KFileItemModel::setShowHiddenFiles(bool show) { - KDirLister* dirLister = m_dirLister.data(); - if (dirLister) { - dirLister->setShowingDotFiles(show); - dirLister->emitChanges(); - if (show) { - slotCompleted(); - } + m_dirLister->setShowingDotFiles(show); + m_dirLister->emitChanges(); + if (show) { + slotCompleted(); } } bool KFileItemModel::showHiddenFiles() const { - const KDirLister* dirLister = m_dirLister.data(); - return dirLister ? dirLister->showingDotFiles() : false; + return m_dirLister->showingDotFiles(); } void KFileItemModel::setShowFoldersOnly(bool enabled) { - KDirLister* dirLister = m_dirLister.data(); - if (dirLister) { - dirLister->setDirOnlyMode(enabled); - } + m_dirLister->setDirOnlyMode(enabled); } bool KFileItemModel::showFoldersOnly() const { - KDirLister* dirLister = m_dirLister.data(); - return dirLister ? dirLister->dirOnlyMode() : false; + return m_dirLister->dirOnlyMode(); } QMimeData* KFileItemModel::createMimeData(const QSet& indexes) const @@ -324,11 +338,7 @@ int KFileItemModel::index(const KUrl& url) const KFileItem KFileItemModel::rootItem() const { - const KDirLister* dirLister = m_dirLister.data(); - if (dirLister) { - return dirLister->rootItem(); - } - return KFileItem(); + return m_dirLister->rootItem(); } void KFileItemModel::clear() @@ -391,21 +401,14 @@ bool KFileItemModel::setExpanded(int index, bool expanded) return false; } - KDirLister* dirLister = m_dirLister.data(); const KUrl url = m_itemData.at(index)->item.url(); if (expanded) { m_expandedUrls.insert(url); - - if (dirLister) { - dirLister->openUrl(url, KDirLister::Keep); - return true; - } + m_dirLister->openUrl(url, KDirLister::Keep); } else { m_expandedUrls.remove(url); + m_dirLister->stop(url); - if (dirLister) { - dirLister->stop(url); - } KFileItemList itemsToRemove; const int expandedParentsCount = data(index)["expandedParentsCount"].toInt(); @@ -415,10 +418,9 @@ bool KFileItemModel::setExpanded(int index, bool expanded) ++index; } removeItems(itemsToRemove); - return true; } - return false; + return true; } bool KFileItemModel::isExpanded(int index) const @@ -460,18 +462,13 @@ void KFileItemModel::restoreExpandedUrls(const QSet& urls) void KFileItemModel::expandParentItems(const KUrl& url) { - const KDirLister* dirLister = m_dirLister.data(); - if (!dirLister) { - return; - } - - const int pos = dirLister->url().path().length(); + const int pos = m_dirLister->url().path().length(); // Assure that each sub-path of the URL that should be // expanded is added to m_urlsToExpand. KDirLister // does not care whether the parent-URL has already been // expanded. - KUrl urlToExpand = dirLister->url(); + KUrl urlToExpand = m_dirLister->url(); const QStringList subDirs = url.path().mid(pos).split(QDir::separator()); for (int i = 0; i < subDirs.count() - 1; ++i) { urlToExpand.addPath(subDirs.at(i)); @@ -537,6 +534,11 @@ QString KFileItemModel::nameFilter() const return m_filter.pattern(); } +void KFileItemModel::cancelDirLoading() +{ + m_dirLister->stop(); +} + QList KFileItemModel::rolesInformation() { static QList rolesInfo; @@ -666,7 +668,7 @@ void KFileItemModel::slotCompleted() m_urlsToExpand.clear(); } - emit loadingCompleted(); + emit dirLoadingCompleted(); } void KFileItemModel::slotCanceled() @@ -1222,8 +1224,8 @@ QHash KFileItemModel::retrieveData(const KFileItem& item) } if (m_requestRole[ExpandedParentsCountRole]) { - if (m_expandedParentsCountRoot == UninitializedExpandedParentsCountRoot && m_dirLister.data()) { - const KUrl rootUrl = m_dirLister.data()->url(); + if (m_expandedParentsCountRoot == UninitializedExpandedParentsCountRoot) { + const KUrl rootUrl = m_dirLister->url(); const QString protocol = rootUrl.protocol(); const bool forceExpandedParentsCountRoot = (protocol == QLatin1String("trash") || protocol == QLatin1String("nepomuk") || @@ -1501,8 +1503,7 @@ QString KFileItemModel::subPath(const KFileItem& item, bool KFileItemModel::useMaximumUpdateInterval() const { - const KDirLister* dirLister = m_dirLister.data(); - return dirLister && !dirLister->url().isLocalFile(); + return !m_dirLister->url().isLocalFile(); } QList > KFileItemModel::nameRoleGroups() const @@ -1847,20 +1848,20 @@ void KFileItemModel::emitSortProgress(int resolvedCount) const int itemCount = count(); if (resolvedCount >= itemCount) { - m_sortProgressPercent = -1; + m_sortingProgressPercent = -1; if (m_resortAllItemsTimer->isActive()) { m_resortAllItemsTimer->stop(); resortAllItems(); } - emit sortProgress(100); + emit dirSortingProgress(100); } else if (itemCount > 0) { resolvedCount = qBound(0, resolvedCount, itemCount); const int progress = resolvedCount * 100 / itemCount; - if (m_sortProgressPercent != progress) { - m_sortProgressPercent = progress; - emit sortProgress(progress); + if (m_sortingProgressPercent != progress) { + m_sortingProgressPercent = progress; + emit dirSortingProgress(progress); } } } diff --git a/src/kitemviews/kfileitemmodel.h b/src/kitemviews/kfileitemmodel.h index eaf35fecd..05834cd31 100644 --- a/src/kitemviews/kfileitemmodel.h +++ b/src/kitemviews/kfileitemmodel.h @@ -23,12 +23,12 @@ #include #include #include -#include #include +#include #include -class KDirLister; +class KFileItemModelDirLister; class QTimer; /** @@ -42,24 +42,37 @@ class QTimer; * * Also the recursive expansion of sub-directories is supported by * KFileItemModel::setExpanded(). - * - * TODO: In the longterm instead of passing a KDirLister just an URL should - * be passed and a KDirLister used internally. This solves the following issues: - * - The user of the API does not need to decide whether he listens to KDirLister - * or KFileItemModel. - * - It resolves minor conceptual differences between KDirLister and KFileItemModel. - * E.g. there is no way for KFileItemModel to check whether a completed() signal - * will be emitted after newItems() will be send by KDirLister or not (in the case - * of setShowingDotFiles() no completed() signal will get emitted). */ class LIBDOLPHINPRIVATE_EXPORT KFileItemModel : public KItemModelBase { Q_OBJECT public: - explicit KFileItemModel(KDirLister* dirLister, QObject* parent = 0); + explicit KFileItemModel(QObject* parent = 0); virtual ~KFileItemModel(); + /** + * Loads the directory specified by \a url. The signals + * dirLoadingStarted(), dirLoadingProgress() and dirLoadingCompleted() + * indicate the current state of the loading process. The items + * of the directory are added after the loading has been completed. + */ + void loadDir(const KUrl& url); + + /** + * Throws away all currently loaded items and refreshes the directory + * by reloading all items again. + */ + void refreshDir(const KUrl& url); + + /** + * @return Parent directory of the items that are shown. In case + * if a directory tree is shown, KFileItemModel::dir() returns + * the root-parent of all items. + * @see rootItem() + */ + KUrl dir() const; + virtual int count() const; virtual QHash data(int index) const; virtual bool setData(int index, const QHash& values); @@ -123,7 +136,8 @@ public: int index(const KUrl& url) const; /** - * @return Root item of all items. + * @return Root item of all items representing the item + * for KFileItemModel::dir(). */ KFileItem rootItem() const; @@ -158,6 +172,8 @@ public: void setNameFilter(const QString& nameFilter); QString nameFilter() const; + void cancelDirLoading(); + struct RoleInfo { QByteArray role; QString translation; @@ -175,6 +191,14 @@ public: static QList rolesInformation(); signals: + /** + * Is emitted if the loading of a directory has been started. It is + * assured that a signal dirLoadingCompleted() will be send after + * the loading has been finished. For tracking the loading progress + * the signal dirLoadingProgress() gets emitted in between. + */ + void dirLoadingStarted(); + /** * Is emitted after the loading of a directory has been completed or new * items have been inserted to an already loaded directory. Usually @@ -182,14 +206,38 @@ signals: * (the only exception is loading an empty directory, where only a * loadingCompleted() signal gets emitted). */ - void loadingCompleted(); + void dirLoadingCompleted(); + + /** + * Informs about the progress in percent when loading a directory. It is assured + * that the signal dirLoadingStarted() has been emitted before. + */ + void dirLoadingProgress(int percent); /** * Is emitted if the sort-role gets resolved asynchronously and provides * the progress-information of the sorting in percent. It is assured * that the last sortProgress-signal contains 100 as value. */ - void sortProgress(int percent); + void dirSortingProgress(int percent); + + /** + * Is emitted if an information message (e.g. "Connecting to host...") + * should be shown. + */ + void infoMessage(const QString& message); + + /** + * Is emitted if an error message (e.g. "Unknown location") + * should be shown. + */ + void errorMessage(const QString& message); + + /** + * Is emitted if a redirection from the current URL \a oldUrl + * to the new URL \a newUrl has been done. + */ + void redirection(const KUrl& oldUrl, const KUrl& newUrl); protected: virtual void onGroupedSortingChanged(bool current); @@ -357,13 +405,13 @@ private: static void determineMimeTypes(const KFileItemList& items, int timeout); private: - QWeakPointer m_dirLister; + KFileItemModelDirLister* m_dirLister; bool m_naturalSorting; bool m_sortFoldersFirst; RoleType m_sortRole; - int m_sortProgressPercent; // Value of sortProgress() signal + int m_sortingProgressPercent; // Value of dirSortingProgress() signal QSet m_roles; Qt::CaseSensitivity m_caseSensitivity; diff --git a/src/kitemviews/kfileitemmodelfilter.cpp b/src/kitemviews/kfileitemmodelfilter.cpp deleted file mode 100644 index f3f47ba56..000000000 --- a/src/kitemviews/kfileitemmodelfilter.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Janardhan Reddy * - * * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "kfileitemmodelfilter_p.h" - -#include -#include - -KFileItemModelFilter::KFileItemModelFilter() : - m_useRegExp(false), - m_regExp(0), - m_lowerCasePattern(), - m_pattern() -{ -} - -KFileItemModelFilter::~KFileItemModelFilter() -{ - delete m_regExp; - m_regExp = 0; -} - -void KFileItemModelFilter::setPattern(const QString& filter) -{ - m_pattern = filter; - m_lowerCasePattern = filter.toLower(); - - m_useRegExp = filter.contains('*') || - filter.contains('?') || - filter.contains('['); - if (m_useRegExp) { - if (!m_regExp) { - m_regExp = new QRegExp(); - m_regExp->setCaseSensitivity(Qt::CaseInsensitive); - m_regExp->setMinimal(false); - m_regExp->setPatternSyntax(QRegExp::WildcardUnix); - } - m_regExp->setPattern(filter); - } -} - -QString KFileItemModelFilter::pattern() const -{ - return m_pattern; -} - -bool KFileItemModelFilter::matches(const KFileItem& item) const -{ - if (m_useRegExp) { - return m_regExp->exactMatch(item.text()); - } else { - return item.text().toLower().contains(m_lowerCasePattern); - } -} diff --git a/src/kitemviews/kfileitemmodelfilter_p.h b/src/kitemviews/kfileitemmodelfilter_p.h deleted file mode 100644 index 9bdf1fd95..000000000 --- a/src/kitemviews/kfileitemmodelfilter_p.h +++ /dev/null @@ -1,70 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Janardhan Reddy * - * * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef KFILEITEMMODELFILTER_H -#define KFILEITEMMODELFILTER_H - -#include -#include - -class KFileItem; -class QRegExp; - -/** - * @brief Allows to check whether an item of the KFileItemModel - * matches with a set filter-string. - * - * Currently the filter is only checked for the KFileItem::text() - * property of the KFileItem, but this might get extended in - * future. - */ -class LIBDOLPHINPRIVATE_EXPORT KFileItemModelFilter -{ - -public: - KFileItemModelFilter(); - virtual ~KFileItemModelFilter(); - - /** - * Sets the pattern that is used for a comparison with the item - * in KFileItemModelFilter::matches(). Per default the pattern - * defines a sub-string. As soon as the pattern contains at least - * a '*', '?' or '[' the pattern represents a regular expression. - */ - void setPattern(const QString& pattern); - QString pattern() const; - - /** - * @return True if the item matches with the pattern defined by - * KFileItemModelFilter::setPattern(). - */ - bool matches(const KFileItem& item) const; - -private: - bool m_useRegExp; // If true, m_regExp is used for filtering, - // otherwise m_lowerCaseFilter is used. - QRegExp* m_regExp; - QString m_lowerCasePattern; // Lowercase version of m_filter for - // faster comparison in matches(). - QString m_pattern; // Property set by setFilter(). -}; -#endif - - diff --git a/src/kitemviews/kfileitemmodelrolesupdater.cpp b/src/kitemviews/kfileitemmodelrolesupdater.cpp index 632df676d..927407a69 100644 --- a/src/kitemviews/kfileitemmodelrolesupdater.cpp +++ b/src/kitemviews/kfileitemmodelrolesupdater.cpp @@ -20,7 +20,6 @@ #include "kfileitemmodelrolesupdater.h" #include "kfileitemmodel.h" -#include "kpixmapmodifier_p.h" #include #include @@ -28,14 +27,17 @@ #include #include #include + +#include "private/kpixmapmodifier.h" + #include #include #include #include #ifdef HAVE_NEPOMUK - #include "knepomukrolesprovider_p.h" - #include "knepomukresourcewatcher_p.h" + #include "private/knepomukrolesprovider.h" + #include "private/knepomukresourcewatcher.h" #endif // Required includes for subItemsCount(): @@ -69,7 +71,7 @@ KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel* model, QO m_previewShown(false), m_enlargeSmallPreviews(true), m_clearPreviews(false), - m_sortProgress(-1), + m_sortingProgress(-1), m_model(model), m_iconSize(), m_firstVisibleIndex(0), @@ -849,7 +851,7 @@ void KFileItemModelRolesUpdater::sortAndResolvePendingRoles() void KFileItemModelRolesUpdater::applySortProgressToModel() { - if (m_sortProgress < 0) { + if (m_sortingProgress < 0) { return; } @@ -861,7 +863,7 @@ void KFileItemModelRolesUpdater::applySortProgressToModel() if (resolvedCount > 0) { m_model->emitSortProgress(resolvedCount); if (resolvedCount == m_model->count()) { - m_sortProgress = -1; + m_sortingProgress = -1; } } } @@ -877,11 +879,11 @@ void KFileItemModelRolesUpdater::updateSortProgress() ? hasUnknownMimeTypes() : m_resolvableRoles.contains(sortRole); - if (m_sortProgress >= 0) { + if (m_sortingProgress >= 0) { // Mark the current sorting as finished m_model->emitSortProgress(m_model->count()); } - m_sortProgress = showProgress ? 0 : -1; + m_sortingProgress = showProgress ? 0 : -1; } bool KFileItemModelRolesUpdater::hasUnknownMimeTypes() const diff --git a/src/kitemviews/kfileitemmodelrolesupdater.h b/src/kitemviews/kfileitemmodelrolesupdater.h index ce8cf1c73..c520a23e8 100644 --- a/src/kitemviews/kfileitemmodelrolesupdater.h +++ b/src/kitemviews/kfileitemmodelrolesupdater.h @@ -240,7 +240,7 @@ private: // during the roles-updater has been paused by setPaused(). bool m_clearPreviews; - int m_sortProgress; + int m_sortingProgress; KFileItemModel* m_model; QSize m_iconSize; diff --git a/src/kitemviews/kfileitemmodelsortalgorithm.cpp b/src/kitemviews/kfileitemmodelsortalgorithm.cpp deleted file mode 100644 index 4c2f29dee..000000000 --- a/src/kitemviews/kfileitemmodelsortalgorithm.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2012 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "kfileitemmodelsortalgorithm_p.h" - -void KFileItemModelSortAlgorithm::sort(KFileItemModel* model, - QList::iterator begin, - QList::iterator end) -{ - // The implementation is based on qStableSortHelper() from qalgorithms.h - // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). - - const int span = end - begin; - if (span < 2) { - return; - } - - const QList::iterator middle = begin + span / 2; - sort(model, begin, middle); - sort(model, middle, end); - merge(model, begin, middle, end); -} - -void KFileItemModelSortAlgorithm::merge(KFileItemModel* model, - QList::iterator begin, - QList::iterator pivot, - QList::iterator end) -{ - // The implementation is based on qMerge() from qalgorithms.h - // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). - - const int len1 = pivot - begin; - const int len2 = end - pivot; - - if (len1 == 0 || len2 == 0) { - return; - } - - if (len1 + len2 == 2) { - if (model->lessThan(*(begin + 1), *(begin))) { - qSwap(*begin, *(begin + 1)); - } - return; - } - - QList::iterator firstCut; - QList::iterator secondCut; - int len2Half; - if (len1 > len2) { - const int len1Half = len1 / 2; - firstCut = begin + len1Half; - secondCut = lowerBound(model, pivot, end, *firstCut); - len2Half = secondCut - pivot; - } else { - len2Half = len2 / 2; - secondCut = pivot + len2Half; - firstCut = upperBound(model, begin, pivot, *secondCut); - } - - reverse(firstCut, pivot); - reverse(pivot, secondCut); - reverse(firstCut, secondCut); - - const QList::iterator newPivot = firstCut + len2Half; - merge(model, begin, firstCut, newPivot); - merge(model, newPivot, secondCut, end); -} - - -QList::iterator -KFileItemModelSortAlgorithm::lowerBound(KFileItemModel* model, - QList::iterator begin, - QList::iterator end, - const KFileItemModel::ItemData* value) -{ - // The implementation is based on qLowerBound() from qalgorithms.h - // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). - - QList::iterator middle; - int n = int(end - begin); - int half; - - while (n > 0) { - half = n >> 1; - middle = begin + half; - if (model->lessThan(*middle, value)) { - begin = middle + 1; - n -= half + 1; - } else { - n = half; - } - } - return begin; -} - -QList::iterator -KFileItemModelSortAlgorithm::upperBound(KFileItemModel* model, - QList::iterator begin, - QList::iterator end, - const KFileItemModel::ItemData* value) -{ - // The implementation is based on qUpperBound() from qalgorithms.h - // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). - - QList::iterator middle; - int n = end - begin; - int half; - - while (n > 0) { - half = n >> 1; - middle = begin + half; - if (model->lessThan(value, *middle)) { - n = half; - } else { - begin = middle + 1; - n -= half + 1; - } - } - return begin; -} - -void KFileItemModelSortAlgorithm::reverse(QList::iterator begin, - QList::iterator end) -{ - // The implementation is based on qReverse() from qalgorithms.h - // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). - - --end; - while (begin < end) { - qSwap(*begin++, *end--); - } -} diff --git a/src/kitemviews/kfileitemmodelsortalgorithm_p.h b/src/kitemviews/kfileitemmodelsortalgorithm_p.h deleted file mode 100644 index 3a596dff5..000000000 --- a/src/kitemviews/kfileitemmodelsortalgorithm_p.h +++ /dev/null @@ -1,70 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2012 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef KFILEITEMMODELSORTALGORITHM_H -#define KFILEITEMMODELSORTALGORITHM_H - -#include - -#include - -/** - * @brief Sort algorithm for sorting items of KFileItemModel. - * - * Sorts the items by using KFileItemModel::lessThan() as comparison criteria. - * The merge sort algorithm is used to assure a worst-case - * of O(n * log(n)) and to keep the number of comparisons low. - * - * The implementation is based on qStableSortHelper() from qalgorithms.h - * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). - * The sorting implementations of qAlgorithms could not be used as they - * don't support having a member-function as comparison criteria. - */ -class LIBDOLPHINPRIVATE_EXPORT KFileItemModelSortAlgorithm -{ -public: - static void sort(KFileItemModel* model, - QList::iterator begin, - QList::iterator end); - -private: - static void merge(KFileItemModel* model, - QList::iterator begin, - QList::iterator pivot, - QList::iterator end); - - static QList::iterator - lowerBound(KFileItemModel* model, - QList::iterator begin, - QList::iterator end, - const KFileItemModel::ItemData* value); - - static QList::iterator - upperBound(KFileItemModel* model, - QList::iterator begin, - QList::iterator end, - const KFileItemModel::ItemData* value); - - static void reverse(QList::iterator begin, - QList::iterator end); -}; - -#endif - - diff --git a/src/kitemviews/kitemlistcontainer.cpp b/src/kitemviews/kitemlistcontainer.cpp index b480b4494..5a485b62c 100644 --- a/src/kitemviews/kitemlistcontainer.cpp +++ b/src/kitemviews/kitemlistcontainer.cpp @@ -23,10 +23,11 @@ #include "kitemlistcontainer.h" #include "kitemlistcontroller.h" -#include "kitemlistsmoothscroller_p.h" #include "kitemlistview.h" #include "kitemmodelbase.h" +#include "private/kitemlistsmoothscroller.h" + #include #include #include diff --git a/src/kitemviews/kitemlistcontroller.cpp b/src/kitemviews/kitemlistcontroller.cpp index ad08223a4..c0f565b4d 100644 --- a/src/kitemviews/kitemlistcontroller.cpp +++ b/src/kitemviews/kitemlistcontroller.cpp @@ -23,10 +23,14 @@ #include "kitemlistcontroller.h" +#include +#include + #include "kitemlistview.h" -#include "kitemlistrubberband_p.h" #include "kitemlistselectionmanager.h" -#include "kitemlistkeyboardsearchmanager_p.h" + +#include "private/kitemlistrubberband.h" +#include "private/kitemlistkeyboardsearchmanager.h" #include #include @@ -37,9 +41,6 @@ #include #include -#include -#include - KItemListController::KItemListController(QObject* parent) : QObject(parent), m_singleClickActivation(KGlobalSettings::singleClick()), diff --git a/src/kitemviews/kitemlistheader.cpp b/src/kitemviews/kitemlistheader.cpp index be7a09c8f..e89ece0a1 100644 --- a/src/kitemviews/kitemlistheader.cpp +++ b/src/kitemviews/kitemlistheader.cpp @@ -18,9 +18,10 @@ ***************************************************************************/ #include "kitemlistheader.h" -#include "kitemlistheaderwidget_p.h" #include "kitemlistview.h" +#include "private/kitemlistheaderwidget.h" + KItemListHeader::~KItemListHeader() { } diff --git a/src/kitemviews/kitemlistheaderwidget.cpp b/src/kitemviews/kitemlistheaderwidget.cpp deleted file mode 100644 index 2105b674c..000000000 --- a/src/kitemviews/kitemlistheaderwidget.cpp +++ /dev/null @@ -1,535 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "kitemlistheaderwidget_p.h" - -#include -#include -#include "kitemmodelbase.h" - -#include -#include -#include -#include - -#include - -KItemListHeaderWidget::KItemListHeaderWidget(QGraphicsWidget* parent) : - QGraphicsWidget(parent), - m_automaticColumnResizing(true), - m_model(0), - m_offset(0), - m_columns(), - m_columnWidths(), - m_preferredColumnWidths(), - m_hoveredRoleIndex(-1), - m_pressedRoleIndex(-1), - m_roleOperation(NoRoleOperation), - m_pressedMousePos(), - m_movingRole() -{ - m_movingRole.x = 0; - m_movingRole.xDec = 0; - m_movingRole.index = -1; - - setAcceptHoverEvents(true); -} - -KItemListHeaderWidget::~KItemListHeaderWidget() -{ -} - -void KItemListHeaderWidget::setModel(KItemModelBase* model) -{ - if (m_model == model) { - return; - } - - if (m_model) { - disconnect(m_model, SIGNAL(sortRoleChanged(QByteArray,QByteArray)), - this, SLOT(slotSortRoleChanged(QByteArray,QByteArray))); - disconnect(m_model, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)), - this, SLOT(slotSortOrderChanged(Qt::SortOrder,Qt::SortOrder))); - } - - m_model = model; - - if (m_model) { - connect(m_model, SIGNAL(sortRoleChanged(QByteArray,QByteArray)), - this, SLOT(slotSortRoleChanged(QByteArray,QByteArray))); - connect(m_model, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)), - this, SLOT(slotSortOrderChanged(Qt::SortOrder,Qt::SortOrder))); - } -} - -KItemModelBase* KItemListHeaderWidget::model() const -{ - return m_model; -} - -void KItemListHeaderWidget::setAutomaticColumnResizing(bool automatic) -{ - m_automaticColumnResizing = automatic; -} - -bool KItemListHeaderWidget::automaticColumnResizing() const -{ - return m_automaticColumnResizing; -} - -void KItemListHeaderWidget::setColumns(const QList& roles) -{ - foreach (const QByteArray& role, roles) { - if (!m_columnWidths.contains(role)) { - m_columnWidths.remove(role); - m_preferredColumnWidths.remove(role); - } - } - - m_columns = roles; - update(); -} - -QList KItemListHeaderWidget::columns() const -{ - return m_columns; -} - -void KItemListHeaderWidget::setColumnWidth(const QByteArray& role, qreal width) -{ - const qreal minWidth = minimumColumnWidth(); - if (width < minWidth) { - width = minWidth; - } - - if (m_columnWidths.value(role) != width) { - m_columnWidths.insert(role, width); - update(); - } -} - -qreal KItemListHeaderWidget::columnWidth(const QByteArray& role) const -{ - return m_columnWidths.value(role); -} - -void KItemListHeaderWidget::setPreferredColumnWidth(const QByteArray& role, qreal width) -{ - m_preferredColumnWidths.insert(role, width); -} - -qreal KItemListHeaderWidget::preferredColumnWidth(const QByteArray& role) const -{ - return m_preferredColumnWidths.value(role); -} - -void KItemListHeaderWidget::setOffset(qreal offset) -{ - if (m_offset != offset) { - m_offset = offset; - update(); - } -} - -qreal KItemListHeaderWidget::offset() const -{ - return m_offset; -} - -qreal KItemListHeaderWidget::minimumColumnWidth() const -{ - QFontMetricsF fontMetrics(font()); - return fontMetrics.height() * 4; -} - -void KItemListHeaderWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - - if (!m_model) { - return; - } - - // Draw roles - painter->setFont(font()); - painter->setPen(palette().text().color()); - - qreal x = -m_offset; - int orderIndex = 0; - foreach (const QByteArray& role, m_columns) { - const qreal roleWidth = m_columnWidths.value(role); - const QRectF rect(x, 0, roleWidth, size().height()); - paintRole(painter, role, rect, orderIndex, widget); - x += roleWidth; - ++orderIndex; - } - - // Draw background without roles - QStyleOption opt; - opt.init(widget); - opt.rect = QRect(x, 0, size().width() - x, size().height()); - opt.state |= QStyle::State_Horizontal; - style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, painter); - - if (!m_movingRole.pixmap.isNull()) { - Q_ASSERT(m_roleOperation == MoveRoleOperation); - painter->drawPixmap(m_movingRole.x, 0, m_movingRole.pixmap); - } -} - -void KItemListHeaderWidget::mousePressEvent(QGraphicsSceneMouseEvent* event) -{ - if (event->button() & Qt::LeftButton) { - updatePressedRoleIndex(event->pos()); - m_pressedMousePos = event->pos(); - m_roleOperation = isAboveRoleGrip(m_pressedMousePos, m_pressedRoleIndex) ? - ResizeRoleOperation : NoRoleOperation; - event->accept(); - } else { - event->ignore(); - } -} - -void KItemListHeaderWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) -{ - QGraphicsWidget::mouseReleaseEvent(event); - - if (m_pressedRoleIndex == -1) { - return; - } - - switch (m_roleOperation) { - case NoRoleOperation: { - // Only a click has been done and no moving or resizing has been started - const QByteArray sortRole = m_model->sortRole(); - const int sortRoleIndex = m_columns.indexOf(sortRole); - if (m_pressedRoleIndex == sortRoleIndex) { - // Toggle the sort order - const Qt::SortOrder previous = m_model->sortOrder(); - const Qt::SortOrder current = (m_model->sortOrder() == Qt::AscendingOrder) ? - Qt::DescendingOrder : Qt::AscendingOrder; - m_model->setSortOrder(current); - emit sortOrderChanged(current, previous); - } else { - // Change the sort role - const QByteArray previous = m_model->sortRole(); - const QByteArray current = m_columns[m_pressedRoleIndex]; - m_model->setSortRole(current); - emit sortRoleChanged(current, previous); - } - break; - } - - case MoveRoleOperation: - m_movingRole.pixmap = QPixmap(); - m_movingRole.x = 0; - m_movingRole.xDec = 0; - m_movingRole.index = -1; - break; - - default: - break; - } - - m_pressedRoleIndex = -1; - m_roleOperation = NoRoleOperation; - update(); - - QApplication::restoreOverrideCursor(); -} - -void KItemListHeaderWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* event) -{ - QGraphicsWidget::mouseMoveEvent(event); - - switch (m_roleOperation) { - case NoRoleOperation: - if ((event->pos() - m_pressedMousePos).manhattanLength() >= QApplication::startDragDistance()) { - // A role gets dragged by the user. Create a pixmap of the role that will get - // synchronized on each furter mouse-move-event with the mouse-position. - m_roleOperation = MoveRoleOperation; - const int roleIndex = roleIndexAt(m_pressedMousePos); - m_movingRole.index = roleIndex; - if (roleIndex == 0) { - // TODO: It should be configurable whether moving the first role is allowed. - // In the context of Dolphin this is not required, however this should be - // changed if KItemViews are used in a more generic way. - QApplication::setOverrideCursor(QCursor(Qt::ForbiddenCursor)); - } else { - m_movingRole.pixmap = createRolePixmap(roleIndex); - - qreal roleX = -m_offset; - for (int i = 0; i < roleIndex; ++i) { - const QByteArray role = m_columns[i]; - roleX += m_columnWidths.value(role); - } - - m_movingRole.xDec = event->pos().x() - roleX; - m_movingRole.x = roleX; - update(); - } - } - break; - - case ResizeRoleOperation: { - const QByteArray pressedRole = m_columns[m_pressedRoleIndex]; - - qreal previousWidth = m_columnWidths.value(pressedRole); - qreal currentWidth = previousWidth; - currentWidth += event->pos().x() - event->lastPos().x(); - currentWidth = qMax(minimumColumnWidth(), currentWidth); - - m_columnWidths.insert(pressedRole, currentWidth); - update(); - - emit columnWidthChanged(pressedRole, currentWidth, previousWidth); - break; - } - - case MoveRoleOperation: { - // TODO: It should be configurable whether moving the first role is allowed. - // In the context of Dolphin this is not required, however this should be - // changed if KItemViews are used in a more generic way. - if (m_movingRole.index > 0) { - m_movingRole.x = event->pos().x() - m_movingRole.xDec; - update(); - - const int targetIndex = targetOfMovingRole(); - if (targetIndex > 0 && targetIndex != m_movingRole.index) { - const QByteArray role = m_columns[m_movingRole.index]; - const int previousIndex = m_movingRole.index; - m_movingRole.index = targetIndex; - emit columnMoved(role, targetIndex, previousIndex); - - m_movingRole.xDec = event->pos().x() - roleXPosition(role); - } - } - break; - } - - default: - break; - } -} - -void KItemListHeaderWidget::hoverEnterEvent(QGraphicsSceneHoverEvent* event) -{ - QGraphicsWidget::hoverEnterEvent(event); - updateHoveredRoleIndex(event->pos()); -} - -void KItemListHeaderWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent* event) -{ - QGraphicsWidget::hoverLeaveEvent(event); - if (m_hoveredRoleIndex != -1) { - m_hoveredRoleIndex = -1; - update(); - } -} - -void KItemListHeaderWidget::hoverMoveEvent(QGraphicsSceneHoverEvent* event) -{ - QGraphicsWidget::hoverMoveEvent(event); - - const QPointF& pos = event->pos(); - updateHoveredRoleIndex(pos); - if (m_hoveredRoleIndex >= 0 && isAboveRoleGrip(pos, m_hoveredRoleIndex)) { - setCursor(Qt::SplitHCursor); - } else { - unsetCursor(); - } -} - -void KItemListHeaderWidget::slotSortRoleChanged(const QByteArray& current, const QByteArray& previous) -{ - Q_UNUSED(current); - Q_UNUSED(previous); - update(); -} - -void KItemListHeaderWidget::slotSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous) -{ - Q_UNUSED(current); - Q_UNUSED(previous); - update(); -} - -void KItemListHeaderWidget::paintRole(QPainter* painter, - const QByteArray& role, - const QRectF& rect, - int orderIndex, - QWidget* widget) const -{ - // The following code is based on the code from QHeaderView::paintSection(). - // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). - QStyleOptionHeader option; - option.section = orderIndex; - option.state = QStyle::State_None | QStyle::State_Raised | QStyle::State_Horizontal; - if (isEnabled()) { - option.state |= QStyle::State_Enabled; - } - if (window() && window()->isActiveWindow()) { - option.state |= QStyle::State_Active; - } - if (m_hoveredRoleIndex == orderIndex) { - option.state |= QStyle::State_MouseOver; - } - if (m_pressedRoleIndex == orderIndex) { - option.state |= QStyle::State_Sunken; - } - if (m_model->sortRole() == role) { - option.sortIndicator = (m_model->sortOrder() == Qt::AscendingOrder) ? - QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp; - } - option.rect = rect.toRect(); - - if (m_columns.count() == 1) { - option.position = QStyleOptionHeader::OnlyOneSection; - } else if (orderIndex == 0) { - option.position = QStyleOptionHeader::Beginning; - } else if (orderIndex == m_columns.count() - 1) { - option.position = QStyleOptionHeader::End; - } else { - option.position = QStyleOptionHeader::Middle; - } - - option.orientation = Qt::Horizontal; - option.selectedPosition = QStyleOptionHeader::NotAdjacent; - option.text = m_model->roleDescription(role); - - style()->drawControl(QStyle::CE_Header, &option, painter, widget); -} - -void KItemListHeaderWidget::updatePressedRoleIndex(const QPointF& pos) -{ - const int pressedIndex = roleIndexAt(pos); - if (m_pressedRoleIndex != pressedIndex) { - m_pressedRoleIndex = pressedIndex; - update(); - } -} - -void KItemListHeaderWidget::updateHoveredRoleIndex(const QPointF& pos) -{ - const int hoverIndex = roleIndexAt(pos); - if (m_hoveredRoleIndex != hoverIndex) { - m_hoveredRoleIndex = hoverIndex; - update(); - } -} - -int KItemListHeaderWidget::roleIndexAt(const QPointF& pos) const -{ - int index = -1; - - qreal x = -m_offset; - foreach (const QByteArray& role, m_columns) { - ++index; - x += m_columnWidths.value(role); - if (pos.x() <= x) { - break; - } - } - - return index; -} - -bool KItemListHeaderWidget::isAboveRoleGrip(const QPointF& pos, int roleIndex) const -{ - qreal x = -m_offset; - for (int i = 0; i <= roleIndex; ++i) { - const QByteArray role = m_columns[i]; - x += m_columnWidths.value(role); - } - - const int grip = style()->pixelMetric(QStyle::PM_HeaderGripMargin); - return pos.x() >= (x - grip) && pos.x() <= x; -} - -QPixmap KItemListHeaderWidget::createRolePixmap(int roleIndex) const -{ - const QByteArray role = m_columns[roleIndex]; - const qreal roleWidth = m_columnWidths.value(role); - const QRect rect(0, 0, roleWidth, size().height()); - - QImage image(rect.size(), QImage::Format_ARGB32_Premultiplied); - - QPainter painter(&image); - paintRole(&painter, role, rect, roleIndex); - - // Apply a highlighting-color - const QPalette::ColorGroup group = isActiveWindow() ? QPalette::Active : QPalette::Inactive; - QColor highlightColor = palette().color(group, QPalette::Highlight); - highlightColor.setAlpha(64); - painter.fillRect(rect, highlightColor); - - // Make the image transparent - painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); - painter.fillRect(0, 0, image.width(), image.height(), QColor(0, 0, 0, 192)); - - return QPixmap::fromImage(image); -} - -int KItemListHeaderWidget::targetOfMovingRole() const -{ - const int movingWidth = m_movingRole.pixmap.width(); - const int movingLeft = m_movingRole.x; - const int movingRight = movingLeft + movingWidth - 1; - - int targetIndex = 0; - qreal targetLeft = -m_offset; - while (targetIndex < m_columns.count()) { - const QByteArray role = m_columns[targetIndex]; - const qreal targetWidth = m_columnWidths.value(role); - const qreal targetRight = targetLeft + targetWidth - 1; - - const bool isInTarget = (targetWidth >= movingWidth && - movingLeft >= targetLeft && - movingRight <= targetRight) || - (targetWidth < movingWidth && - movingLeft <= targetLeft && - movingRight >= targetRight); - - if (isInTarget) { - return targetIndex; - } - - targetLeft += targetWidth; - ++targetIndex; - } - - return m_movingRole.index; -} - -qreal KItemListHeaderWidget::roleXPosition(const QByteArray& role) const -{ - qreal x = -m_offset; - foreach (const QByteArray& visibleRole, m_columns) { - if (visibleRole == role) { - return x; - } - - x += m_columnWidths.value(visibleRole); - } - - return -1; -} - -#include "kitemlistheaderwidget_p.moc" diff --git a/src/kitemviews/kitemlistheaderwidget_p.h b/src/kitemviews/kitemlistheaderwidget_p.h deleted file mode 100644 index f8bba977b..000000000 --- a/src/kitemviews/kitemlistheaderwidget_p.h +++ /dev/null @@ -1,171 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef KITEMLISTHEADERWIDGET_H -#define KITEMLISTHEADERWIDGET_H - -#include -#include -#include -#include - -class KItemModelBase; - -/** - * @brief Widget the implements the header for KItemListView showing the currently used roles. - * - * The widget is an internal API, the user of KItemListView may only access the - * class KItemListHeader. - */ -class LIBDOLPHINPRIVATE_EXPORT KItemListHeaderWidget : public QGraphicsWidget -{ - Q_OBJECT - -public: - KItemListHeaderWidget(QGraphicsWidget* parent = 0); - virtual ~KItemListHeaderWidget(); - - void setModel(KItemModelBase* model); - KItemModelBase* model() const; - - void setAutomaticColumnResizing(bool automatic); - bool automaticColumnResizing() const; - - void setColumns(const QList& roles); - QList columns() const; - - void setColumnWidth(const QByteArray& role, qreal width); - qreal columnWidth(const QByteArray& role) const; - - /** - * Sets the column-width that is required to show the role unclipped. - */ - void setPreferredColumnWidth(const QByteArray& role, qreal width); - qreal preferredColumnWidth(const QByteArray& role) const; - - void setOffset(qreal offset); - qreal offset() const; - - qreal minimumColumnWidth() const; - - virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0); - -signals: - /** - * Is emitted if the width of a visible role has been adjusted by the user with the mouse - * (no signal is emitted if KItemListHeader::setVisibleRoleWidth() is invoked). - */ - void columnWidthChanged(const QByteArray& role, - qreal currentWidth, - qreal previousWidth); - - /** - * Is emitted if the position of the column has been changed. - */ - void columnMoved(const QByteArray& role, int currentIndex, int previousIndex); - - /** - * Is emitted if the user has changed the sort order by clicking on a - * header item. The sort order of the model has already been adjusted to - * the current sort order. Note that no signal will be emitted if the - * sort order of the model has been changed without user interaction. - */ - void sortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous); - - /** - * Is emitted if the user has changed the sort role by clicking on a - * header item. The sort role of the model has already been adjusted to - * the current sort role. Note that no signal will be emitted if the - * sort role of the model has been changed without user interaction. - */ - void sortRoleChanged(const QByteArray& current, const QByteArray& previous); - -protected: - virtual void mousePressEvent(QGraphicsSceneMouseEvent* event); - virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent* event); - virtual void mouseMoveEvent(QGraphicsSceneMouseEvent* event); - virtual void hoverEnterEvent(QGraphicsSceneHoverEvent* event); - virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent* event); - virtual void hoverMoveEvent(QGraphicsSceneHoverEvent* event); - -private slots: - void slotSortRoleChanged(const QByteArray& current, const QByteArray& previous); - void slotSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous); - -private: - void paintRole(QPainter* painter, - const QByteArray& role, - const QRectF& rect, - int orderIndex, - QWidget* widget = 0) const; - - void updatePressedRoleIndex(const QPointF& pos); - void updateHoveredRoleIndex(const QPointF& pos); - int roleIndexAt(const QPointF& pos) const; - bool isAboveRoleGrip(const QPointF& pos, int roleIndex) const; - - /** - * Creates a pixmap of the role with the index \a roleIndex that is shown - * during moving a role. - */ - QPixmap createRolePixmap(int roleIndex) const; - - /** - * @return Target index of the currently moving visible role based on the current - * state of m_movingRole. - */ - int targetOfMovingRole() const; - - /** - * @return x-position of the left border of the role \a role. - */ - qreal roleXPosition(const QByteArray& role) const; - -private: - enum RoleOperation - { - NoRoleOperation, - ResizeRoleOperation, - MoveRoleOperation - }; - - bool m_automaticColumnResizing; - KItemModelBase* m_model; - qreal m_offset; - QList m_columns; - QHash m_columnWidths; - QHash m_preferredColumnWidths; - - int m_hoveredRoleIndex; - int m_pressedRoleIndex; - RoleOperation m_roleOperation; - QPointF m_pressedMousePos; - - struct MovingRole - { - QPixmap pixmap; - int x; - int xDec; - int index; - } m_movingRole; -}; - -#endif - - diff --git a/src/kitemviews/kitemlistkeyboardsearchmanager.cpp b/src/kitemviews/kitemlistkeyboardsearchmanager.cpp deleted file mode 100644 index f4dc1a547..000000000 --- a/src/kitemviews/kitemlistkeyboardsearchmanager.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Tirtha Chatterjee * - * * - * Based on the Itemviews NG project from Trolltech Labs: * - * http://qt.gitorious.org/qt-labs/itemviews-ng * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "kitemlistkeyboardsearchmanager_p.h" - -#include -#include - -#include - -KItemListKeyboardSearchManager::KItemListKeyboardSearchManager(QObject* parent) : - QObject(parent), - m_timeout(5000) -{ - m_keyboardInputTime.invalidate(); -} - -KItemListKeyboardSearchManager::~KItemListKeyboardSearchManager() -{ -} - -void KItemListKeyboardSearchManager::addKeys(const QString& keys) -{ - const bool keyboardTimeWasValid = m_keyboardInputTime.isValid(); - const qint64 keyboardInputTimeElapsed = m_keyboardInputTime.restart(); - if (keyboardInputTimeElapsed > m_timeout || !keyboardTimeWasValid || keys.isEmpty()) { - m_searchedString.clear(); - } - - const bool newSearch = m_searchedString.isEmpty(); - - if (!keys.isEmpty()) { - m_searchedString.append(keys); - - // Special case: - // If the same key is pressed repeatedly, the next item matching that key should be highlighted - const QChar firstKey = m_searchedString.length() > 0 ? m_searchedString.at(0) : QChar(); - const bool sameKey = m_searchedString.length() > 1 && m_searchedString.count(firstKey) == m_searchedString.length(); - - // Searching for a matching item should start from the next item if either - // 1. a new search is started, or - // 2. a 'repeated key' search is done. - const bool searchFromNextItem = newSearch || sameKey; - - emit changeCurrentItem(sameKey ? firstKey : m_searchedString, searchFromNextItem); - } - m_keyboardInputTime.start(); -} - -void KItemListKeyboardSearchManager::setTimeout(qint64 milliseconds) -{ - m_timeout = milliseconds; -} - -qint64 KItemListKeyboardSearchManager::timeout() const -{ - return m_timeout; -} - diff --git a/src/kitemviews/kitemlistkeyboardsearchmanager_p.h b/src/kitemviews/kitemlistkeyboardsearchmanager_p.h deleted file mode 100644 index d6a6686db..000000000 --- a/src/kitemviews/kitemlistkeyboardsearchmanager_p.h +++ /dev/null @@ -1,81 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Tirtha Chatterjee * - * * - * Based on the Itemviews NG project from Trolltech Labs: * - * http://qt.gitorious.org/qt-labs/itemviews-ng * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef KITEMLISTKEYBOARDMANAGER_H -#define KITEMLISTKEYBOARDMANAGER_H - -#include - -#include -#include -#include - -/** - * @brief Controls the keyboard searching ability for a KItemListController. - * - * @see KItemListController - * @see KItemModelBase - */ -class LIBDOLPHINPRIVATE_EXPORT KItemListKeyboardSearchManager : public QObject -{ - Q_OBJECT - -public: - - KItemListKeyboardSearchManager(QObject* parent = 0); - virtual ~KItemListKeyboardSearchManager(); - - /** - * Add \a keys to the text buffer used for searching. - */ - void addKeys(const QString& keys); - - /** - * Sets the delay after which the search is cancelled to \a milliseconds. - * If the time interval between two calls of addKeys(const QString&) is - * larger than this, the second call will start a new search, rather than - * combining the keys received from both calls to a single search string. - */ - void setTimeout(qint64 milliseconds); - qint64 timeout() const; - -signals: - /** - * Is emitted if the current item should be changed corresponding - * to \a text. - * @param searchFromNextItem If true start searching from item next to the - * current item. Otherwise, search from the - * current item. - */ - // TODO: Think about getting rid of the bool parameter - // (see http://doc.qt.nokia.com/qq/qq13-apis.html#thebooleanparametertrap) - void changeCurrentItem(const QString& string, bool searchFromNextItem); - -private: - QString m_searchedString; - QElapsedTimer m_keyboardInputTime; - qint64 m_timeout; -}; - -#endif - - diff --git a/src/kitemviews/kitemlistrubberband.cpp b/src/kitemviews/kitemlistrubberband.cpp deleted file mode 100644 index c1f276cdf..000000000 --- a/src/kitemviews/kitemlistrubberband.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "kitemlistrubberband_p.h" - -KItemListRubberBand::KItemListRubberBand(QObject* parent) : - QObject(parent), - m_active(false), - m_startPos(), - m_endPos() -{ -} - -KItemListRubberBand::~KItemListRubberBand() -{ -} - -void KItemListRubberBand::setStartPosition(const QPointF& pos) -{ - if (m_startPos != pos) { - const QPointF previous = m_startPos; - m_startPos = pos; - emit startPositionChanged(m_startPos, previous); - } -} - -QPointF KItemListRubberBand::startPosition() const -{ - return m_startPos; -} - -void KItemListRubberBand::setEndPosition(const QPointF& pos) -{ - if (m_endPos != pos) { - const QPointF previous = m_endPos; - m_endPos = pos; - emit endPositionChanged(m_endPos, previous); - } -} - -QPointF KItemListRubberBand::endPosition() const -{ - return m_endPos; -} - -void KItemListRubberBand::setActive(bool active) -{ - if (m_active != active) { - m_active = active; - emit activationChanged(active); - } -} - -bool KItemListRubberBand::isActive() const -{ - return m_active; -} - -#include "kitemlistrubberband_p.moc" diff --git a/src/kitemviews/kitemlistrubberband_p.h b/src/kitemviews/kitemlistrubberband_p.h deleted file mode 100644 index aea58af46..000000000 --- a/src/kitemviews/kitemlistrubberband_p.h +++ /dev/null @@ -1,60 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef KITEMLISTRUBBERBAND_H -#define KITEMLISTRUBBERBAND_H - -#include -#include -#include - -/** - * @brief Manages the rubberband when selecting items. - */ -class LIBDOLPHINPRIVATE_EXPORT KItemListRubberBand : public QObject -{ - Q_OBJECT - -public: - explicit KItemListRubberBand(QObject* parent = 0); - virtual ~KItemListRubberBand(); - - void setStartPosition(const QPointF& pos); - QPointF startPosition() const; - - void setEndPosition(const QPointF& pos); - QPointF endPosition() const; - - void setActive(bool active); - bool isActive() const; - -signals: - void activationChanged(bool active); - void startPositionChanged(const QPointF& current, const QPointF& previous); - void endPositionChanged(const QPointF& current, const QPointF& previous); - -private: - bool m_active; - QPointF m_startPos; - QPointF m_endPos; -}; - -#endif - - diff --git a/src/kitemviews/kitemlistselectiontoggle.cpp b/src/kitemviews/kitemlistselectiontoggle.cpp deleted file mode 100644 index 014f65b40..000000000 --- a/src/kitemviews/kitemlistselectiontoggle.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "kitemlistselectiontoggle_p.h" - -#include -#include -#include - -#include - -KItemListSelectionToggle::KItemListSelectionToggle(QGraphicsItem* parent) : - QGraphicsWidget(parent, 0), - m_checked(false), - m_hovered(false) -{ - setAcceptHoverEvents(true); -} - -KItemListSelectionToggle::~KItemListSelectionToggle() -{ -} - -void KItemListSelectionToggle::setChecked(bool checked) -{ - if (m_checked != checked) { - m_checked = checked; - m_pixmap = QPixmap(); - update(); - } -} - -bool KItemListSelectionToggle::isChecked() const -{ - return m_checked; -} - -void KItemListSelectionToggle::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) -{ - Q_UNUSED(option); - Q_UNUSED(widget); - - if (m_pixmap.isNull()) { - updatePixmap(); - } - - const qreal x = (size().width() - qreal(m_pixmap.width())) / 2; - const qreal y = (size().height() - qreal(m_pixmap.height())) / 2; - 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::updatePixmap() -{ - const char* icon = m_checked ? "list-remove" : "list-add"; - - int iconSize = qMin(size().width(), size().height()); - if (iconSize < KIconLoader::SizeSmallMedium) { - iconSize = KIconLoader::SizeSmall; - } else if (iconSize < KIconLoader::SizeMedium) { - iconSize = KIconLoader::SizeSmallMedium; - } else if (iconSize < KIconLoader::SizeLarge) { - iconSize = KIconLoader::SizeMedium; - } else if (iconSize < KIconLoader::SizeHuge) { - iconSize = KIconLoader::SizeLarge; - } else if (iconSize < KIconLoader::SizeEnormous) { - iconSize = KIconLoader::SizeHuge; - } - - m_pixmap = KIconLoader::global()->loadIcon(QLatin1String(icon), KIconLoader::NoGroup, iconSize); - - if (m_hovered) { - KIconLoader::global()->iconEffect()->apply(m_pixmap, KIconLoader::Desktop, KIconLoader::ActiveState); - } -} - -#include "kitemlistselectiontoggle_p.moc" diff --git a/src/kitemviews/kitemlistselectiontoggle_p.h b/src/kitemviews/kitemlistselectiontoggle_p.h deleted file mode 100644 index a8050d811..000000000 --- a/src/kitemviews/kitemlistselectiontoggle_p.h +++ /dev/null @@ -1,61 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef KITEMLISTSELECTIONTOGGLE_H -#define KITEMLISTSELECTIONTOGGLE_H - -#include - -#include -#include - -class QPropertyAnimation; - -/** - * @brief Allows to toggle between the selected and unselected state of an item. - */ -class LIBDOLPHINPRIVATE_EXPORT KItemListSelectionToggle : public QGraphicsWidget -{ - Q_OBJECT - -public: - KItemListSelectionToggle(QGraphicsItem* parent); - virtual ~KItemListSelectionToggle(); - - void setChecked(bool checked); - bool isChecked() const; - - virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0); - -protected: - virtual void hoverEnterEvent(QGraphicsSceneHoverEvent* event); - virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent* event); - -private: - void updatePixmap(); - -private: - bool m_checked; - bool m_hovered; - QPixmap m_pixmap; -}; - -#endif - - diff --git a/src/kitemviews/kitemlistsizehintresolver.cpp b/src/kitemviews/kitemlistsizehintresolver.cpp deleted file mode 100644 index 0520fac04..000000000 --- a/src/kitemviews/kitemlistsizehintresolver.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "kitemlistsizehintresolver_p.h" - -#include -#include - -KItemListSizeHintResolver::KItemListSizeHintResolver(const KItemListView* itemListView) : - m_itemListView(itemListView), - m_sizeHintCache() -{ -} - -KItemListSizeHintResolver::~KItemListSizeHintResolver() -{ -} - -QSizeF KItemListSizeHintResolver::sizeHint(int index) const -{ - QSizeF size = m_sizeHintCache.at(index); - if (size.isEmpty()) { - size = m_itemListView->itemSizeHint(index); - m_sizeHintCache[index] = size; - } - return size; -} - -void KItemListSizeHintResolver::itemsInserted(int index, int count) -{ - const int currentCount = m_sizeHintCache.count(); - m_sizeHintCache.reserve(currentCount + count); - while (count > 0) { - m_sizeHintCache.insert(index, QSizeF()); - ++index; - --count; - } -} - -void KItemListSizeHintResolver::itemsRemoved(int index, int count) -{ - const QList::iterator begin = m_sizeHintCache.begin() + index; - const QList::iterator end = begin + count; - m_sizeHintCache.erase(begin, end); -} - -void KItemListSizeHintResolver::itemsMoved(int index, int count) -{ - while (count) { - m_sizeHintCache[index] = QSizeF(); - ++index; - --count; - } -} - -void KItemListSizeHintResolver::itemsChanged(int index, int count, const QSet& roles) -{ - Q_UNUSED(roles); - while (count) { - m_sizeHintCache[index] = QSizeF(); - ++index; - --count; - } -} - -void KItemListSizeHintResolver::clearCache() -{ - const int count = m_sizeHintCache.count(); - for (int i = 0; i < count; ++i) { - m_sizeHintCache[i] = QSizeF(); - } -} diff --git a/src/kitemviews/kitemlistsizehintresolver_p.h b/src/kitemviews/kitemlistsizehintresolver_p.h deleted file mode 100644 index 1345e0321..000000000 --- a/src/kitemviews/kitemlistsizehintresolver_p.h +++ /dev/null @@ -1,53 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef KITEMLISTSIZEHINTRESOLVER_H -#define KITEMLISTSIZEHINTRESOLVER_H - -#include - -#include -#include -#include - -class KItemListView; - -/** - * @brief Calculates and caches the sizehints of items in KItemListView. - */ -class LIBDOLPHINPRIVATE_EXPORT KItemListSizeHintResolver -{ -public: - KItemListSizeHintResolver(const KItemListView* itemListView); - virtual ~KItemListSizeHintResolver(); - QSizeF sizeHint(int index) const; - - void itemsInserted(int index, int count); - void itemsRemoved(int index, int count); - void itemsMoved(int index, int count); - void itemsChanged(int index, int count, const QSet& roles); - - void clearCache(); - -private: - const KItemListView* m_itemListView; - mutable QList m_sizeHintCache; -}; - -#endif diff --git a/src/kitemviews/kitemlistsmoothscroller.cpp b/src/kitemviews/kitemlistsmoothscroller.cpp deleted file mode 100644 index 80f7f2883..000000000 --- a/src/kitemviews/kitemlistsmoothscroller.cpp +++ /dev/null @@ -1,207 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "kitemlistsmoothscroller_p.h" - -#include -#include -#include -#include -#include - -#include - -KItemListSmoothScroller::KItemListSmoothScroller(QScrollBar* scrollBar, - QObject* parent) : - QObject(parent), - m_scrollBarPressed(false), - m_smoothScrolling(true), - m_scrollBar(scrollBar), - m_animation(0) -{ - m_animation = new QPropertyAnimation(this); - const int duration = (KGlobalSettings::graphicEffectsLevel() == KGlobalSettings::NoEffects) ? 1 : 100; - m_animation->setDuration(duration); - connect(m_animation, SIGNAL(stateChanged(QAbstractAnimation::State,QAbstractAnimation::State)), - this, SLOT(slotAnimationStateChanged(QAbstractAnimation::State,QAbstractAnimation::State))); - - m_scrollBar->installEventFilter(this); -} - -KItemListSmoothScroller::~KItemListSmoothScroller() -{ -} - -void KItemListSmoothScroller::setScrollBar(QScrollBar *scrollBar) -{ - m_scrollBar = scrollBar; -} - -QScrollBar* KItemListSmoothScroller::scrollBar() const -{ - return m_scrollBar; -} - -void KItemListSmoothScroller::setTargetObject(QObject* target) -{ - m_animation->setTargetObject(target); -} - -QObject* KItemListSmoothScroller::targetObject() const -{ - return m_animation->targetObject(); -} - -void KItemListSmoothScroller::setPropertyName(const QByteArray& propertyName) -{ - m_animation->setPropertyName(propertyName); -} - -QByteArray KItemListSmoothScroller::propertyName() const -{ - return m_animation->propertyName(); -} - -void KItemListSmoothScroller::scrollContentsBy(qreal distance) -{ - QObject* target = targetObject(); - if (!target) { - return; - } - - const QByteArray name = propertyName(); - const qreal currentOffset = target->property(name).toReal(); - if (static_cast(currentOffset) == m_scrollBar->value()) { - // The current offset is already synchronous to the scrollbar - return; - } - - const bool animRunning = (m_animation->state() == QAbstractAnimation::Running); - if (animRunning) { - // Stopping a running animation means skipping the range from the current offset - // until the target offset. To prevent skipping of the range the difference - // is added to the new target offset. - const qreal oldEndOffset = m_animation->endValue().toReal(); - distance += (currentOffset - oldEndOffset); - } - - const qreal endOffset = currentOffset - distance; - if (m_smoothScrolling || animRunning) { - qreal startOffset = currentOffset; - if (animRunning) { - // If the animation was running and has been interrupted by assigning a new end-offset - // one frame must be added to the start-offset to keep the animation smooth. This also - // assures that animation proceeds even in cases where new end-offset are triggered - // within a very short timeslots. - startOffset += (endOffset - currentOffset) * 1000 / (m_animation->duration() * 60); - if (currentOffset < endOffset) { - startOffset = qMin(startOffset, endOffset); - } else { - startOffset = qMax(startOffset, endOffset); - } - } - - m_animation->stop(); - m_animation->setStartValue(startOffset); - m_animation->setEndValue(endOffset); - m_animation->setEasingCurve(animRunning ? QEasingCurve::OutQuad : QEasingCurve::InOutQuad); - m_animation->start(); - target->setProperty(name, startOffset); - } else { - target->setProperty(name, endOffset); - } -} - -void KItemListSmoothScroller::scrollTo(qreal position) -{ - m_smoothScrolling = true; - m_scrollBar->setValue(position); -} - -bool KItemListSmoothScroller::requestScrollBarUpdate(int newMaximum) -{ - if (m_animation->state() == QAbstractAnimation::Running) { - if (newMaximum == m_scrollBar->maximum()) { - // The value has been changed by the animation, no update - // of the scrollbars is required as their target state will be - // reached with the end of the animation. - return false; - } - - // The maximum has been changed which indicates that the content - // of the view has been changed. Stop the animation in any case and - // update the scrollbars immediately. - m_animation->stop(); - } - return true; -} - -bool KItemListSmoothScroller::eventFilter(QObject* obj, QEvent* event) -{ - Q_ASSERT(obj == m_scrollBar); - - switch (event->type()) { - case QEvent::MouseButtonPress: - m_scrollBarPressed = true; - m_smoothScrolling = true; - break; - - case QEvent::MouseButtonRelease: - m_scrollBarPressed = false; - m_smoothScrolling = false; - break; - - case QEvent::Wheel: - handleWheelEvent(static_cast(event)); - break; - - default: - break; - } - - return QObject::eventFilter(obj, event); -} - -void KItemListSmoothScroller::slotAnimationStateChanged(QAbstractAnimation::State newState, - QAbstractAnimation::State oldState) -{ - Q_UNUSED(oldState); - if (newState == QAbstractAnimation::Stopped && m_smoothScrolling && !m_scrollBarPressed) { - m_smoothScrolling = false; - } -} - -void KItemListSmoothScroller::handleWheelEvent(QWheelEvent* event) -{ - const int numDegrees = event->delta() / 8; - const int numSteps = numDegrees / 15; - - const bool previous = m_smoothScrolling; - - m_smoothScrolling = true; - const int value = m_scrollBar->value(); - const int pageStep = m_scrollBar->pageStep(); - m_scrollBar->setValue(value - numSteps * pageStep); - - m_smoothScrolling = previous; - - event->accept(); -} - -#include "kitemlistsmoothscroller_p.moc" diff --git a/src/kitemviews/kitemlistsmoothscroller_p.h b/src/kitemviews/kitemlistsmoothscroller_p.h deleted file mode 100644 index 252c966c7..000000000 --- a/src/kitemviews/kitemlistsmoothscroller_p.h +++ /dev/null @@ -1,103 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef KITEMLISTSMOOTHSCROLLER_H -#define KITEMLISTSMOOTHSCROLLER_H - -#include - -#include -#include - -class QPropertyAnimation; -class QScrollBar; -class QWheelEvent; - -/** - * @brief Helper class for KItemListContainer to have a smooth - * scrolling when adjusting the scrollbars. - */ -class LIBDOLPHINPRIVATE_EXPORT KItemListSmoothScroller : public QObject -{ - Q_OBJECT - -public: - KItemListSmoothScroller(QScrollBar* scrollBar, - QObject* parent = 0); - virtual ~KItemListSmoothScroller(); - - void setScrollBar(QScrollBar* scrollBar); - QScrollBar* scrollBar() const; - - void setTargetObject(QObject* target); - QObject* targetObject() const; - - void setPropertyName(const QByteArray& propertyName); - QByteArray propertyName() const; - - /** - * Adjusts the position of the target by \p distance - * pixels. Is invoked in the context of QAbstractScrollArea::scrollContentsBy() - * where the scrollbars already have the new position but the content - * has not been scrolled yet. - */ - void scrollContentsBy(qreal distance); - - /** - * Does a smooth-scrolling to the position \p position - * on the target and also adjusts the corresponding scrollbar - * to the new position. - */ - void scrollTo(qreal position); - - /** - * Must be invoked before the scrollbar should get updated to have a new - * maximum. True is returned if the new maximum can be applied. If false - * is returned the maximum has already been reached and the value will - * be reached at the end of the animation. - */ - // TODO: This interface is tricky to understand. Try to make this more - // generic/readable if the corresponding code in KItemListContainer got - // stable. - bool requestScrollBarUpdate(int newMaximum); - -protected: - virtual bool eventFilter(QObject* obj, QEvent* event); - -private slots: - void slotAnimationStateChanged(QAbstractAnimation::State newState, - QAbstractAnimation::State oldState); - -private: - /** - * Results into a smooth-scrolling of the target dependent on the direction - * of the wheel event. - */ - void handleWheelEvent(QWheelEvent* event); - -private: - bool m_scrollBarPressed; - bool m_smoothScrolling; - QScrollBar* m_scrollBar; - QPropertyAnimation* m_animation; -}; - -#endif - - diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp index 1e68c2bd2..732ed24e4 100644 --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -24,14 +24,15 @@ #include "kitemlistcontroller.h" #include "kitemlistheader.h" -#include "kitemlistheaderwidget_p.h" -#include "kitemlistrubberband_p.h" #include "kitemlistselectionmanager.h" -#include "kitemlistsizehintresolver_p.h" -#include "kitemlistviewlayouter_p.h" -#include "kitemlistviewanimation_p.h" #include "kitemlistwidget.h" +#include "private/kitemlistheaderwidget.h" +#include "private/kitemlistrubberband.h" +#include "private/kitemlistsizehintresolver.h" +#include "private/kitemlistviewlayouter.h" +#include "private/kitemlistviewanimation.h" + #include #include diff --git a/src/kitemviews/kitemlistview.h b/src/kitemviews/kitemlistview.h index d65ece8e2..a3c11a6bf 100644 --- a/src/kitemviews/kitemlistview.h +++ b/src/kitemviews/kitemlistview.h @@ -27,9 +27,9 @@ #include #include -#include #include #include +#include #include #include diff --git a/src/kitemviews/kitemlistviewanimation.cpp b/src/kitemviews/kitemlistviewanimation.cpp deleted file mode 100644 index 9184b7144..000000000 --- a/src/kitemviews/kitemlistviewanimation.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "kitemlistviewanimation_p.h" - -#include "kitemlistview.h" - -#include -#include - -#include -#include - -KItemListViewAnimation::KItemListViewAnimation(QObject* parent) : - QObject(parent), - m_animationDuration(200), - m_scrollOrientation(Qt::Vertical), - m_scrollOffset(0), - m_animation() -{ - if (KGlobalSettings::graphicEffectsLevel() == KGlobalSettings::NoEffects) { - m_animationDuration = 1; - } -} - -KItemListViewAnimation::~KItemListViewAnimation() -{ - for (int type = 0; type < AnimationTypeCount; ++type) { - qDeleteAll(m_animation[type]); - } -} - -void KItemListViewAnimation::setScrollOrientation(Qt::Orientation orientation) -{ - m_scrollOrientation = orientation; -} - -Qt::Orientation KItemListViewAnimation::scrollOrientation() const -{ - return m_scrollOrientation; -} - -void KItemListViewAnimation::setScrollOffset(qreal offset) -{ - const qreal diff = m_scrollOffset - offset; - m_scrollOffset = offset; - - // The change of the offset requires that the position of all - // animated QGraphicsWidgets get adjusted. An exception is made - // for the delete animation that should just fade away on the - // existing position. - for (int type = 0; type < AnimationTypeCount; ++type) { - if (type == DeleteAnimation) { - continue; - } - - QHashIterator it(m_animation[type]); - while (it.hasNext()) { - it.next(); - - QGraphicsWidget* widget = it.key(); - QPropertyAnimation* propertyAnim = it.value(); - - QPointF currentPos = widget->pos(); - if (m_scrollOrientation == Qt::Vertical) { - currentPos.ry() += diff; - } else { - currentPos.rx() += diff; - } - - if (type == MovingAnimation) { - // Stop the animation, calculate the moved start- and end-value - // and restart the animation for the remaining duration. - const int remainingDuration = propertyAnim->duration() - - propertyAnim->currentTime(); - - const bool block = propertyAnim->signalsBlocked(); - propertyAnim->blockSignals(true); - propertyAnim->stop(); - - QPointF endPos = propertyAnim->endValue().toPointF(); - if (m_scrollOrientation == Qt::Vertical) { - endPos.ry() += diff; - } else { - endPos.rx() += diff; - } - - propertyAnim->setDuration(remainingDuration); - propertyAnim->setStartValue(currentPos); - propertyAnim->setEndValue(endPos); - propertyAnim->start(); - propertyAnim->blockSignals(block); - } else { - widget->setPos(currentPos); - } - } - } -} - -qreal KItemListViewAnimation::scrollOffset() const -{ - return m_scrollOffset; -} - -void KItemListViewAnimation::start(QGraphicsWidget* widget, AnimationType type, const QVariant& endValue) -{ - stop(widget, type); - - QPropertyAnimation* propertyAnim = 0; - - switch (type) { - case MovingAnimation: { - const QPointF newPos = endValue.toPointF(); - if (newPos == widget->pos()) { - return; - } - - propertyAnim = new QPropertyAnimation(widget, "pos"); - propertyAnim->setDuration(m_animationDuration); - propertyAnim->setEndValue(newPos); - break; - } - - case CreateAnimation: { - propertyAnim = new QPropertyAnimation(widget, "opacity"); - propertyAnim->setEasingCurve(QEasingCurve::InQuart); - propertyAnim->setDuration(m_animationDuration); - propertyAnim->setStartValue(0.0); - propertyAnim->setEndValue(1.0); - break; - } - - case DeleteAnimation: { - propertyAnim = new QPropertyAnimation(widget, "opacity"); - propertyAnim->setEasingCurve(QEasingCurve::OutQuart); - propertyAnim->setDuration(m_animationDuration); - propertyAnim->setStartValue(1.0); - propertyAnim->setEndValue(0.0); - break; - } - - case ResizeAnimation: { - const QSizeF newSize = endValue.toSizeF(); - if (newSize == widget->size()) { - return; - } - - propertyAnim = new QPropertyAnimation(widget, "size"); - propertyAnim->setDuration(m_animationDuration); - propertyAnim->setEndValue(newSize); - break; - } - - default: - break; - } - - Q_ASSERT(propertyAnim); - connect(propertyAnim, SIGNAL(finished()), this, SLOT(slotFinished())); - m_animation[type].insert(widget, propertyAnim); - - propertyAnim->start(); -} - -void KItemListViewAnimation::stop(QGraphicsWidget* widget, AnimationType type) -{ - QPropertyAnimation* propertyAnim = m_animation[type].value(widget); - if (propertyAnim) { - propertyAnim->stop(); - - switch (type) { - case MovingAnimation: break; - case CreateAnimation: widget->setOpacity(1.0); break; - case DeleteAnimation: widget->setOpacity(0.0); break; - case ResizeAnimation: break; - default: break; - } - - m_animation[type].remove(widget); - delete propertyAnim; - - emit finished(widget, type); - } -} - -void KItemListViewAnimation::stop(QGraphicsWidget* widget) -{ - for (int type = 0; type < AnimationTypeCount; ++type) { - stop(widget, static_cast(type)); - } -} - -bool KItemListViewAnimation::isStarted(QGraphicsWidget *widget, AnimationType type) const -{ - return m_animation[type].value(widget); -} - -bool KItemListViewAnimation::isStarted(QGraphicsWidget* widget) const -{ - for (int type = 0; type < AnimationTypeCount; ++type) { - if (isStarted(widget, static_cast(type))) { - return true; - } - } - return false; -} - -void KItemListViewAnimation::slotFinished() -{ - QPropertyAnimation* finishedAnim = qobject_cast(sender()); - for (int type = 0; type < AnimationTypeCount; ++type) { - QHashIterator 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); - finishedAnim->deleteLater(); - - emit finished(widget, static_cast(type)); - return; - } - } - } - Q_ASSERT(false); -} - -#include "kitemlistviewanimation_p.moc" diff --git a/src/kitemviews/kitemlistviewanimation_p.h b/src/kitemviews/kitemlistviewanimation_p.h deleted file mode 100644 index a3aceb0f5..000000000 --- a/src/kitemviews/kitemlistviewanimation_p.h +++ /dev/null @@ -1,106 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef KITEMLISTVIEWANIMATION_H -#define KITEMLISTVIEWANIMATION_H - -#include - -#include -#include -#include - -class KItemListView; -class QGraphicsWidget; -class QPointF; -class QPropertyAnimation; - -/** - * @brief Internal helper class for KItemListView to animate the items. - * - * Supports item animations for moving, creating, deleting and resizing - * an item. Several applications can be applied to one item in parallel. - */ -class LIBDOLPHINPRIVATE_EXPORT KItemListViewAnimation : public QObject -{ - Q_OBJECT - -public: - enum AnimationType { - MovingAnimation, - CreateAnimation, - DeleteAnimation, - ResizeAnimation - }; - - KItemListViewAnimation(QObject* parent = 0); - virtual ~KItemListViewAnimation(); - - void setScrollOrientation(Qt::Orientation orientation); - Qt::Orientation scrollOrientation() const; - - void setScrollOffset(qreal scrollOffset); - qreal scrollOffset() const; - - /** - * Starts the animation of the type \a type for the widget \a widget. If an animation - * of the type is already running, this animation will be stopped before starting - * the new animation. - */ - void start(QGraphicsWidget* widget, AnimationType type, const QVariant& endValue = QVariant()); - - /** - * Stops the animation of the type \a type for the widget \a widget. - */ - void stop(QGraphicsWidget* widget, AnimationType type); - - /** - * Stops all animations that have been applied to the widget \a widget. - */ - void stop(QGraphicsWidget* widget); - - /** - * @return True if the animation of the type \a type has been started - * for the widget \a widget.. - */ - bool isStarted(QGraphicsWidget *widget, AnimationType type) const; - - /** - * @return True if any animation has been started for the widget. - */ - bool isStarted(QGraphicsWidget* widget) const; - -signals: - void finished(QGraphicsWidget* widget, KItemListViewAnimation::AnimationType type); - -private slots: - void slotFinished(); - -private: - enum { AnimationTypeCount = 4 }; - - int m_animationDuration; - Qt::Orientation m_scrollOrientation; - qreal m_scrollOffset; - QHash m_animation[AnimationTypeCount]; -}; - -#endif - - diff --git a/src/kitemviews/kitemlistviewlayouter.cpp b/src/kitemviews/kitemlistviewlayouter.cpp deleted file mode 100644 index 405837d23..000000000 --- a/src/kitemviews/kitemlistviewlayouter.cpp +++ /dev/null @@ -1,630 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "kitemlistviewlayouter_p.h" - -#include "kitemmodelbase.h" -#include "kitemlistsizehintresolver_p.h" - -#include - -// #define KITEMLISTVIEWLAYOUTER_DEBUG - -KItemListViewLayouter::KItemListViewLayouter(QObject* parent) : - QObject(parent), - m_dirty(true), - m_visibleIndexesDirty(true), - m_scrollOrientation(Qt::Vertical), - m_size(), - m_itemSize(128, 128), - m_itemMargin(), - m_headerHeight(0), - m_model(0), - m_sizeHintResolver(0), - m_scrollOffset(0), - m_maximumScrollOffset(0), - m_itemOffset(0), - m_maximumItemOffset(0), - m_firstVisibleIndex(-1), - m_lastVisibleIndex(-1), - m_columnWidth(0), - m_xPosInc(0), - m_columnCount(0), - m_groupItemIndexes(), - m_groupHeaderHeight(0), - m_groupHeaderMargin(0), - m_itemInfos() -{ -} - -KItemListViewLayouter::~KItemListViewLayouter() -{ -} - -void KItemListViewLayouter::setScrollOrientation(Qt::Orientation orientation) -{ - if (m_scrollOrientation != orientation) { - m_scrollOrientation = orientation; - m_dirty = true; - } -} - -Qt::Orientation KItemListViewLayouter::scrollOrientation() const -{ - return m_scrollOrientation; -} - -void KItemListViewLayouter::setSize(const QSizeF& size) -{ - if (m_size != size) { - m_size = size; - m_dirty = true; - } -} - -QSizeF KItemListViewLayouter::size() const -{ - return m_size; -} - -void KItemListViewLayouter::setItemSize(const QSizeF& size) -{ - if (m_itemSize != size) { - m_itemSize = size; - m_dirty = true; - } -} - -QSizeF KItemListViewLayouter::itemSize() const -{ - return m_itemSize; -} - -void KItemListViewLayouter::setItemMargin(const QSizeF& margin) -{ - if (m_itemMargin != margin) { - m_itemMargin = margin; - m_dirty = true; - } -} - -QSizeF KItemListViewLayouter::itemMargin() const -{ - return m_itemMargin; -} - -void KItemListViewLayouter::setHeaderHeight(qreal height) -{ - if (m_headerHeight != height) { - m_headerHeight = height; - m_dirty = true; - } -} - -qreal KItemListViewLayouter::headerHeight() const -{ - return m_headerHeight; -} - -void KItemListViewLayouter::setGroupHeaderHeight(qreal height) -{ - if (m_groupHeaderHeight != height) { - m_groupHeaderHeight = height; - m_dirty = true; - } -} - -qreal KItemListViewLayouter::groupHeaderHeight() const -{ - return m_groupHeaderHeight; -} - -void KItemListViewLayouter::setGroupHeaderMargin(qreal margin) -{ - if (m_groupHeaderMargin != margin) { - m_groupHeaderMargin = margin; - m_dirty = true; - } -} - -qreal KItemListViewLayouter::groupHeaderMargin() const -{ - return m_groupHeaderMargin; -} - -void KItemListViewLayouter::setScrollOffset(qreal offset) -{ - if (m_scrollOffset != offset) { - m_scrollOffset = offset; - m_visibleIndexesDirty = true; - } -} - -qreal KItemListViewLayouter::scrollOffset() const -{ - return m_scrollOffset; -} - -qreal KItemListViewLayouter::maximumScrollOffset() const -{ - const_cast(this)->doLayout(); - return m_maximumScrollOffset; -} - -void KItemListViewLayouter::setItemOffset(qreal offset) -{ - if (m_itemOffset != offset) { - m_itemOffset = offset; - m_visibleIndexesDirty = true; - } -} - -qreal KItemListViewLayouter::itemOffset() const -{ - return m_itemOffset; -} - -qreal KItemListViewLayouter::maximumItemOffset() const -{ - const_cast(this)->doLayout(); - return m_maximumItemOffset; -} - -void KItemListViewLayouter::setModel(const KItemModelBase* model) -{ - if (m_model != model) { - m_model = model; - m_dirty = true; - } -} - -const KItemModelBase* KItemListViewLayouter::model() const -{ - return m_model; -} - -void KItemListViewLayouter::setSizeHintResolver(const KItemListSizeHintResolver* sizeHintResolver) -{ - if (m_sizeHintResolver != sizeHintResolver) { - m_sizeHintResolver = sizeHintResolver; - m_dirty = true; - } -} - -const KItemListSizeHintResolver* KItemListViewLayouter::sizeHintResolver() const -{ - return m_sizeHintResolver; -} - -int KItemListViewLayouter::firstVisibleIndex() const -{ - const_cast(this)->doLayout(); - return m_firstVisibleIndex; -} - -int KItemListViewLayouter::lastVisibleIndex() const -{ - const_cast(this)->doLayout(); - return m_lastVisibleIndex; -} - -QRectF KItemListViewLayouter::itemRect(int index) const -{ - const_cast(this)->doLayout(); - if (index < 0 || index >= m_itemInfos.count()) { - return QRectF(); - } - - if (m_scrollOrientation == Qt::Horizontal) { - // Rotate the logical direction which is always vertical by 90° - // to get the physical horizontal direction - const QRectF& b = m_itemInfos[index].rect; - QRectF bounds(b.y(), b.x(), b.height(), b.width()); - QPointF pos = bounds.topLeft(); - pos.rx() -= m_scrollOffset; - bounds.moveTo(pos); - return bounds; - } - - QRectF bounds = m_itemInfos[index].rect; - bounds.moveTo(bounds.topLeft() - QPointF(m_itemOffset, m_scrollOffset)); - return bounds; -} - -QRectF KItemListViewLayouter::groupHeaderRect(int index) const -{ - const_cast(this)->doLayout(); - - const QRectF firstItemRect = itemRect(index); - QPointF pos = firstItemRect.topLeft(); - if (pos.isNull()) { - return QRectF(); - } - - QSizeF size; - if (m_scrollOrientation == Qt::Vertical) { - pos.rx() = 0; - pos.ry() -= m_groupHeaderHeight; - size = QSizeF(m_size.width(), m_groupHeaderHeight); - } else { - pos.rx() -= m_itemMargin.width(); - pos.ry() = 0; - - // Determine the maximum width used in the - // current column. As the scroll-direction is - // Qt::Horizontal and m_itemRects is accessed directly, - // the logical height represents the visual width. - qreal width = minimumGroupHeaderWidth(); - const qreal y = m_itemInfos[index].rect.y(); - const int maxIndex = m_itemInfos.count() - 1; - while (index <= maxIndex) { - QRectF bounds = m_itemInfos[index].rect; - if (bounds.y() != y) { - break; - } - - if (bounds.height() > width) { - width = bounds.height(); - } - - ++index; - } - - size = QSizeF(width, m_size.height()); - } - return QRectF(pos, size); -} - -int KItemListViewLayouter::itemColumn(int index) const -{ - const_cast(this)->doLayout(); - if (index < 0 || index >= m_itemInfos.count()) { - return -1; - } - - return (m_scrollOrientation == Qt::Vertical) - ? m_itemInfos[index].column - : m_itemInfos[index].row; -} - -int KItemListViewLayouter::itemRow(int index) const -{ - const_cast(this)->doLayout(); - if (index < 0 || index >= m_itemInfos.count()) { - return -1; - } - - return (m_scrollOrientation == Qt::Vertical) - ? m_itemInfos[index].row - : m_itemInfos[index].column; -} - -int KItemListViewLayouter::maximumVisibleItems() const -{ - const_cast(this)->doLayout(); - - const int height = static_cast(m_size.height()); - const int rowHeight = static_cast(m_itemSize.height()); - int rows = height / rowHeight; - if (height % rowHeight != 0) { - ++rows; - } - - return rows * m_columnCount; -} - -bool KItemListViewLayouter::isFirstGroupItem(int itemIndex) const -{ - const_cast(this)->doLayout(); - return m_groupItemIndexes.contains(itemIndex); -} - -void KItemListViewLayouter::markAsDirty() -{ - m_dirty = true; -} - - -#ifndef QT_NO_DEBUG - bool KItemListViewLayouter::isDirty() - { - return m_dirty; - } -#endif - -void KItemListViewLayouter::doLayout() -{ - if (m_dirty) { -#ifdef KITEMLISTVIEWLAYOUTER_DEBUG - QElapsedTimer timer; - timer.start(); -#endif - m_visibleIndexesDirty = true; - - QSizeF itemSize = m_itemSize; - QSizeF itemMargin = m_itemMargin; - QSizeF size = m_size; - - const bool grouped = createGroupHeaders(); - - const bool horizontalScrolling = (m_scrollOrientation == Qt::Horizontal); - if (horizontalScrolling) { - // Flip everything so that the layout logically can work like having - // a vertical scrolling - itemSize.setWidth(m_itemSize.height()); - itemSize.setHeight(m_itemSize.width()); - itemMargin.setWidth(m_itemMargin.height()); - itemMargin.setHeight(m_itemMargin.width()); - size.setWidth(m_size.height()); - size.setHeight(m_size.width()); - - if (grouped) { - // In the horizontal scrolling case all groups are aligned - // at the top, which decreases the available height. For the - // flipped data this means that the width must be decreased. - size.rwidth() -= m_groupHeaderHeight; - } - } - - m_columnWidth = itemSize.width() + itemMargin.width(); - const qreal widthForColumns = size.width() - itemMargin.width(); - m_columnCount = qMax(1, int(widthForColumns / m_columnWidth)); - m_xPosInc = itemMargin.width(); - - const int itemCount = m_model->count(); - if (itemCount > m_columnCount && m_columnWidth >= 32) { - // Apply the unused width equally to each column - const qreal unusedWidth = widthForColumns - m_columnCount * m_columnWidth; - if (unusedWidth > 0) { - const qreal columnInc = unusedWidth / (m_columnCount + 1); - m_columnWidth += columnInc; - m_xPosInc += columnInc; - } - } - - int rowCount = itemCount / m_columnCount; - if (itemCount % m_columnCount != 0) { - ++rowCount; - } - - m_itemInfos.reserve(itemCount); - - qreal y = m_headerHeight + itemMargin.height(); - int row = 0; - - int index = 0; - while (index < itemCount) { - qreal x = m_xPosInc; - qreal maxItemHeight = itemSize.height(); - - if (grouped) { - if (horizontalScrolling) { - // All group headers will always be aligned on the top and not - // flipped like the other properties - x += m_groupHeaderHeight; - } - - if (m_groupItemIndexes.contains(index)) { - // The item is the first item of a group. - // Increase the y-position to provide space - // for the group header. - if (index > 0) { - // Only add a margin if there has been added another - // group already before - y += m_groupHeaderMargin; - } else if (!horizontalScrolling) { - // The first group header should be aligned on top - y -= itemMargin.height(); - } - - if (!horizontalScrolling) { - y += m_groupHeaderHeight; - } - } - } - - int column = 0; - while (index < itemCount && column < m_columnCount) { - qreal requiredItemHeight = itemSize.height(); - if (m_sizeHintResolver) { - const QSizeF sizeHint = m_sizeHintResolver->sizeHint(index); - const qreal sizeHintHeight = horizontalScrolling ? sizeHint.width() : sizeHint.height(); - if (sizeHintHeight > requiredItemHeight) { - requiredItemHeight = sizeHintHeight; - } - } - - const QRectF bounds(x, y, itemSize.width(), requiredItemHeight); - if (index < m_itemInfos.count()) { - m_itemInfos[index].rect = bounds; - m_itemInfos[index].column = column; - m_itemInfos[index].row = row; - } else { - ItemInfo itemInfo; - itemInfo.rect = bounds; - itemInfo.column = column; - itemInfo.row = row; - m_itemInfos.append(itemInfo); - } - - if (grouped && horizontalScrolling) { - // When grouping is enabled in the horizontal mode, the header alignment - // looks like this: - // Header-1 Header-2 Header-3 - // Item 1 Item 4 Item 7 - // Item 2 Item 5 Item 8 - // Item 3 Item 6 Item 9 - // In this case 'requiredItemHeight' represents the column-width. We don't - // check the content of the header in the layouter to determine the required - // width, hence assure that at least a minimal width of 15 characters is given - // (in average a character requires the halve width of the font height). - // - // TODO: Let the group headers provide a minimum width and respect this width here - const qreal headerWidth = minimumGroupHeaderWidth(); - if (requiredItemHeight < headerWidth) { - requiredItemHeight = headerWidth; - } - } - - maxItemHeight = qMax(maxItemHeight, requiredItemHeight); - x += m_columnWidth; - ++index; - ++column; - - if (grouped && m_groupItemIndexes.contains(index)) { - // The item represents the first index of a group - // and must aligned in the first column - break; - } - } - - y += maxItemHeight + itemMargin.height(); - ++row; - } - if (m_itemInfos.count() > itemCount) { - m_itemInfos.erase(m_itemInfos.begin() + itemCount, - m_itemInfos.end()); - } - - if (itemCount > 0) { - // Calculate the maximum y-range of the last row for m_maximumScrollOffset - m_maximumScrollOffset = m_itemInfos.last().rect.bottom(); - const qreal rowY = m_itemInfos.last().rect.y(); - - int index = m_itemInfos.count() - 2; - while (index >= 0 && m_itemInfos[index].rect.bottom() >= rowY) { - m_maximumScrollOffset = qMax(m_maximumScrollOffset, m_itemInfos[index].rect.bottom()); - --index; - } - - m_maximumScrollOffset += itemMargin.height(); - - m_maximumItemOffset = m_columnCount * m_columnWidth; - } else { - m_maximumScrollOffset = 0; - m_maximumItemOffset = 0; - } - -#ifdef KITEMLISTVIEWLAYOUTER_DEBUG - kDebug() << "[TIME] doLayout() for " << m_model->count() << "items:" << timer.elapsed(); -#endif - m_dirty = false; - } - - updateVisibleIndexes(); -} - -void KItemListViewLayouter::updateVisibleIndexes() -{ - if (!m_visibleIndexesDirty) { - return; - } - - Q_ASSERT(!m_dirty); - - if (m_model->count() <= 0) { - m_firstVisibleIndex = -1; - m_lastVisibleIndex = -1; - m_visibleIndexesDirty = false; - return; - } - - const int maxIndex = m_model->count() - 1; - - // Calculate the first visible index that is fully visible - int min = 0; - int max = maxIndex; - int mid = 0; - do { - mid = (min + max) / 2; - if (m_itemInfos[mid].rect.top() < m_scrollOffset) { - min = mid + 1; - } else { - max = mid - 1; - } - } while (min <= max); - - if (mid > 0) { - // Include the row before the first fully visible index, as it might - // be partly visible - if (m_itemInfos[mid].rect.top() >= m_scrollOffset) { - --mid; - Q_ASSERT(m_itemInfos[mid].rect.top() < m_scrollOffset); - } - - const qreal rowTop = m_itemInfos[mid].rect.top(); - while (mid > 0 && m_itemInfos[mid - 1].rect.top() == rowTop) { - --mid; - } - } - m_firstVisibleIndex = mid; - - // Calculate the last visible index that is (at least partly) visible - const int visibleHeight = (m_scrollOrientation == Qt::Horizontal) ? m_size.width() : m_size.height(); - qreal bottom = m_scrollOffset + visibleHeight; - if (m_model->groupedSorting()) { - bottom += m_groupHeaderHeight; - } - - min = m_firstVisibleIndex; - max = maxIndex; - do { - mid = (min + max) / 2; - if (m_itemInfos[mid].rect.y() <= bottom) { - min = mid + 1; - } else { - max = mid - 1; - } - } while (min <= max); - - while (mid > 0 && m_itemInfos[mid].rect.y() > bottom) { - --mid; - } - m_lastVisibleIndex = mid; - - m_visibleIndexesDirty = false; -} - -bool KItemListViewLayouter::createGroupHeaders() -{ - if (!m_model->groupedSorting()) { - return false; - } - - m_groupItemIndexes.clear(); - - const QList > groups = m_model->groups(); - if (groups.isEmpty()) { - return false; - } - - for (int i = 0; i < groups.count(); ++i) { - const int firstItemIndex = groups.at(i).first; - m_groupItemIndexes.insert(firstItemIndex); - } - - return true; -} - -qreal KItemListViewLayouter::minimumGroupHeaderWidth() const -{ - return 100; -} - -#include "kitemlistviewlayouter_p.moc" diff --git a/src/kitemviews/kitemlistviewlayouter_p.h b/src/kitemviews/kitemlistviewlayouter_p.h deleted file mode 100644 index da5bd1d7d..000000000 --- a/src/kitemviews/kitemlistviewlayouter_p.h +++ /dev/null @@ -1,235 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef KITEMLISTVIEWLAYOUTER_H -#define KITEMLISTVIEWLAYOUTER_H - -#include - -#include -#include -#include -#include - -class KItemModelBase; -class KItemListSizeHintResolver; - -/** - * @brief Internal helper class for KItemListView to layout the items. - * - * The layouter is capable to align the items within a grid. If the - * scroll-direction is horizontal the column-width of the grid can be - * variable. If the scroll-direction is vertical the row-height of - * the grid can be variable. - * - * The layouter is implemented in a way that it postpones the expensive - * layout operation until a property is read the first time after - * marking the layouter as dirty (see markAsDirty()). This means that - * changing properties of the layouter is not expensive, only the - * first read of a property can get expensive. - */ -class LIBDOLPHINPRIVATE_EXPORT KItemListViewLayouter : public QObject -{ - Q_OBJECT - -public: - KItemListViewLayouter(QObject* parent = 0); - virtual ~KItemListViewLayouter(); - - void setScrollOrientation(Qt::Orientation orientation); - Qt::Orientation scrollOrientation() const; - - void setSize(const QSizeF& size); - QSizeF size() const; - - void setItemSize(const QSizeF& size); - QSizeF itemSize() const; - - /** - * Margin between the rows and columns of items. - */ - void setItemMargin(const QSizeF& margin); - QSizeF itemMargin() const; - - /** - * Sets the height of the header that is always aligned - * at the top. A height of <= 0.0 means that no header is - * used. - */ - void setHeaderHeight(qreal height); - qreal headerHeight() const; - - /** - * Sets the height of the group header that is used - * to indicate a new item group. - */ - void setGroupHeaderHeight(qreal height); - qreal groupHeaderHeight() const; - - /** - * Sets the margin between the last items of the group n and - * the group header for the group n + 1. - */ - void setGroupHeaderMargin(qreal margin); - qreal groupHeaderMargin() const; - - void setScrollOffset(qreal scrollOffset); - qreal scrollOffset() const; - - qreal maximumScrollOffset() const; - - void setItemOffset(qreal scrollOffset); - qreal itemOffset() const; - - qreal maximumItemOffset() const; - - void setModel(const KItemModelBase* model); - const KItemModelBase* model() const; - - void setSizeHintResolver(const KItemListSizeHintResolver* sizeHintResolver); - const KItemListSizeHintResolver* sizeHintResolver() const; - - /** - * @return The first (at least partly) visible index. -1 is returned - * if the item count is 0. - */ - int firstVisibleIndex() const; - - /** - * @return The last (at least partly) visible index. -1 is returned - * if the item count is 0. - */ - int lastVisibleIndex() const; - - /** - * @return Rectangle of the item with the index \a index. - * The top/left of the bounding rectangle is related to - * the top/left of the KItemListView. An empty rectangle - * is returned if an invalid index is given. - */ - QRectF itemRect(int index) const; - - /** - * @return Rectangle of the group header for the item with the - * index \a index. Note that the layouter does not check - * whether the item really has a header: Usually only - * the first item of a group gets a header (see - * isFirstGroupItem()). - */ - QRectF groupHeaderRect(int index) const; - - /** - * @return Column of the item with the index \a index. - * -1 is returned if an invalid index is given. - */ - int itemColumn(int index) const; - - /** - * @return Row of the item with the index \a index. - * -1 is returned if an invalid index is given. - */ - int itemRow(int index) const; - - /** - * @return Maximum number of (at least partly) visible items for - * the given size. - */ - int maximumVisibleItems() const; - - /** - * @return True if the item with the index \p itemIndex - * is the first item within a group. - */ - bool isFirstGroupItem(int itemIndex) const; - - /** - * Marks the layouter as dirty. This means as soon as a property of - * the layouter gets read, an expensive relayout will be done. - */ - void markAsDirty(); - -#ifndef QT_NO_DEBUG - /** - * @return True if the layouter has been marked as dirty and hence has - * not called yet doLayout(). Is enabled only in the debugging - * mode, as it is not useful to check the dirty state otherwise. - */ - bool isDirty(); -#endif - -private: - void doLayout(); - void updateVisibleIndexes(); - bool createGroupHeaders(); - - /** - * @return Minimum width of group headers when grouping is enabled in the horizontal - * alignment mode. The header alignment is done like this: - * Header-1 Header-2 Header-3 - * Item 1 Item 4 Item 7 - * Item 2 Item 5 Item 8 - * Item 3 Item 6 Item 9 - */ - qreal minimumGroupHeaderWidth() const; - -private: - bool m_dirty; - bool m_visibleIndexesDirty; - - Qt::Orientation m_scrollOrientation; - QSizeF m_size; - - QSizeF m_itemSize; - QSizeF m_itemMargin; - qreal m_headerHeight; - const KItemModelBase* m_model; - const KItemListSizeHintResolver* m_sizeHintResolver; - - qreal m_scrollOffset; - qreal m_maximumScrollOffset; - - qreal m_itemOffset; - qreal m_maximumItemOffset; - - int m_firstVisibleIndex; - int m_lastVisibleIndex; - - qreal m_columnWidth; - qreal m_xPosInc; - int m_columnCount; - - // Stores all item indexes that are the first item of a group. - // Assures fast access for KItemListViewLayouter::isFirstGroupItem(). - QSet m_groupItemIndexes; - qreal m_groupHeaderHeight; - qreal m_groupHeaderMargin; - - struct ItemInfo { - QRectF rect; - int column; - int row; - }; - QList m_itemInfos; - - friend class KItemListControllerTest; -}; - -#endif - - diff --git a/src/kitemviews/kitemlistwidget.cpp b/src/kitemviews/kitemlistwidget.cpp index b703fbfe2..74b96ca1f 100644 --- a/src/kitemviews/kitemlistwidget.cpp +++ b/src/kitemviews/kitemlistwidget.cpp @@ -22,10 +22,11 @@ #include "kitemlistwidget.h" -#include "kitemlistselectiontoggle_p.h" #include "kitemlistview.h" #include "kitemmodelbase.h" +#include "private/kitemlistselectiontoggle.h" + #include #include diff --git a/src/kitemviews/knepomukdatamanagement_export_p.h b/src/kitemviews/knepomukdatamanagement_export_p.h deleted file mode 100644 index 929a737c9..000000000 --- a/src/kitemviews/knepomukdatamanagement_export_p.h +++ /dev/null @@ -1,40 +0,0 @@ -/* This file is part of the KDE project - Copyright (C) 2007 David Faure - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#ifndef NEPOMUKDATAMANAGEMENT_EXPORT_H -#define NEPOMUKDATAMANAGEMENT_EXPORT_H - -/* needed for KDE_EXPORT and KDE_IMPORT macros */ -#include - -#ifndef NEPOMUK_DATA_MANAGEMENT_EXPORT -# if defined(MAKE_NEPOMUKDATAMANAGEMENT_LIB) - /* We are building this library */ -# define NEPOMUK_DATA_MANAGEMENT_EXPORT KDE_EXPORT -# else - /* We are using this library */ -# define NEPOMUK_DATA_MANAGEMENT_EXPORT KDE_IMPORT -# endif -#endif - -# ifndef NEPOMUK_DATA_MANAGEMENT_EXPORT_DEPRECATED -# define NEPOMUK_DATA_MANAGEMENT_EXPORT_DEPRECATED KDE_DEPRECATED NEPOMUK_DATA_MANAGEMENT_EXPORT -# endif - -#endif diff --git a/src/kitemviews/knepomukresourcewatcher_p.h b/src/kitemviews/knepomukresourcewatcher_p.h deleted file mode 100644 index 9b4b8b71d..000000000 --- a/src/kitemviews/knepomukresourcewatcher_p.h +++ /dev/null @@ -1,288 +0,0 @@ -/* - This file is part of the Nepomuk KDE project. - Copyright (C) 2011 Vishesh Handa - Copyright (C) 2011 Sebastian Trueg - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - - -#ifndef RESOURCEWATCHER_H -#define RESOURCEWATCHER_H - -#include -#include -#include - -#include -#include - -#include "knepomukdatamanagement_export_p.h" - -namespace Nepomuk { - - /** - * \class ResourceWatcher resourcewatcher.h - * - * \brief Selectively monitor the nepomuk repository for changes. - * - * Resources may be monitored on the basis of types, properties, and uris. - * - * Changes may be monitored in one of the following ways: - * -# By resources - - * Specify the exact resources that should be watched. Any changes made to the specified resources - * (Excluding \ref nepomuk_dms_metadata) will be notified through the propertyAdded() and propertyRemoved() - * signals. Notifications will also be sent if any of the watched resources is deleted. - * -# By resources and properties - - * Specify the exact resources and their properties. Any changes made to the specified resources - * which touch one of the specified properties will be notified through the propertyAdded() and propertyRemoved() - * signals. - * -# By types - - * Specific types may be specified via add/setType. If types are set, then notifications will be - * sent for all new resources of that type. This includes property changes and resource creation and removal. - * TODO: add flags that allow to only watch for resource creation and removal. - * -# By types and properties - - * Both the types and properties may be specified. Notifications will be sent for property changes - * in resource with the specified types. - * - * \section nepomuk_rw_examples Resource Watcher Usage Example - * - * The following code creates a new ResourceWatcher, configures it to listen to changes on the \c nmm:performer - * property on one specific resource \c res. - * - * \code - * Nepomuk::ResourceWatcher* watcher = new Nepomuk::ResourceWatcher(this); - * watcher->addResource(res); - * watcher->addProperty(NMM:performer()); - * connect(watcher, SIGNAL(propertyAdded(Nepomuk::Resource, Nepomuk::Types::Property, QVariant)), - * this, SLOT(slotPropertyChanged())); - * connect(watcher, SIGNAL(propertyRemoved(Nepomuk::Resource, Nepomuk::Types::Property, QVariant)), - * this, SLOT(slotPropertyChanged())); - * rwatcher->start(); - * \endcode - * - * \author Vishesh Handa , Sebastian Trueg - * - * \ingroup nepomuk_datamanagement - */ - class NEPOMUK_DATA_MANAGEMENT_EXPORT ResourceWatcher : public QObject - { - Q_OBJECT - - public: - /** - * \brief Create a new %ResourceWatcher instance. - * - * This instance will not emit any signals before it has been configured - * and started. - */ - ResourceWatcher( QObject* parent = 0 ); - - /** - * \brief Destructor. - */ - virtual ~ResourceWatcher(); - - /** - * \brief Add a type to be watched. - * - * Every resource of this type will be watched for changes. - * - * \sa setTypes() - */ - void addType( const Types::Class & type ); - - /** - * \brief Add a resource to be watched. - * - * Every change to this resource will be - * signalled, depending on the configured properties(). - * - * \sa setResources() - */ - void addResource( const Nepomuk::Resource & res ); - - /** - * \brief Add a property to be watched. - * - * Every change to a value of this property - * will be signalled, depending on the configured resources() or types(). - * - * \sa setProperties() - */ - void addProperty( const Types::Property & property ); - - /** - * \brief Set the types to be watched. - * - * Every resource having one of these types will be watched for changes. - * - * \sa addType() - */ - void setTypes( const QList & types_ ); - - /** - * \brief Set the resources to be watched. - * - * Every change to one of these resources will be - * signalled, depending on the configured properties(). - * - * \sa addResource() - */ - void setResources( const QList & resources_ ); - - /** - * \brief Set the properties to be watched. - * - * Every change to a value of any of these properties - * will be signalled, depending on the configured resources() or types(). - * - * \sa addProperty() - */ - void setProperties( const QList & properties_ ); - - /** - * \brief The types that have been configured via addType() and setTypes(). - * - * Every resource having one of these types will be watched - * for changes. - */ - QList types() const; - - /** - * \brief The resources that have been configured via addResource() and setResources(). - * - * Every change to one of these resources will be - * signalled, depending on the configured properties(). - */ - QList resources() const; - - /** - * \brief The properties that have been configured via addProperty() and setProperties(). - * - * Every change to a value of any of these properties - * will be signalled, depending on the configured resources() or types(). - */ - QList properties() const; - - public Q_SLOTS: - /** - * \brief Start the signalling of changes. - * - * Before calling this method no signal will be emitted. In - * combination with stop() this allows to suspend the watching. - * Calling start() multiple times has no effect. - */ - bool start(); - - /** - * \brief Stop the signalling of changes. - * - * Allows to stop the watcher which has been started - * via start(). Calling stop() multiple times has no effect. - */ - void stop(); - - Q_SIGNALS: - /** - * \brief This signal is emitted when a new resource is created. - * \param resource The newly created resource. - * \param types The types the new resource has. If types() have been configured this list will always - * contain one of the configured types. - */ - void resourceCreated( const Nepomuk::Resource & resource, const QList& types ); //FIXME: Use either Resource or uri, not a mix - - /** - * \brief This signal is emitted when a resource is deleted. - * \param uri The resource URI of the removed resource. - * \param types The types the removed resource had. If types() have been configured this list will always - * contain one of the configured types. - */ - void resourceRemoved( const QUrl & uri, const QList& types ); - - /** - * \brief This signal is emitted when a type has been added to a resource. This does not include creation which - * is signalled via resourceCreated(). It only applies to changes in a resource's types. - * \param res The changed resource. - * \param type The newly added type. If types() have been configured it will be one of them. - */ - void resourceTypeAdded( const Nepomuk::Resource & res, const Types::Class & type ); - - /** - * \brief This signal is emitted when a type has been removed from a resource. - * - * This does not include removal of entire resources which is signalled via resourceRemoved(). - * It only applies to changes in a resource's types. - * \param res The changed resource. - * \param type The removed type. If types() have been configured it will be one of them. - */ - void resourceTypeRemoved( const Nepomuk::Resource & res, const Types::Class & type ); - - /** - * \brief This signal is emitted when a property value is added. - * \param resource The changed resource. - * \param property The property which has a new value. - * \param value The newly added property value. - */ - void propertyAdded( const Nepomuk::Resource & resource, - const Nepomuk::Types::Property & property, - const QVariant & value ); - - /** - * \brief This signal is emitted when a property value is removed. - * \param resource The changed resource. - * \param property The property which was changed. - * \param value The removed property value. - */ - void propertyRemoved( const Nepomuk::Resource & resource, - const Nepomuk::Types::Property & property, - const QVariant & value ); - - /** - * \brief This signal is emitted when a property value is changed. - * - * This signal cannot be emitted for all changes. It doesn't work if a property is first - * removed and then set, cause the Data Mangement Service does not maintain an internal - * cache for the purpose of emitting the propertyChanged signal. - * - * Specially, since one could theoretically take forever between the removal and the - * setting of the property. - * - * \param resource The changed resource. - * \param property The property which was changed. - * \param oldValue The removed property value. - */ - void propertyChanged( const Nepomuk::Resource & resource, - const Nepomuk::Types::Property & property, - const QVariantList & oldValue, - const QVariantList & newValue ); - - private Q_SLOTS: - void slotResourceCreated(const QString& res, const QStringList& types); - void slotResourceRemoved(const QString& res, const QStringList& types); - void slotResourceTypeAdded(const QString& res, const QString& type); - void slotResourceTypeRemoved(const QString& res, const QString& type); - void slotPropertyAdded(const QString& res, const QString& prop, const QDBusVariant& object); - void slotPropertyRemoved(const QString& res, const QString& prop, const QDBusVariant& object); - void slotPropertyChanged(const QString& res, const QString& prop, - const QVariantList & oldObjs, - const QVariantList & newObjs); - private: - class Private; - Private * d; - }; -} - -#endif // RESOURCEWATCHER_H diff --git a/src/kitemviews/knepomukrolesprovider.cpp b/src/kitemviews/knepomukrolesprovider.cpp deleted file mode 100644 index 25fb16121..000000000 --- a/src/kitemviews/knepomukrolesprovider.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2012 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "knepomukrolesprovider_p.h" - -#include -#include -#include - -#include -#include -#include -#include - -struct KNepomukRolesProviderSingleton -{ - KNepomukRolesProvider instance; -}; -K_GLOBAL_STATIC(KNepomukRolesProviderSingleton, s_nepomukRolesProvider) - - -KNepomukRolesProvider& KNepomukRolesProvider::instance() -{ - return s_nepomukRolesProvider->instance; -} - -KNepomukRolesProvider::~KNepomukRolesProvider() -{ -} - -QSet KNepomukRolesProvider::roles() const -{ - return m_roles; -} - -QHash KNepomukRolesProvider::roleValues(const Nepomuk::Resource& resource, - const QSet& roles) const -{ - if (!resource.isValid()) { - return QHash(); - } - - QHash values; - - int width = -1; - int height = -1; - - QHashIterator it(resource.properties()); - while (it.hasNext()) { - it.next(); - - const Nepomuk::Types::Property property = it.key(); - const QByteArray role = m_roleForUri.value(property.uri()); - if (role.isEmpty() || !roles.contains(role)) { - continue; - } - - const Nepomuk::Variant value = it.value(); - - if (role == "imageSize") { - // Merge the two Nepomuk properties for width and height - // as one string into the "imageSize" role - const QString uri = property.uri().toString(); - if (uri.endsWith("#width")) { - width = value.toInt(); - } else if (uri.endsWith("#height")) { - height = value.toInt(); - } - - if (width >= 0 && height >= 0) { - const QString widthAndHeight = QString::number(width) + - QLatin1String(" x ") + - QString::number(height); - values.insert(role, widthAndHeight); - } - } else if (role == "tags") { - const QString tags = tagsFromValues(value.toStringList()); - values.insert(role, tags); - } else if (role == "orientation") { - const QString orientation = orientationFromValue(value.toInt()); - values.insert(role, orientation); - } else { - values.insert(role, value.toString()); - } - } - - // Assure that empty values get replaced by "-" - foreach (const QByteArray& role, roles) { - if (m_roles.contains(role) && values.value(role).toString().isEmpty()) { - values.insert(role, QLatin1String("-")); - } - } - - return values; -} - -KNepomukRolesProvider::KNepomukRolesProvider() : - m_roles(), - m_roleForUri() -{ - struct UriInfo - { - const char* const uri; - const char* const role; - }; - - // 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") - static const UriInfo uriInfoList[] = { - { "http://www.semanticdesktop.org/ontologies/2007/08/15/nao#numericRating", "rating" }, - { "http://www.semanticdesktop.org/ontologies/2007/08/15/nao#hasTag", "tags" }, - { "http://www.semanticdesktop.org/ontologies/2007/08/15/nao#description", "comment" }, - { "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#wordCount", "wordCount" }, - { "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#lineCount", "lineCount" }, - { "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#width", "imageSize" }, - { "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#height", "imageSize" }, - { "http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#orientation", "orientation", }, - { "http://www.semanticdesktop.org/ontologies/2009/02/19/nmm#performer", "artist" }, - { "http://www.semanticdesktop.org/ontologies/2009/02/19/nmm#musicAlbum", "album" }, - { "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#duration", "duration" }, - { "http://www.semanticdesktop.org/ontologies/2009/02/19/nmm#trackNumber", "track" }, - { "http://www.semanticdesktop.org/ontologies/2010/04/30/ndo#copiedFrom", "copiedFrom" } - }; - - for (unsigned int i = 0; i < sizeof(uriInfoList) / sizeof(UriInfo); ++i) { - m_roleForUri.insert(QUrl(uriInfoList[i].uri), uriInfoList[i].role); - m_roles.insert(uriInfoList[i].role); - } -} - -QString KNepomukRolesProvider::tagsFromValues(const QStringList& values) const -{ - QString tags; - - for (int i = 0; i < values.count(); ++i) { - if (i > 0) { - tags.append(QLatin1String(", ")); - } - - const Nepomuk::Tag tag(values[i]); - tags += tag.genericLabel(); - } - - return tags; -} - -QString KNepomukRolesProvider::orientationFromValue(int value) const -{ - QString string; - switch (value) { - case 1: string = i18nc("@item:intable Image orientation", "Unchanged"); break; - case 2: string = i18nc("@item:intable Image orientation", "Horizontally flipped"); break; - case 3: string = i18nc("@item:intable image orientation", "180° rotated"); break; - case 4: string = i18nc("@item:intable image orientation", "Vertically flipped"); break; - case 5: string = i18nc("@item:intable image orientation", "Transposed"); break; - case 6: string = i18nc("@item:intable image orientation", "90° rotated"); break; - case 7: string = i18nc("@item:intable image orientation", "Transversed"); break; - case 8: string = i18nc("@item:intable image orientation", "270° rotated"); break; - default: - break; - } - return string; -} - diff --git a/src/kitemviews/knepomukrolesprovider_p.h b/src/kitemviews/knepomukrolesprovider_p.h deleted file mode 100644 index 46a78d4ee..000000000 --- a/src/kitemviews/knepomukrolesprovider_p.h +++ /dev/null @@ -1,82 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2012 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef KNEPOMUKROLESPROVIDER_H -#define KNEPOMUKROLESPROVIDER_H - -#include - -#include -#include -#include - -namespace Nepomuk -{ - class Resource; -} - -/** - * @brief Allows accessing metadata of a file by providing KFileItemModel roles. - * - * Is a helper class for KFileItemModelRolesUpdater to retrieve roles that - * are only accessible with Nepomuk. - */ -class LIBDOLPHINPRIVATE_EXPORT KNepomukRolesProvider -{ -public: - static KNepomukRolesProvider& instance(); - virtual ~KNepomukRolesProvider(); - - /** - * @return Roles that can be provided by KNepomukRolesProvider. - */ - QSet roles() const; - - /** - * @return Values for the roles \a roles that can be determined from the file - * with the URL \a url. - */ - QHash roleValues(const Nepomuk::Resource& resource, - const QSet& roles) const; - -protected: - KNepomukRolesProvider(); - -private: - /** - * @return User visible string for the given tag-values. - */ - QString tagsFromValues(const QStringList& values) const; - - /** - * @return User visible string for the EXIF-orientation property - * which can have the values 0 to 8. - * (see http://sylvana.net/jpegcrop/exif_orientation.html) - */ - QString orientationFromValue(int value) const; - -private: - QSet m_roles; - QHash m_roleForUri; - - friend class KNepomukRolesProviderSingleton; -}; - -#endif - diff --git a/src/kitemviews/kpixmapmodifier.cpp b/src/kitemviews/kpixmapmodifier.cpp deleted file mode 100644 index 475f36a64..000000000 --- a/src/kitemviews/kpixmapmodifier.cpp +++ /dev/null @@ -1,400 +0,0 @@ -// krazy:excludeall=copyright (email of Maxim is missing) -/* - This file is a part of the KDE project - - Copyright © 2006 Zack Rusin - Copyright © 2006-2007, 2008 Fredrik Höglund - - The stack blur algorithm was invented by Mario Klingemann - - This implementation is based on the version in Anti-Grain Geometry Version 2.4, - Copyright © 2002-2005 Maxim Shemanarev (http://www.antigrain.com) - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "kpixmapmodifier_p.h" - -#include -#include -#include -#include - -#include - -#include // for HAVE_XRENDER -#if defined(Q_WS_X11) && defined(HAVE_XRENDER) -# include -# include -# include -#endif - -static const quint32 stackBlur8Mul[255] = -{ - 512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512, - 454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512, - 482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456, - 437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512, - 497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328, - 320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456, - 446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335, - 329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512, - 505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405, - 399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328, - 324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271, - 268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456, - 451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388, - 385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335, - 332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292, - 289,287,285,282,280,278,275,273,271,269,267,265,263,261,259 -}; - -static const quint32 stackBlur8Shr[255] = -{ - 9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, - 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24 -}; - -static void blurHorizontal(QImage& image, unsigned int* stack, int div, int radius) -{ - int stackindex; - int stackstart; - - quint32 * const pixels = reinterpret_cast(image.bits()); - quint32 pixel; - - int w = image.width(); - int h = image.height(); - int wm = w - 1; - - unsigned int mulSum = stackBlur8Mul[radius]; - unsigned int shrSum = stackBlur8Shr[radius]; - - unsigned int sum, sumIn, sumOut; - - for (int y = 0; y < h; y++) { - sum = 0; - sumIn = 0; - sumOut = 0; - - const int yw = y * w; - pixel = pixels[yw]; - for (int i = 0; i <= radius; i++) { - stack[i] = qAlpha(pixel); - - sum += stack[i] * (i + 1); - sumOut += stack[i]; - } - - for (int i = 1; i <= radius; i++) { - pixel = pixels[yw + qMin(i, wm)]; - - unsigned int* stackpix = &stack[i + radius]; - *stackpix = qAlpha(pixel); - - sum += *stackpix * (radius + 1 - i); - sumIn += *stackpix; - } - - stackindex = radius; - for (int x = 0, i = yw; x < w; x++) { - pixels[i++] = (((sum * mulSum) >> shrSum) << 24) & 0xff000000; - - sum -= sumOut; - - stackstart = stackindex + div - radius; - if (stackstart >= div) { - stackstart -= div; - } - - unsigned int* stackpix = &stack[stackstart]; - - sumOut -= *stackpix; - - pixel = pixels[yw + qMin(x + radius + 1, wm)]; - - *stackpix = qAlpha(pixel); - - sumIn += *stackpix; - sum += sumIn; - - if (++stackindex >= div) { - stackindex = 0; - } - - stackpix = &stack[stackindex]; - - sumOut += *stackpix; - sumIn -= *stackpix; - } - } -} - -static void blurVertical(QImage& image, unsigned int* stack, int div, int radius) -{ - int stackindex; - int stackstart; - - quint32 * const pixels = reinterpret_cast(image.bits()); - quint32 pixel; - - int w = image.width(); - int h = image.height(); - int hm = h - 1; - - int mul_sum = stackBlur8Mul[radius]; - int shr_sum = stackBlur8Shr[radius]; - - unsigned int sum, sumIn, sumOut; - - for (int x = 0; x < w; x++) { - sum = 0; - sumIn = 0; - sumOut = 0; - - pixel = pixels[x]; - for (int i = 0; i <= radius; i++) { - stack[i] = qAlpha(pixel); - - sum += stack[i] * (i + 1); - sumOut += stack[i]; - } - - for (int i = 1; i <= radius; i++) { - pixel = pixels[qMin(i, hm) * w + x]; - - unsigned int* stackpix = &stack[i + radius]; - *stackpix = qAlpha(pixel); - - sum += *stackpix * (radius + 1 - i); - sumIn += *stackpix; - } - - stackindex = radius; - for (int y = 0, i = x; y < h; y++, i += w) { - pixels[i] = (((sum * mul_sum) >> shr_sum) << 24) & 0xff000000; - - sum -= sumOut; - - stackstart = stackindex + div - radius; - if (stackstart >= div) - stackstart -= div; - - unsigned int* stackpix = &stack[stackstart]; - - sumOut -= *stackpix; - - pixel = pixels[qMin(y + radius + 1, hm) * w + x]; - - *stackpix = qAlpha(pixel); - - sumIn += *stackpix; - sum += sumIn; - - if (++stackindex >= div) { - stackindex = 0; - } - - stackpix = &stack[stackindex]; - - sumOut += *stackpix; - sumIn -= *stackpix; - } - } -} - -static void stackBlur(QImage& image, float radius) -{ - radius = qRound(radius); - - int div = int(radius * 2) + 1; - unsigned int* stack = new unsigned int[div]; - - blurHorizontal(image, stack, div, radius); - blurVertical(image, stack, div, radius); - - delete [] stack; -} - -static void shadowBlur(QImage& image, float radius, const QColor& color) -{ - if (radius < 0) { - return; - } - - if (radius > 0) { - stackBlur(image, radius); - } - - // Correct the color and opacity of the shadow - QPainter p(&image); - p.setCompositionMode(QPainter::CompositionMode_SourceIn); - p.fillRect(image.rect(), color); -} - -namespace { - /** Helper class for drawing frames for KPixmapModifier::applyFrame(). */ - class TileSet - { - public: - enum { LeftMargin = 3, TopMargin = 2, RightMargin = 3, BottomMargin = 4 }; - - enum Tile { TopLeftCorner = 0, TopSide, TopRightCorner, LeftSide, - RightSide, BottomLeftCorner, BottomSide, BottomRightCorner, - NumTiles }; - - TileSet() - { - QImage image(8 * 3, 8 * 3, QImage::Format_ARGB32_Premultiplied); - - QPainter p(&image); - p.setCompositionMode(QPainter::CompositionMode_Source); - p.fillRect(image.rect(), Qt::transparent); - p.fillRect(image.rect().adjusted(3, 3, -3, -3), Qt::black); - p.end(); - - shadowBlur(image, 3, Qt::black); - - QPixmap pixmap = QPixmap::fromImage(image); - m_tiles[TopLeftCorner] = pixmap.copy(0, 0, 8, 8); - m_tiles[TopSide] = pixmap.copy(8, 0, 8, 8); - m_tiles[TopRightCorner] = pixmap.copy(16, 0, 8, 8); - m_tiles[LeftSide] = pixmap.copy(0, 8, 8, 8); - m_tiles[RightSide] = pixmap.copy(16, 8, 8, 8); - m_tiles[BottomLeftCorner] = pixmap.copy(0, 16, 8, 8); - m_tiles[BottomSide] = pixmap.copy(8, 16, 8, 8); - m_tiles[BottomRightCorner] = pixmap.copy(16, 16, 8, 8); - } - - void paint(QPainter* p, const QRect& r) - { - p->drawPixmap(r.topLeft(), m_tiles[TopLeftCorner]); - if (r.width() - 16 > 0) { - p->drawTiledPixmap(r.x() + 8, r.y(), r.width() - 16, 8, m_tiles[TopSide]); - } - p->drawPixmap(r.right() - 8 + 1, r.y(), m_tiles[TopRightCorner]); - if (r.height() - 16 > 0) { - p->drawTiledPixmap(r.x(), r.y() + 8, 8, r.height() - 16, m_tiles[LeftSide]); - p->drawTiledPixmap(r.right() - 8 + 1, r.y() + 8, 8, r.height() - 16, m_tiles[RightSide]); - } - p->drawPixmap(r.x(), r.bottom() - 8 + 1, m_tiles[BottomLeftCorner]); - if (r.width() - 16 > 0) { - p->drawTiledPixmap(r.x() + 8, r.bottom() - 8 + 1, r.width() - 16, 8, m_tiles[BottomSide]); - } - p->drawPixmap(r.right() - 8 + 1, r.bottom() - 8 + 1, m_tiles[BottomRightCorner]); - - const QRect contentRect = r.adjusted(LeftMargin + 1, TopMargin + 1, - -(RightMargin + 1), -(BottomMargin + 1)); - p->fillRect(contentRect, Qt::transparent); - } - - QPixmap m_tiles[NumTiles]; - }; -} - -void KPixmapModifier::scale(QPixmap& pixmap, const QSize& scaledSize) -{ - if (scaledSize.isEmpty()) { - pixmap = QPixmap(); - return; - } - -#if defined(Q_WS_X11) && defined(HAVE_XRENDER) - // Assume that the texture size limit is 2048x2048 - if ((pixmap.width() <= 2048) && (pixmap.height() <= 2048) && pixmap.x11PictureHandle()) { - const QPixmap unscaledPixmap = pixmap.copy(); // Make a deep copy for XRender - QSize scaledPixmapSize = pixmap.size(); - scaledPixmapSize.scale(scaledSize, Qt::KeepAspectRatio); - - const qreal factor = scaledPixmapSize.width() / qreal(unscaledPixmap.width()); - - XTransform xform = {{ - { XDoubleToFixed(1 / factor), 0, 0 }, - { 0, XDoubleToFixed(1 / factor), 0 }, - { 0, 0, XDoubleToFixed(1) } - }}; - - QPixmap scaledPixmap(scaledPixmapSize); - scaledPixmap.fill(Qt::transparent); - - Display* dpy = QX11Info::display(); - - XRenderPictureAttributes attr; - attr.repeat = RepeatPad; - XRenderChangePicture(dpy, unscaledPixmap.x11PictureHandle(), CPRepeat, &attr); - - XRenderSetPictureFilter(dpy, unscaledPixmap.x11PictureHandle(), FilterBilinear, 0, 0); - XRenderSetPictureTransform(dpy, unscaledPixmap.x11PictureHandle(), &xform); - XRenderComposite(dpy, PictOpOver, unscaledPixmap.x11PictureHandle(), None, scaledPixmap.x11PictureHandle(), - 0, 0, 0, 0, 0, 0, scaledPixmap.width(), scaledPixmap.height()); - pixmap = scaledPixmap; - } else { - pixmap = pixmap.scaled(scaledSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); - } -#else - pixmap = pixmap.scaled(scaledSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); -#endif -} - -void KPixmapModifier::applyFrame(QPixmap& icon, const QSize& scaledSize) -{ - static TileSet tileSet; - - // Resize the icon to the maximum size minus the space required for the frame - const QSize size(scaledSize.width() - TileSet::LeftMargin - TileSet::RightMargin, - scaledSize.height() - TileSet::TopMargin - TileSet::BottomMargin); - scale(icon, size); - - QPixmap framedIcon(icon.size().width() + TileSet::LeftMargin + TileSet::RightMargin, - icon.size().height() + TileSet::TopMargin + TileSet::BottomMargin); - framedIcon.fill(Qt::transparent); - - QPainter painter; - painter.begin(&framedIcon); - painter.setCompositionMode(QPainter::CompositionMode_Source); - tileSet.paint(&painter, framedIcon.rect()); - painter.setCompositionMode(QPainter::CompositionMode_SourceOver); - painter.drawPixmap(TileSet::LeftMargin, TileSet::TopMargin, icon); - - icon = framedIcon; -} - -QSize KPixmapModifier::sizeInsideFrame(const QSize& frameSize) -{ - return QSize(frameSize.width() - TileSet::LeftMargin - TileSet::RightMargin, - frameSize.height() - TileSet::TopMargin - TileSet::BottomMargin); -} - diff --git a/src/kitemviews/kpixmapmodifier_p.h b/src/kitemviews/kpixmapmodifier_p.h deleted file mode 100644 index 4f863c349..000000000 --- a/src/kitemviews/kpixmapmodifier_p.h +++ /dev/null @@ -1,38 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2011 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef KPIXMAPMODIFIER_H -#define KPIXMAPMODIFIER_H - -#include - -class QPixmap; -class QSize; - -class LIBDOLPHINPRIVATE_EXPORT KPixmapModifier -{ -public: - static void scale(QPixmap& pixmap, const QSize& scaledSize); - static void applyFrame(QPixmap& icon, const QSize& scaledSize); - static QSize sizeInsideFrame(const QSize& frameSize); -}; - -#endif - - diff --git a/src/kitemviews/private/kfileitemclipboard.cpp b/src/kitemviews/private/kfileitemclipboard.cpp new file mode 100644 index 000000000..6d6085641 --- /dev/null +++ b/src/kitemviews/private/kfileitemclipboard.cpp @@ -0,0 +1,76 @@ +/*************************************************************************** + * Copyright (C) 2011 by Peter Penz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#include "kfileitemclipboard.h" + +#include +#include +#include +#include + +class KFileItemClipboardSingleton +{ +public: + KFileItemClipboard instance; +}; +K_GLOBAL_STATIC(KFileItemClipboardSingleton, s_KFileItemClipboard) + + + +KFileItemClipboard* KFileItemClipboard::instance() +{ + return &s_KFileItemClipboard->instance; +} + +bool KFileItemClipboard::isCut(const KUrl& url) const +{ + return m_cutItems.contains(url); +} + +QList KFileItemClipboard::cutItems() const +{ + return m_cutItems.toList(); +} + +KFileItemClipboard::~KFileItemClipboard() +{ +} + +void KFileItemClipboard::updateCutItems() +{ + const QMimeData* mimeData = QApplication::clipboard()->mimeData(); + const QByteArray data = mimeData->data("application/x-kde-cutselection"); + const bool isCutSelection = (!data.isEmpty() && data.at(0) == QLatin1Char('1')); + if (isCutSelection) { + m_cutItems = KUrl::List::fromMimeData(mimeData).toSet(); + emit cutItemsChanged(); + } +} + +KFileItemClipboard::KFileItemClipboard() : + QObject(0), + m_cutItems() +{ + updateCutItems(); + + connect(QApplication::clipboard(), SIGNAL(dataChanged()), + this, SLOT(updateCutItems())); +} + +#include "kfileitemclipboard.moc" diff --git a/src/kitemviews/private/kfileitemclipboard.h b/src/kitemviews/private/kfileitemclipboard.h new file mode 100644 index 000000000..86eb8e9fc --- /dev/null +++ b/src/kitemviews/private/kfileitemclipboard.h @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (C) 2011 by Peter Penz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#ifndef KFILEITEMCLIPBOARD_H +#define KFILEITEMCLIPBOARD_H + +#include +#include +#include +#include + +#include "libdolphin_export.h" + +/** + * @brief Wrapper for QClipboard to provide fast access for checking + * whether a KFileItem has been clipped. + */ +class LIBDOLPHINPRIVATE_EXPORT KFileItemClipboard : public QObject +{ + Q_OBJECT + +public: + static KFileItemClipboard* instance(); + + bool isCut(const KUrl& url) const; + + QList cutItems() const; + +signals: + void cutItemsChanged(); + +protected: + virtual ~KFileItemClipboard(); + +private slots: + void updateCutItems(); + +private: + KFileItemClipboard(); + + QSet m_cutItems; + + friend class KFileItemClipboardSingleton; +}; + +#endif diff --git a/src/kitemviews/private/kfileitemmodeldirlister.cpp b/src/kitemviews/private/kfileitemmodeldirlister.cpp new file mode 100644 index 000000000..be0f9f77b --- /dev/null +++ b/src/kitemviews/private/kfileitemmodeldirlister.cpp @@ -0,0 +1,44 @@ +/*************************************************************************** + * Copyright (C) 2006-2012 by Peter Penz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#include "kfileitemmodeldirlister.h" +#include +#include + +KFileItemModelDirLister::KFileItemModelDirLister(QObject* parent) : + KDirLister(parent) +{ + setAutoErrorHandlingEnabled(false, 0); +} + +KFileItemModelDirLister::~KFileItemModelDirLister() +{ +} + +void KFileItemModelDirLister::handleError(KIO::Job* job) +{ + const QString errorString = job->errorString(); + if (errorString.isEmpty()) { + emit errorMessage(i18nc("@info:status", "Unknown error.")); + } else { + emit errorMessage(errorString); + } +} + +#include "kfileitemmodeldirlister.moc" diff --git a/src/kitemviews/private/kfileitemmodeldirlister.h b/src/kitemviews/private/kfileitemmodeldirlister.h new file mode 100644 index 000000000..1d58347f4 --- /dev/null +++ b/src/kitemviews/private/kfileitemmodeldirlister.h @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (C) 2006-2012 by Peter Penz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#ifndef KFILEITEMMODELDIRLISTER_H +#define KFILEITEMMODELDIRLISTER_H + +#include +#include + +/** + * @brief Extends the class KDirLister by emitting a signal when an + * error occurred instead of showing an error dialog. + * KDirLister::autoErrorHandlingEnabled() is set to false. + */ +class LIBDOLPHINPRIVATE_EXPORT KFileItemModelDirLister : public KDirLister +{ + Q_OBJECT + +public: + KFileItemModelDirLister(QObject* parent = 0); + virtual ~KFileItemModelDirLister(); + +signals: + /** Is emitted whenever an error has occurred. */ + void errorMessage(const QString& msg); + +protected: + virtual void handleError(KIO::Job* job); +}; + +#endif diff --git a/src/kitemviews/private/kfileitemmodelfilter.cpp b/src/kitemviews/private/kfileitemmodelfilter.cpp new file mode 100644 index 000000000..816d35634 --- /dev/null +++ b/src/kitemviews/private/kfileitemmodelfilter.cpp @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright (C) 2011 by Janardhan Reddy * + * * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#include "kfileitemmodelfilter.h" + +#include +#include + +KFileItemModelFilter::KFileItemModelFilter() : + m_useRegExp(false), + m_regExp(0), + m_lowerCasePattern(), + m_pattern() +{ +} + +KFileItemModelFilter::~KFileItemModelFilter() +{ + delete m_regExp; + m_regExp = 0; +} + +void KFileItemModelFilter::setPattern(const QString& filter) +{ + m_pattern = filter; + m_lowerCasePattern = filter.toLower(); + + m_useRegExp = filter.contains('*') || + filter.contains('?') || + filter.contains('['); + if (m_useRegExp) { + if (!m_regExp) { + m_regExp = new QRegExp(); + m_regExp->setCaseSensitivity(Qt::CaseInsensitive); + m_regExp->setMinimal(false); + m_regExp->setPatternSyntax(QRegExp::WildcardUnix); + } + m_regExp->setPattern(filter); + } +} + +QString KFileItemModelFilter::pattern() const +{ + return m_pattern; +} + +bool KFileItemModelFilter::matches(const KFileItem& item) const +{ + if (m_useRegExp) { + return m_regExp->exactMatch(item.text()); + } else { + return item.text().toLower().contains(m_lowerCasePattern); + } +} diff --git a/src/kitemviews/private/kfileitemmodelfilter.h b/src/kitemviews/private/kfileitemmodelfilter.h new file mode 100644 index 000000000..9bdf1fd95 --- /dev/null +++ b/src/kitemviews/private/kfileitemmodelfilter.h @@ -0,0 +1,70 @@ +/*************************************************************************** + * Copyright (C) 2011 by Janardhan Reddy * + * * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#ifndef KFILEITEMMODELFILTER_H +#define KFILEITEMMODELFILTER_H + +#include +#include + +class KFileItem; +class QRegExp; + +/** + * @brief Allows to check whether an item of the KFileItemModel + * matches with a set filter-string. + * + * Currently the filter is only checked for the KFileItem::text() + * property of the KFileItem, but this might get extended in + * future. + */ +class LIBDOLPHINPRIVATE_EXPORT KFileItemModelFilter +{ + +public: + KFileItemModelFilter(); + virtual ~KFileItemModelFilter(); + + /** + * Sets the pattern that is used for a comparison with the item + * in KFileItemModelFilter::matches(). Per default the pattern + * defines a sub-string. As soon as the pattern contains at least + * a '*', '?' or '[' the pattern represents a regular expression. + */ + void setPattern(const QString& pattern); + QString pattern() const; + + /** + * @return True if the item matches with the pattern defined by + * KFileItemModelFilter::setPattern(). + */ + bool matches(const KFileItem& item) const; + +private: + bool m_useRegExp; // If true, m_regExp is used for filtering, + // otherwise m_lowerCaseFilter is used. + QRegExp* m_regExp; + QString m_lowerCasePattern; // Lowercase version of m_filter for + // faster comparison in matches(). + QString m_pattern; // Property set by setFilter(). +}; +#endif + + diff --git a/src/kitemviews/private/kfileitemmodelsortalgorithm.cpp b/src/kitemviews/private/kfileitemmodelsortalgorithm.cpp new file mode 100644 index 000000000..e0aac13de --- /dev/null +++ b/src/kitemviews/private/kfileitemmodelsortalgorithm.cpp @@ -0,0 +1,148 @@ +/*************************************************************************** + * Copyright (C) 2012 by Peter Penz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#include "kfileitemmodelsortalgorithm.h" + +void KFileItemModelSortAlgorithm::sort(KFileItemModel* model, + QList::iterator begin, + QList::iterator end) +{ + // The implementation is based on qStableSortHelper() from qalgorithms.h + // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + + const int span = end - begin; + if (span < 2) { + return; + } + + const QList::iterator middle = begin + span / 2; + sort(model, begin, middle); + sort(model, middle, end); + merge(model, begin, middle, end); +} + +void KFileItemModelSortAlgorithm::merge(KFileItemModel* model, + QList::iterator begin, + QList::iterator pivot, + QList::iterator end) +{ + // The implementation is based on qMerge() from qalgorithms.h + // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + + const int len1 = pivot - begin; + const int len2 = end - pivot; + + if (len1 == 0 || len2 == 0) { + return; + } + + if (len1 + len2 == 2) { + if (model->lessThan(*(begin + 1), *(begin))) { + qSwap(*begin, *(begin + 1)); + } + return; + } + + QList::iterator firstCut; + QList::iterator secondCut; + int len2Half; + if (len1 > len2) { + const int len1Half = len1 / 2; + firstCut = begin + len1Half; + secondCut = lowerBound(model, pivot, end, *firstCut); + len2Half = secondCut - pivot; + } else { + len2Half = len2 / 2; + secondCut = pivot + len2Half; + firstCut = upperBound(model, begin, pivot, *secondCut); + } + + reverse(firstCut, pivot); + reverse(pivot, secondCut); + reverse(firstCut, secondCut); + + const QList::iterator newPivot = firstCut + len2Half; + merge(model, begin, firstCut, newPivot); + merge(model, newPivot, secondCut, end); +} + + +QList::iterator +KFileItemModelSortAlgorithm::lowerBound(KFileItemModel* model, + QList::iterator begin, + QList::iterator end, + const KFileItemModel::ItemData* value) +{ + // The implementation is based on qLowerBound() from qalgorithms.h + // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + + QList::iterator middle; + int n = int(end - begin); + int half; + + while (n > 0) { + half = n >> 1; + middle = begin + half; + if (model->lessThan(*middle, value)) { + begin = middle + 1; + n -= half + 1; + } else { + n = half; + } + } + return begin; +} + +QList::iterator +KFileItemModelSortAlgorithm::upperBound(KFileItemModel* model, + QList::iterator begin, + QList::iterator end, + const KFileItemModel::ItemData* value) +{ + // The implementation is based on qUpperBound() from qalgorithms.h + // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + + QList::iterator middle; + int n = end - begin; + int half; + + while (n > 0) { + half = n >> 1; + middle = begin + half; + if (model->lessThan(value, *middle)) { + n = half; + } else { + begin = middle + 1; + n -= half + 1; + } + } + return begin; +} + +void KFileItemModelSortAlgorithm::reverse(QList::iterator begin, + QList::iterator end) +{ + // The implementation is based on qReverse() from qalgorithms.h + // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + + --end; + while (begin < end) { + qSwap(*begin++, *end--); + } +} diff --git a/src/kitemviews/private/kfileitemmodelsortalgorithm.h b/src/kitemviews/private/kfileitemmodelsortalgorithm.h new file mode 100644 index 000000000..3a596dff5 --- /dev/null +++ b/src/kitemviews/private/kfileitemmodelsortalgorithm.h @@ -0,0 +1,70 @@ +/*************************************************************************** + * Copyright (C) 2012 by Peter Penz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#ifndef KFILEITEMMODELSORTALGORITHM_H +#define KFILEITEMMODELSORTALGORITHM_H + +#include + +#include + +/** + * @brief Sort algorithm for sorting items of KFileItemModel. + * + * Sorts the items by using KFileItemModel::lessThan() as comparison criteria. + * The merge sort algorithm is used to assure a worst-case + * of O(n * log(n)) and to keep the number of comparisons low. + * + * The implementation is based on qStableSortHelper() from qalgorithms.h + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + * The sorting implementations of qAlgorithms could not be used as they + * don't support having a member-function as comparison criteria. + */ +class LIBDOLPHINPRIVATE_EXPORT KFileItemModelSortAlgorithm +{ +public: + static void sort(KFileItemModel* model, + QList::iterator begin, + QList::iterator end); + +private: + static void merge(KFileItemModel* model, + QList::iterator begin, + QList::iterator pivot, + QList::iterator end); + + static QList::iterator + lowerBound(KFileItemModel* model, + QList::iterator begin, + QList::iterator end, + const KFileItemModel::ItemData* value); + + static QList::iterator + upperBound(KFileItemModel* model, + QList::iterator begin, + QList::iterator end, + const KFileItemModel::ItemData* value); + + static void reverse(QList::iterator begin, + QList::iterator end); +}; + +#endif + + diff --git a/src/kitemviews/private/kitemlistheaderwidget.cpp b/src/kitemviews/private/kitemlistheaderwidget.cpp new file mode 100644 index 000000000..576516f25 --- /dev/null +++ b/src/kitemviews/private/kitemlistheaderwidget.cpp @@ -0,0 +1,535 @@ +/*************************************************************************** + * Copyright (C) 2011 by Peter Penz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#include "kitemlistheaderwidget.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include + +KItemListHeaderWidget::KItemListHeaderWidget(QGraphicsWidget* parent) : + QGraphicsWidget(parent), + m_automaticColumnResizing(true), + m_model(0), + m_offset(0), + m_columns(), + m_columnWidths(), + m_preferredColumnWidths(), + m_hoveredRoleIndex(-1), + m_pressedRoleIndex(-1), + m_roleOperation(NoRoleOperation), + m_pressedMousePos(), + m_movingRole() +{ + m_movingRole.x = 0; + m_movingRole.xDec = 0; + m_movingRole.index = -1; + + setAcceptHoverEvents(true); +} + +KItemListHeaderWidget::~KItemListHeaderWidget() +{ +} + +void KItemListHeaderWidget::setModel(KItemModelBase* model) +{ + if (m_model == model) { + return; + } + + if (m_model) { + disconnect(m_model, SIGNAL(sortRoleChanged(QByteArray,QByteArray)), + this, SLOT(slotSortRoleChanged(QByteArray,QByteArray))); + disconnect(m_model, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)), + this, SLOT(slotSortOrderChanged(Qt::SortOrder,Qt::SortOrder))); + } + + m_model = model; + + if (m_model) { + connect(m_model, SIGNAL(sortRoleChanged(QByteArray,QByteArray)), + this, SLOT(slotSortRoleChanged(QByteArray,QByteArray))); + connect(m_model, SIGNAL(sortOrderChanged(Qt::SortOrder,Qt::SortOrder)), + this, SLOT(slotSortOrderChanged(Qt::SortOrder,Qt::SortOrder))); + } +} + +KItemModelBase* KItemListHeaderWidget::model() const +{ + return m_model; +} + +void KItemListHeaderWidget::setAutomaticColumnResizing(bool automatic) +{ + m_automaticColumnResizing = automatic; +} + +bool KItemListHeaderWidget::automaticColumnResizing() const +{ + return m_automaticColumnResizing; +} + +void KItemListHeaderWidget::setColumns(const QList& roles) +{ + foreach (const QByteArray& role, roles) { + if (!m_columnWidths.contains(role)) { + m_columnWidths.remove(role); + m_preferredColumnWidths.remove(role); + } + } + + m_columns = roles; + update(); +} + +QList KItemListHeaderWidget::columns() const +{ + return m_columns; +} + +void KItemListHeaderWidget::setColumnWidth(const QByteArray& role, qreal width) +{ + const qreal minWidth = minimumColumnWidth(); + if (width < minWidth) { + width = minWidth; + } + + if (m_columnWidths.value(role) != width) { + m_columnWidths.insert(role, width); + update(); + } +} + +qreal KItemListHeaderWidget::columnWidth(const QByteArray& role) const +{ + return m_columnWidths.value(role); +} + +void KItemListHeaderWidget::setPreferredColumnWidth(const QByteArray& role, qreal width) +{ + m_preferredColumnWidths.insert(role, width); +} + +qreal KItemListHeaderWidget::preferredColumnWidth(const QByteArray& role) const +{ + return m_preferredColumnWidths.value(role); +} + +void KItemListHeaderWidget::setOffset(qreal offset) +{ + if (m_offset != offset) { + m_offset = offset; + update(); + } +} + +qreal KItemListHeaderWidget::offset() const +{ + return m_offset; +} + +qreal KItemListHeaderWidget::minimumColumnWidth() const +{ + QFontMetricsF fontMetrics(font()); + return fontMetrics.height() * 4; +} + +void KItemListHeaderWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + if (!m_model) { + return; + } + + // Draw roles + painter->setFont(font()); + painter->setPen(palette().text().color()); + + qreal x = -m_offset; + int orderIndex = 0; + foreach (const QByteArray& role, m_columns) { + const qreal roleWidth = m_columnWidths.value(role); + const QRectF rect(x, 0, roleWidth, size().height()); + paintRole(painter, role, rect, orderIndex, widget); + x += roleWidth; + ++orderIndex; + } + + // Draw background without roles + QStyleOption opt; + opt.init(widget); + opt.rect = QRect(x, 0, size().width() - x, size().height()); + opt.state |= QStyle::State_Horizontal; + style()->drawControl(QStyle::CE_HeaderEmptyArea, &opt, painter); + + if (!m_movingRole.pixmap.isNull()) { + Q_ASSERT(m_roleOperation == MoveRoleOperation); + painter->drawPixmap(m_movingRole.x, 0, m_movingRole.pixmap); + } +} + +void KItemListHeaderWidget::mousePressEvent(QGraphicsSceneMouseEvent* event) +{ + if (event->button() & Qt::LeftButton) { + updatePressedRoleIndex(event->pos()); + m_pressedMousePos = event->pos(); + m_roleOperation = isAboveRoleGrip(m_pressedMousePos, m_pressedRoleIndex) ? + ResizeRoleOperation : NoRoleOperation; + event->accept(); + } else { + event->ignore(); + } +} + +void KItemListHeaderWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) +{ + QGraphicsWidget::mouseReleaseEvent(event); + + if (m_pressedRoleIndex == -1) { + return; + } + + switch (m_roleOperation) { + case NoRoleOperation: { + // Only a click has been done and no moving or resizing has been started + const QByteArray sortRole = m_model->sortRole(); + const int sortRoleIndex = m_columns.indexOf(sortRole); + if (m_pressedRoleIndex == sortRoleIndex) { + // Toggle the sort order + const Qt::SortOrder previous = m_model->sortOrder(); + const Qt::SortOrder current = (m_model->sortOrder() == Qt::AscendingOrder) ? + Qt::DescendingOrder : Qt::AscendingOrder; + m_model->setSortOrder(current); + emit sortOrderChanged(current, previous); + } else { + // Change the sort role + const QByteArray previous = m_model->sortRole(); + const QByteArray current = m_columns[m_pressedRoleIndex]; + m_model->setSortRole(current); + emit sortRoleChanged(current, previous); + } + break; + } + + case MoveRoleOperation: + m_movingRole.pixmap = QPixmap(); + m_movingRole.x = 0; + m_movingRole.xDec = 0; + m_movingRole.index = -1; + break; + + default: + break; + } + + m_pressedRoleIndex = -1; + m_roleOperation = NoRoleOperation; + update(); + + QApplication::restoreOverrideCursor(); +} + +void KItemListHeaderWidget::mouseMoveEvent(QGraphicsSceneMouseEvent* event) +{ + QGraphicsWidget::mouseMoveEvent(event); + + switch (m_roleOperation) { + case NoRoleOperation: + if ((event->pos() - m_pressedMousePos).manhattanLength() >= QApplication::startDragDistance()) { + // A role gets dragged by the user. Create a pixmap of the role that will get + // synchronized on each furter mouse-move-event with the mouse-position. + m_roleOperation = MoveRoleOperation; + const int roleIndex = roleIndexAt(m_pressedMousePos); + m_movingRole.index = roleIndex; + if (roleIndex == 0) { + // TODO: It should be configurable whether moving the first role is allowed. + // In the context of Dolphin this is not required, however this should be + // changed if KItemViews are used in a more generic way. + QApplication::setOverrideCursor(QCursor(Qt::ForbiddenCursor)); + } else { + m_movingRole.pixmap = createRolePixmap(roleIndex); + + qreal roleX = -m_offset; + for (int i = 0; i < roleIndex; ++i) { + const QByteArray role = m_columns[i]; + roleX += m_columnWidths.value(role); + } + + m_movingRole.xDec = event->pos().x() - roleX; + m_movingRole.x = roleX; + update(); + } + } + break; + + case ResizeRoleOperation: { + const QByteArray pressedRole = m_columns[m_pressedRoleIndex]; + + qreal previousWidth = m_columnWidths.value(pressedRole); + qreal currentWidth = previousWidth; + currentWidth += event->pos().x() - event->lastPos().x(); + currentWidth = qMax(minimumColumnWidth(), currentWidth); + + m_columnWidths.insert(pressedRole, currentWidth); + update(); + + emit columnWidthChanged(pressedRole, currentWidth, previousWidth); + break; + } + + case MoveRoleOperation: { + // TODO: It should be configurable whether moving the first role is allowed. + // In the context of Dolphin this is not required, however this should be + // changed if KItemViews are used in a more generic way. + if (m_movingRole.index > 0) { + m_movingRole.x = event->pos().x() - m_movingRole.xDec; + update(); + + const int targetIndex = targetOfMovingRole(); + if (targetIndex > 0 && targetIndex != m_movingRole.index) { + const QByteArray role = m_columns[m_movingRole.index]; + const int previousIndex = m_movingRole.index; + m_movingRole.index = targetIndex; + emit columnMoved(role, targetIndex, previousIndex); + + m_movingRole.xDec = event->pos().x() - roleXPosition(role); + } + } + break; + } + + default: + break; + } +} + +void KItemListHeaderWidget::hoverEnterEvent(QGraphicsSceneHoverEvent* event) +{ + QGraphicsWidget::hoverEnterEvent(event); + updateHoveredRoleIndex(event->pos()); +} + +void KItemListHeaderWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent* event) +{ + QGraphicsWidget::hoverLeaveEvent(event); + if (m_hoveredRoleIndex != -1) { + m_hoveredRoleIndex = -1; + update(); + } +} + +void KItemListHeaderWidget::hoverMoveEvent(QGraphicsSceneHoverEvent* event) +{ + QGraphicsWidget::hoverMoveEvent(event); + + const QPointF& pos = event->pos(); + updateHoveredRoleIndex(pos); + if (m_hoveredRoleIndex >= 0 && isAboveRoleGrip(pos, m_hoveredRoleIndex)) { + setCursor(Qt::SplitHCursor); + } else { + unsetCursor(); + } +} + +void KItemListHeaderWidget::slotSortRoleChanged(const QByteArray& current, const QByteArray& previous) +{ + Q_UNUSED(current); + Q_UNUSED(previous); + update(); +} + +void KItemListHeaderWidget::slotSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous) +{ + Q_UNUSED(current); + Q_UNUSED(previous); + update(); +} + +void KItemListHeaderWidget::paintRole(QPainter* painter, + const QByteArray& role, + const QRectF& rect, + int orderIndex, + QWidget* widget) const +{ + // The following code is based on the code from QHeaderView::paintSection(). + // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + QStyleOptionHeader option; + option.section = orderIndex; + option.state = QStyle::State_None | QStyle::State_Raised | QStyle::State_Horizontal; + if (isEnabled()) { + option.state |= QStyle::State_Enabled; + } + if (window() && window()->isActiveWindow()) { + option.state |= QStyle::State_Active; + } + if (m_hoveredRoleIndex == orderIndex) { + option.state |= QStyle::State_MouseOver; + } + if (m_pressedRoleIndex == orderIndex) { + option.state |= QStyle::State_Sunken; + } + if (m_model->sortRole() == role) { + option.sortIndicator = (m_model->sortOrder() == Qt::AscendingOrder) ? + QStyleOptionHeader::SortDown : QStyleOptionHeader::SortUp; + } + option.rect = rect.toRect(); + + if (m_columns.count() == 1) { + option.position = QStyleOptionHeader::OnlyOneSection; + } else if (orderIndex == 0) { + option.position = QStyleOptionHeader::Beginning; + } else if (orderIndex == m_columns.count() - 1) { + option.position = QStyleOptionHeader::End; + } else { + option.position = QStyleOptionHeader::Middle; + } + + option.orientation = Qt::Horizontal; + option.selectedPosition = QStyleOptionHeader::NotAdjacent; + option.text = m_model->roleDescription(role); + + style()->drawControl(QStyle::CE_Header, &option, painter, widget); +} + +void KItemListHeaderWidget::updatePressedRoleIndex(const QPointF& pos) +{ + const int pressedIndex = roleIndexAt(pos); + if (m_pressedRoleIndex != pressedIndex) { + m_pressedRoleIndex = pressedIndex; + update(); + } +} + +void KItemListHeaderWidget::updateHoveredRoleIndex(const QPointF& pos) +{ + const int hoverIndex = roleIndexAt(pos); + if (m_hoveredRoleIndex != hoverIndex) { + m_hoveredRoleIndex = hoverIndex; + update(); + } +} + +int KItemListHeaderWidget::roleIndexAt(const QPointF& pos) const +{ + int index = -1; + + qreal x = -m_offset; + foreach (const QByteArray& role, m_columns) { + ++index; + x += m_columnWidths.value(role); + if (pos.x() <= x) { + break; + } + } + + return index; +} + +bool KItemListHeaderWidget::isAboveRoleGrip(const QPointF& pos, int roleIndex) const +{ + qreal x = -m_offset; + for (int i = 0; i <= roleIndex; ++i) { + const QByteArray role = m_columns[i]; + x += m_columnWidths.value(role); + } + + const int grip = style()->pixelMetric(QStyle::PM_HeaderGripMargin); + return pos.x() >= (x - grip) && pos.x() <= x; +} + +QPixmap KItemListHeaderWidget::createRolePixmap(int roleIndex) const +{ + const QByteArray role = m_columns[roleIndex]; + const qreal roleWidth = m_columnWidths.value(role); + const QRect rect(0, 0, roleWidth, size().height()); + + QImage image(rect.size(), QImage::Format_ARGB32_Premultiplied); + + QPainter painter(&image); + paintRole(&painter, role, rect, roleIndex); + + // Apply a highlighting-color + const QPalette::ColorGroup group = isActiveWindow() ? QPalette::Active : QPalette::Inactive; + QColor highlightColor = palette().color(group, QPalette::Highlight); + highlightColor.setAlpha(64); + painter.fillRect(rect, highlightColor); + + // Make the image transparent + painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); + painter.fillRect(0, 0, image.width(), image.height(), QColor(0, 0, 0, 192)); + + return QPixmap::fromImage(image); +} + +int KItemListHeaderWidget::targetOfMovingRole() const +{ + const int movingWidth = m_movingRole.pixmap.width(); + const int movingLeft = m_movingRole.x; + const int movingRight = movingLeft + movingWidth - 1; + + int targetIndex = 0; + qreal targetLeft = -m_offset; + while (targetIndex < m_columns.count()) { + const QByteArray role = m_columns[targetIndex]; + const qreal targetWidth = m_columnWidths.value(role); + const qreal targetRight = targetLeft + targetWidth - 1; + + const bool isInTarget = (targetWidth >= movingWidth && + movingLeft >= targetLeft && + movingRight <= targetRight) || + (targetWidth < movingWidth && + movingLeft <= targetLeft && + movingRight >= targetRight); + + if (isInTarget) { + return targetIndex; + } + + targetLeft += targetWidth; + ++targetIndex; + } + + return m_movingRole.index; +} + +qreal KItemListHeaderWidget::roleXPosition(const QByteArray& role) const +{ + qreal x = -m_offset; + foreach (const QByteArray& visibleRole, m_columns) { + if (visibleRole == role) { + return x; + } + + x += m_columnWidths.value(visibleRole); + } + + return -1; +} + +#include "kitemlistheaderwidget.moc" diff --git a/src/kitemviews/private/kitemlistheaderwidget.h b/src/kitemviews/private/kitemlistheaderwidget.h new file mode 100644 index 000000000..f8bba977b --- /dev/null +++ b/src/kitemviews/private/kitemlistheaderwidget.h @@ -0,0 +1,171 @@ +/*************************************************************************** + * Copyright (C) 2011 by Peter Penz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#ifndef KITEMLISTHEADERWIDGET_H +#define KITEMLISTHEADERWIDGET_H + +#include +#include +#include +#include + +class KItemModelBase; + +/** + * @brief Widget the implements the header for KItemListView showing the currently used roles. + * + * The widget is an internal API, the user of KItemListView may only access the + * class KItemListHeader. + */ +class LIBDOLPHINPRIVATE_EXPORT KItemListHeaderWidget : public QGraphicsWidget +{ + Q_OBJECT + +public: + KItemListHeaderWidget(QGraphicsWidget* parent = 0); + virtual ~KItemListHeaderWidget(); + + void setModel(KItemModelBase* model); + KItemModelBase* model() const; + + void setAutomaticColumnResizing(bool automatic); + bool automaticColumnResizing() const; + + void setColumns(const QList& roles); + QList columns() const; + + void setColumnWidth(const QByteArray& role, qreal width); + qreal columnWidth(const QByteArray& role) const; + + /** + * Sets the column-width that is required to show the role unclipped. + */ + void setPreferredColumnWidth(const QByteArray& role, qreal width); + qreal preferredColumnWidth(const QByteArray& role) const; + + void setOffset(qreal offset); + qreal offset() const; + + qreal minimumColumnWidth() const; + + virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0); + +signals: + /** + * Is emitted if the width of a visible role has been adjusted by the user with the mouse + * (no signal is emitted if KItemListHeader::setVisibleRoleWidth() is invoked). + */ + void columnWidthChanged(const QByteArray& role, + qreal currentWidth, + qreal previousWidth); + + /** + * Is emitted if the position of the column has been changed. + */ + void columnMoved(const QByteArray& role, int currentIndex, int previousIndex); + + /** + * Is emitted if the user has changed the sort order by clicking on a + * header item. The sort order of the model has already been adjusted to + * the current sort order. Note that no signal will be emitted if the + * sort order of the model has been changed without user interaction. + */ + void sortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous); + + /** + * Is emitted if the user has changed the sort role by clicking on a + * header item. The sort role of the model has already been adjusted to + * the current sort role. Note that no signal will be emitted if the + * sort role of the model has been changed without user interaction. + */ + void sortRoleChanged(const QByteArray& current, const QByteArray& previous); + +protected: + virtual void mousePressEvent(QGraphicsSceneMouseEvent* event); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent* event); + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent* event); + virtual void hoverEnterEvent(QGraphicsSceneHoverEvent* event); + virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent* event); + virtual void hoverMoveEvent(QGraphicsSceneHoverEvent* event); + +private slots: + void slotSortRoleChanged(const QByteArray& current, const QByteArray& previous); + void slotSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous); + +private: + void paintRole(QPainter* painter, + const QByteArray& role, + const QRectF& rect, + int orderIndex, + QWidget* widget = 0) const; + + void updatePressedRoleIndex(const QPointF& pos); + void updateHoveredRoleIndex(const QPointF& pos); + int roleIndexAt(const QPointF& pos) const; + bool isAboveRoleGrip(const QPointF& pos, int roleIndex) const; + + /** + * Creates a pixmap of the role with the index \a roleIndex that is shown + * during moving a role. + */ + QPixmap createRolePixmap(int roleIndex) const; + + /** + * @return Target index of the currently moving visible role based on the current + * state of m_movingRole. + */ + int targetOfMovingRole() const; + + /** + * @return x-position of the left border of the role \a role. + */ + qreal roleXPosition(const QByteArray& role) const; + +private: + enum RoleOperation + { + NoRoleOperation, + ResizeRoleOperation, + MoveRoleOperation + }; + + bool m_automaticColumnResizing; + KItemModelBase* m_model; + qreal m_offset; + QList m_columns; + QHash m_columnWidths; + QHash m_preferredColumnWidths; + + int m_hoveredRoleIndex; + int m_pressedRoleIndex; + RoleOperation m_roleOperation; + QPointF m_pressedMousePos; + + struct MovingRole + { + QPixmap pixmap; + int x; + int xDec; + int index; + } m_movingRole; +}; + +#endif + + diff --git a/src/kitemviews/private/kitemlistkeyboardsearchmanager.cpp b/src/kitemviews/private/kitemlistkeyboardsearchmanager.cpp new file mode 100644 index 000000000..2f4e93b1d --- /dev/null +++ b/src/kitemviews/private/kitemlistkeyboardsearchmanager.cpp @@ -0,0 +1,78 @@ +/*************************************************************************** + * Copyright (C) 2011 by Tirtha Chatterjee * + * * + * Based on the Itemviews NG project from Trolltech Labs: * + * http://qt.gitorious.org/qt-labs/itemviews-ng * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#include "kitemlistkeyboardsearchmanager.h" + +#include +#include + +#include + +KItemListKeyboardSearchManager::KItemListKeyboardSearchManager(QObject* parent) : + QObject(parent), + m_timeout(5000) +{ + m_keyboardInputTime.invalidate(); +} + +KItemListKeyboardSearchManager::~KItemListKeyboardSearchManager() +{ +} + +void KItemListKeyboardSearchManager::addKeys(const QString& keys) +{ + const bool keyboardTimeWasValid = m_keyboardInputTime.isValid(); + const qint64 keyboardInputTimeElapsed = m_keyboardInputTime.restart(); + if (keyboardInputTimeElapsed > m_timeout || !keyboardTimeWasValid || keys.isEmpty()) { + m_searchedString.clear(); + } + + const bool newSearch = m_searchedString.isEmpty(); + + if (!keys.isEmpty()) { + m_searchedString.append(keys); + + // Special case: + // If the same key is pressed repeatedly, the next item matching that key should be highlighted + const QChar firstKey = m_searchedString.length() > 0 ? m_searchedString.at(0) : QChar(); + const bool sameKey = m_searchedString.length() > 1 && m_searchedString.count(firstKey) == m_searchedString.length(); + + // Searching for a matching item should start from the next item if either + // 1. a new search is started, or + // 2. a 'repeated key' search is done. + const bool searchFromNextItem = newSearch || sameKey; + + emit changeCurrentItem(sameKey ? firstKey : m_searchedString, searchFromNextItem); + } + m_keyboardInputTime.start(); +} + +void KItemListKeyboardSearchManager::setTimeout(qint64 milliseconds) +{ + m_timeout = milliseconds; +} + +qint64 KItemListKeyboardSearchManager::timeout() const +{ + return m_timeout; +} + diff --git a/src/kitemviews/private/kitemlistrubberband.cpp b/src/kitemviews/private/kitemlistrubberband.cpp new file mode 100644 index 000000000..ae023d2aa --- /dev/null +++ b/src/kitemviews/private/kitemlistrubberband.cpp @@ -0,0 +1,75 @@ +/*************************************************************************** + * Copyright (C) 2011 by Peter Penz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#include "kitemlistrubberband.h" + +KItemListRubberBand::KItemListRubberBand(QObject* parent) : + QObject(parent), + m_active(false), + m_startPos(), + m_endPos() +{ +} + +KItemListRubberBand::~KItemListRubberBand() +{ +} + +void KItemListRubberBand::setStartPosition(const QPointF& pos) +{ + if (m_startPos != pos) { + const QPointF previous = m_startPos; + m_startPos = pos; + emit startPositionChanged(m_startPos, previous); + } +} + +QPointF KItemListRubberBand::startPosition() const +{ + return m_startPos; +} + +void KItemListRubberBand::setEndPosition(const QPointF& pos) +{ + if (m_endPos != pos) { + const QPointF previous = m_endPos; + m_endPos = pos; + emit endPositionChanged(m_endPos, previous); + } +} + +QPointF KItemListRubberBand::endPosition() const +{ + return m_endPos; +} + +void KItemListRubberBand::setActive(bool active) +{ + if (m_active != active) { + m_active = active; + emit activationChanged(active); + } +} + +bool KItemListRubberBand::isActive() const +{ + return m_active; +} + +#include "kitemlistrubberband.moc" diff --git a/src/kitemviews/private/kitemlistselectiontoggle.cpp b/src/kitemviews/private/kitemlistselectiontoggle.cpp new file mode 100644 index 000000000..66da6a727 --- /dev/null +++ b/src/kitemviews/private/kitemlistselectiontoggle.cpp @@ -0,0 +1,106 @@ +/*************************************************************************** + * Copyright (C) 2011 by Peter Penz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#include "kitemlistselectiontoggle.h" + +#include +#include +#include + +#include + +KItemListSelectionToggle::KItemListSelectionToggle(QGraphicsItem* parent) : + QGraphicsWidget(parent, 0), + m_checked(false), + m_hovered(false) +{ + setAcceptHoverEvents(true); +} + +KItemListSelectionToggle::~KItemListSelectionToggle() +{ +} + +void KItemListSelectionToggle::setChecked(bool checked) +{ + if (m_checked != checked) { + m_checked = checked; + m_pixmap = QPixmap(); + update(); + } +} + +bool KItemListSelectionToggle::isChecked() const +{ + return m_checked; +} + +void KItemListSelectionToggle::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + if (m_pixmap.isNull()) { + updatePixmap(); + } + + const qreal x = (size().width() - qreal(m_pixmap.width())) / 2; + const qreal y = (size().height() - qreal(m_pixmap.height())) / 2; + 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::updatePixmap() +{ + const char* icon = m_checked ? "list-remove" : "list-add"; + + int iconSize = qMin(size().width(), size().height()); + if (iconSize < KIconLoader::SizeSmallMedium) { + iconSize = KIconLoader::SizeSmall; + } else if (iconSize < KIconLoader::SizeMedium) { + iconSize = KIconLoader::SizeSmallMedium; + } else if (iconSize < KIconLoader::SizeLarge) { + iconSize = KIconLoader::SizeMedium; + } else if (iconSize < KIconLoader::SizeHuge) { + iconSize = KIconLoader::SizeLarge; + } else if (iconSize < KIconLoader::SizeEnormous) { + iconSize = KIconLoader::SizeHuge; + } + + m_pixmap = KIconLoader::global()->loadIcon(QLatin1String(icon), KIconLoader::NoGroup, iconSize); + + if (m_hovered) { + KIconLoader::global()->iconEffect()->apply(m_pixmap, KIconLoader::Desktop, KIconLoader::ActiveState); + } +} + +#include "kitemlistselectiontoggle.moc" diff --git a/src/kitemviews/private/kitemlistselectiontoggle.h b/src/kitemviews/private/kitemlistselectiontoggle.h new file mode 100644 index 000000000..a8050d811 --- /dev/null +++ b/src/kitemviews/private/kitemlistselectiontoggle.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (C) 2011 by Peter Penz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#ifndef KITEMLISTSELECTIONTOGGLE_H +#define KITEMLISTSELECTIONTOGGLE_H + +#include + +#include +#include + +class QPropertyAnimation; + +/** + * @brief Allows to toggle between the selected and unselected state of an item. + */ +class LIBDOLPHINPRIVATE_EXPORT KItemListSelectionToggle : public QGraphicsWidget +{ + Q_OBJECT + +public: + KItemListSelectionToggle(QGraphicsItem* parent); + virtual ~KItemListSelectionToggle(); + + void setChecked(bool checked); + bool isChecked() const; + + virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0); + +protected: + virtual void hoverEnterEvent(QGraphicsSceneHoverEvent* event); + virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent* event); + +private: + void updatePixmap(); + +private: + bool m_checked; + bool m_hovered; + QPixmap m_pixmap; +}; + +#endif + + diff --git a/src/kitemviews/private/kitemlistsizehintresolver.cpp b/src/kitemviews/private/kitemlistsizehintresolver.cpp new file mode 100644 index 000000000..c76ff0f55 --- /dev/null +++ b/src/kitemviews/private/kitemlistsizehintresolver.cpp @@ -0,0 +1,88 @@ +/*************************************************************************** + * Copyright (C) 2011 by Peter Penz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#include "kitemlistsizehintresolver.h" + +#include +#include + +KItemListSizeHintResolver::KItemListSizeHintResolver(const KItemListView* itemListView) : + m_itemListView(itemListView), + m_sizeHintCache() +{ +} + +KItemListSizeHintResolver::~KItemListSizeHintResolver() +{ +} + +QSizeF KItemListSizeHintResolver::sizeHint(int index) const +{ + QSizeF size = m_sizeHintCache.at(index); + if (size.isEmpty()) { + size = m_itemListView->itemSizeHint(index); + m_sizeHintCache[index] = size; + } + return size; +} + +void KItemListSizeHintResolver::itemsInserted(int index, int count) +{ + const int currentCount = m_sizeHintCache.count(); + m_sizeHintCache.reserve(currentCount + count); + while (count > 0) { + m_sizeHintCache.insert(index, QSizeF()); + ++index; + --count; + } +} + +void KItemListSizeHintResolver::itemsRemoved(int index, int count) +{ + const QList::iterator begin = m_sizeHintCache.begin() + index; + const QList::iterator end = begin + count; + m_sizeHintCache.erase(begin, end); +} + +void KItemListSizeHintResolver::itemsMoved(int index, int count) +{ + while (count) { + m_sizeHintCache[index] = QSizeF(); + ++index; + --count; + } +} + +void KItemListSizeHintResolver::itemsChanged(int index, int count, const QSet& roles) +{ + Q_UNUSED(roles); + while (count) { + m_sizeHintCache[index] = QSizeF(); + ++index; + --count; + } +} + +void KItemListSizeHintResolver::clearCache() +{ + const int count = m_sizeHintCache.count(); + for (int i = 0; i < count; ++i) { + m_sizeHintCache[i] = QSizeF(); + } +} diff --git a/src/kitemviews/private/kitemlistsizehintresolver.h b/src/kitemviews/private/kitemlistsizehintresolver.h new file mode 100644 index 000000000..1345e0321 --- /dev/null +++ b/src/kitemviews/private/kitemlistsizehintresolver.h @@ -0,0 +1,53 @@ +/*************************************************************************** + * Copyright (C) 2011 by Peter Penz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#ifndef KITEMLISTSIZEHINTRESOLVER_H +#define KITEMLISTSIZEHINTRESOLVER_H + +#include + +#include +#include +#include + +class KItemListView; + +/** + * @brief Calculates and caches the sizehints of items in KItemListView. + */ +class LIBDOLPHINPRIVATE_EXPORT KItemListSizeHintResolver +{ +public: + KItemListSizeHintResolver(const KItemListView* itemListView); + virtual ~KItemListSizeHintResolver(); + QSizeF sizeHint(int index) const; + + void itemsInserted(int index, int count); + void itemsRemoved(int index, int count); + void itemsMoved(int index, int count); + void itemsChanged(int index, int count, const QSet& roles); + + void clearCache(); + +private: + const KItemListView* m_itemListView; + mutable QList m_sizeHintCache; +}; + +#endif diff --git a/src/kitemviews/private/kitemlistsmoothscroller.cpp b/src/kitemviews/private/kitemlistsmoothscroller.cpp new file mode 100644 index 000000000..6987e1ce1 --- /dev/null +++ b/src/kitemviews/private/kitemlistsmoothscroller.cpp @@ -0,0 +1,207 @@ +/*************************************************************************** + * Copyright (C) 2011 by Peter Penz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#include "kitemlistsmoothscroller.h" + +#include +#include +#include +#include +#include + +#include + +KItemListSmoothScroller::KItemListSmoothScroller(QScrollBar* scrollBar, + QObject* parent) : + QObject(parent), + m_scrollBarPressed(false), + m_smoothScrolling(true), + m_scrollBar(scrollBar), + m_animation(0) +{ + m_animation = new QPropertyAnimation(this); + const int duration = (KGlobalSettings::graphicEffectsLevel() == KGlobalSettings::NoEffects) ? 1 : 100; + m_animation->setDuration(duration); + connect(m_animation, SIGNAL(stateChanged(QAbstractAnimation::State,QAbstractAnimation::State)), + this, SLOT(slotAnimationStateChanged(QAbstractAnimation::State,QAbstractAnimation::State))); + + m_scrollBar->installEventFilter(this); +} + +KItemListSmoothScroller::~KItemListSmoothScroller() +{ +} + +void KItemListSmoothScroller::setScrollBar(QScrollBar *scrollBar) +{ + m_scrollBar = scrollBar; +} + +QScrollBar* KItemListSmoothScroller::scrollBar() const +{ + return m_scrollBar; +} + +void KItemListSmoothScroller::setTargetObject(QObject* target) +{ + m_animation->setTargetObject(target); +} + +QObject* KItemListSmoothScroller::targetObject() const +{ + return m_animation->targetObject(); +} + +void KItemListSmoothScroller::setPropertyName(const QByteArray& propertyName) +{ + m_animation->setPropertyName(propertyName); +} + +QByteArray KItemListSmoothScroller::propertyName() const +{ + return m_animation->propertyName(); +} + +void KItemListSmoothScroller::scrollContentsBy(qreal distance) +{ + QObject* target = targetObject(); + if (!target) { + return; + } + + const QByteArray name = propertyName(); + const qreal currentOffset = target->property(name).toReal(); + if (static_cast(currentOffset) == m_scrollBar->value()) { + // The current offset is already synchronous to the scrollbar + return; + } + + const bool animRunning = (m_animation->state() == QAbstractAnimation::Running); + if (animRunning) { + // Stopping a running animation means skipping the range from the current offset + // until the target offset. To prevent skipping of the range the difference + // is added to the new target offset. + const qreal oldEndOffset = m_animation->endValue().toReal(); + distance += (currentOffset - oldEndOffset); + } + + const qreal endOffset = currentOffset - distance; + if (m_smoothScrolling || animRunning) { + qreal startOffset = currentOffset; + if (animRunning) { + // If the animation was running and has been interrupted by assigning a new end-offset + // one frame must be added to the start-offset to keep the animation smooth. This also + // assures that animation proceeds even in cases where new end-offset are triggered + // within a very short timeslots. + startOffset += (endOffset - currentOffset) * 1000 / (m_animation->duration() * 60); + if (currentOffset < endOffset) { + startOffset = qMin(startOffset, endOffset); + } else { + startOffset = qMax(startOffset, endOffset); + } + } + + m_animation->stop(); + m_animation->setStartValue(startOffset); + m_animation->setEndValue(endOffset); + m_animation->setEasingCurve(animRunning ? QEasingCurve::OutQuad : QEasingCurve::InOutQuad); + m_animation->start(); + target->setProperty(name, startOffset); + } else { + target->setProperty(name, endOffset); + } +} + +void KItemListSmoothScroller::scrollTo(qreal position) +{ + m_smoothScrolling = true; + m_scrollBar->setValue(position); +} + +bool KItemListSmoothScroller::requestScrollBarUpdate(int newMaximum) +{ + if (m_animation->state() == QAbstractAnimation::Running) { + if (newMaximum == m_scrollBar->maximum()) { + // The value has been changed by the animation, no update + // of the scrollbars is required as their target state will be + // reached with the end of the animation. + return false; + } + + // The maximum has been changed which indicates that the content + // of the view has been changed. Stop the animation in any case and + // update the scrollbars immediately. + m_animation->stop(); + } + return true; +} + +bool KItemListSmoothScroller::eventFilter(QObject* obj, QEvent* event) +{ + Q_ASSERT(obj == m_scrollBar); + + switch (event->type()) { + case QEvent::MouseButtonPress: + m_scrollBarPressed = true; + m_smoothScrolling = true; + break; + + case QEvent::MouseButtonRelease: + m_scrollBarPressed = false; + m_smoothScrolling = false; + break; + + case QEvent::Wheel: + handleWheelEvent(static_cast(event)); + break; + + default: + break; + } + + return QObject::eventFilter(obj, event); +} + +void KItemListSmoothScroller::slotAnimationStateChanged(QAbstractAnimation::State newState, + QAbstractAnimation::State oldState) +{ + Q_UNUSED(oldState); + if (newState == QAbstractAnimation::Stopped && m_smoothScrolling && !m_scrollBarPressed) { + m_smoothScrolling = false; + } +} + +void KItemListSmoothScroller::handleWheelEvent(QWheelEvent* event) +{ + const int numDegrees = event->delta() / 8; + const int numSteps = numDegrees / 15; + + const bool previous = m_smoothScrolling; + + m_smoothScrolling = true; + const int value = m_scrollBar->value(); + const int pageStep = m_scrollBar->pageStep(); + m_scrollBar->setValue(value - numSteps * pageStep); + + m_smoothScrolling = previous; + + event->accept(); +} + +#include "kitemlistsmoothscroller.moc" diff --git a/src/kitemviews/private/kitemlistsmoothscroller.h b/src/kitemviews/private/kitemlistsmoothscroller.h new file mode 100644 index 000000000..252c966c7 --- /dev/null +++ b/src/kitemviews/private/kitemlistsmoothscroller.h @@ -0,0 +1,103 @@ +/*************************************************************************** + * Copyright (C) 2011 by Peter Penz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#ifndef KITEMLISTSMOOTHSCROLLER_H +#define KITEMLISTSMOOTHSCROLLER_H + +#include + +#include +#include + +class QPropertyAnimation; +class QScrollBar; +class QWheelEvent; + +/** + * @brief Helper class for KItemListContainer to have a smooth + * scrolling when adjusting the scrollbars. + */ +class LIBDOLPHINPRIVATE_EXPORT KItemListSmoothScroller : public QObject +{ + Q_OBJECT + +public: + KItemListSmoothScroller(QScrollBar* scrollBar, + QObject* parent = 0); + virtual ~KItemListSmoothScroller(); + + void setScrollBar(QScrollBar* scrollBar); + QScrollBar* scrollBar() const; + + void setTargetObject(QObject* target); + QObject* targetObject() const; + + void setPropertyName(const QByteArray& propertyName); + QByteArray propertyName() const; + + /** + * Adjusts the position of the target by \p distance + * pixels. Is invoked in the context of QAbstractScrollArea::scrollContentsBy() + * where the scrollbars already have the new position but the content + * has not been scrolled yet. + */ + void scrollContentsBy(qreal distance); + + /** + * Does a smooth-scrolling to the position \p position + * on the target and also adjusts the corresponding scrollbar + * to the new position. + */ + void scrollTo(qreal position); + + /** + * Must be invoked before the scrollbar should get updated to have a new + * maximum. True is returned if the new maximum can be applied. If false + * is returned the maximum has already been reached and the value will + * be reached at the end of the animation. + */ + // TODO: This interface is tricky to understand. Try to make this more + // generic/readable if the corresponding code in KItemListContainer got + // stable. + bool requestScrollBarUpdate(int newMaximum); + +protected: + virtual bool eventFilter(QObject* obj, QEvent* event); + +private slots: + void slotAnimationStateChanged(QAbstractAnimation::State newState, + QAbstractAnimation::State oldState); + +private: + /** + * Results into a smooth-scrolling of the target dependent on the direction + * of the wheel event. + */ + void handleWheelEvent(QWheelEvent* event); + +private: + bool m_scrollBarPressed; + bool m_smoothScrolling; + QScrollBar* m_scrollBar; + QPropertyAnimation* m_animation; +}; + +#endif + + diff --git a/src/kitemviews/private/kitemlistviewanimation.cpp b/src/kitemviews/private/kitemlistviewanimation.cpp new file mode 100644 index 000000000..e347c5bb1 --- /dev/null +++ b/src/kitemviews/private/kitemlistviewanimation.cpp @@ -0,0 +1,245 @@ +/*************************************************************************** + * Copyright (C) 2011 by Peter Penz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#include "kitemlistviewanimation.h" + +#include + +#include +#include + +#include +#include + +KItemListViewAnimation::KItemListViewAnimation(QObject* parent) : + QObject(parent), + m_animationDuration(200), + m_scrollOrientation(Qt::Vertical), + m_scrollOffset(0), + m_animation() +{ + if (KGlobalSettings::graphicEffectsLevel() == KGlobalSettings::NoEffects) { + m_animationDuration = 1; + } +} + +KItemListViewAnimation::~KItemListViewAnimation() +{ + for (int type = 0; type < AnimationTypeCount; ++type) { + qDeleteAll(m_animation[type]); + } +} + +void KItemListViewAnimation::setScrollOrientation(Qt::Orientation orientation) +{ + m_scrollOrientation = orientation; +} + +Qt::Orientation KItemListViewAnimation::scrollOrientation() const +{ + return m_scrollOrientation; +} + +void KItemListViewAnimation::setScrollOffset(qreal offset) +{ + const qreal diff = m_scrollOffset - offset; + m_scrollOffset = offset; + + // The change of the offset requires that the position of all + // animated QGraphicsWidgets get adjusted. An exception is made + // for the delete animation that should just fade away on the + // existing position. + for (int type = 0; type < AnimationTypeCount; ++type) { + if (type == DeleteAnimation) { + continue; + } + + QHashIterator it(m_animation[type]); + while (it.hasNext()) { + it.next(); + + QGraphicsWidget* widget = it.key(); + QPropertyAnimation* propertyAnim = it.value(); + + QPointF currentPos = widget->pos(); + if (m_scrollOrientation == Qt::Vertical) { + currentPos.ry() += diff; + } else { + currentPos.rx() += diff; + } + + if (type == MovingAnimation) { + // Stop the animation, calculate the moved start- and end-value + // and restart the animation for the remaining duration. + const int remainingDuration = propertyAnim->duration() + - propertyAnim->currentTime(); + + const bool block = propertyAnim->signalsBlocked(); + propertyAnim->blockSignals(true); + propertyAnim->stop(); + + QPointF endPos = propertyAnim->endValue().toPointF(); + if (m_scrollOrientation == Qt::Vertical) { + endPos.ry() += diff; + } else { + endPos.rx() += diff; + } + + propertyAnim->setDuration(remainingDuration); + propertyAnim->setStartValue(currentPos); + propertyAnim->setEndValue(endPos); + propertyAnim->start(); + propertyAnim->blockSignals(block); + } else { + widget->setPos(currentPos); + } + } + } +} + +qreal KItemListViewAnimation::scrollOffset() const +{ + return m_scrollOffset; +} + +void KItemListViewAnimation::start(QGraphicsWidget* widget, AnimationType type, const QVariant& endValue) +{ + stop(widget, type); + + QPropertyAnimation* propertyAnim = 0; + + switch (type) { + case MovingAnimation: { + const QPointF newPos = endValue.toPointF(); + if (newPos == widget->pos()) { + return; + } + + propertyAnim = new QPropertyAnimation(widget, "pos"); + propertyAnim->setDuration(m_animationDuration); + propertyAnim->setEndValue(newPos); + break; + } + + case CreateAnimation: { + propertyAnim = new QPropertyAnimation(widget, "opacity"); + propertyAnim->setEasingCurve(QEasingCurve::InQuart); + propertyAnim->setDuration(m_animationDuration); + propertyAnim->setStartValue(0.0); + propertyAnim->setEndValue(1.0); + break; + } + + case DeleteAnimation: { + propertyAnim = new QPropertyAnimation(widget, "opacity"); + propertyAnim->setEasingCurve(QEasingCurve::OutQuart); + propertyAnim->setDuration(m_animationDuration); + propertyAnim->setStartValue(1.0); + propertyAnim->setEndValue(0.0); + break; + } + + case ResizeAnimation: { + const QSizeF newSize = endValue.toSizeF(); + if (newSize == widget->size()) { + return; + } + + propertyAnim = new QPropertyAnimation(widget, "size"); + propertyAnim->setDuration(m_animationDuration); + propertyAnim->setEndValue(newSize); + break; + } + + default: + break; + } + + Q_ASSERT(propertyAnim); + connect(propertyAnim, SIGNAL(finished()), this, SLOT(slotFinished())); + m_animation[type].insert(widget, propertyAnim); + + propertyAnim->start(); +} + +void KItemListViewAnimation::stop(QGraphicsWidget* widget, AnimationType type) +{ + QPropertyAnimation* propertyAnim = m_animation[type].value(widget); + if (propertyAnim) { + propertyAnim->stop(); + + switch (type) { + case MovingAnimation: break; + case CreateAnimation: widget->setOpacity(1.0); break; + case DeleteAnimation: widget->setOpacity(0.0); break; + case ResizeAnimation: break; + default: break; + } + + m_animation[type].remove(widget); + delete propertyAnim; + + emit finished(widget, type); + } +} + +void KItemListViewAnimation::stop(QGraphicsWidget* widget) +{ + for (int type = 0; type < AnimationTypeCount; ++type) { + stop(widget, static_cast(type)); + } +} + +bool KItemListViewAnimation::isStarted(QGraphicsWidget *widget, AnimationType type) const +{ + return m_animation[type].value(widget); +} + +bool KItemListViewAnimation::isStarted(QGraphicsWidget* widget) const +{ + for (int type = 0; type < AnimationTypeCount; ++type) { + if (isStarted(widget, static_cast(type))) { + return true; + } + } + return false; +} + +void KItemListViewAnimation::slotFinished() +{ + QPropertyAnimation* finishedAnim = qobject_cast(sender()); + for (int type = 0; type < AnimationTypeCount; ++type) { + QHashIterator 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); + finishedAnim->deleteLater(); + + emit finished(widget, static_cast(type)); + return; + } + } + } + Q_ASSERT(false); +} + +#include "kitemlistviewanimation.moc" diff --git a/src/kitemviews/private/kitemlistviewanimation.h b/src/kitemviews/private/kitemlistviewanimation.h new file mode 100644 index 000000000..a3aceb0f5 --- /dev/null +++ b/src/kitemviews/private/kitemlistviewanimation.h @@ -0,0 +1,106 @@ +/*************************************************************************** + * Copyright (C) 2011 by Peter Penz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#ifndef KITEMLISTVIEWANIMATION_H +#define KITEMLISTVIEWANIMATION_H + +#include + +#include +#include +#include + +class KItemListView; +class QGraphicsWidget; +class QPointF; +class QPropertyAnimation; + +/** + * @brief Internal helper class for KItemListView to animate the items. + * + * Supports item animations for moving, creating, deleting and resizing + * an item. Several applications can be applied to one item in parallel. + */ +class LIBDOLPHINPRIVATE_EXPORT KItemListViewAnimation : public QObject +{ + Q_OBJECT + +public: + enum AnimationType { + MovingAnimation, + CreateAnimation, + DeleteAnimation, + ResizeAnimation + }; + + KItemListViewAnimation(QObject* parent = 0); + virtual ~KItemListViewAnimation(); + + void setScrollOrientation(Qt::Orientation orientation); + Qt::Orientation scrollOrientation() const; + + void setScrollOffset(qreal scrollOffset); + qreal scrollOffset() const; + + /** + * Starts the animation of the type \a type for the widget \a widget. If an animation + * of the type is already running, this animation will be stopped before starting + * the new animation. + */ + void start(QGraphicsWidget* widget, AnimationType type, const QVariant& endValue = QVariant()); + + /** + * Stops the animation of the type \a type for the widget \a widget. + */ + void stop(QGraphicsWidget* widget, AnimationType type); + + /** + * Stops all animations that have been applied to the widget \a widget. + */ + void stop(QGraphicsWidget* widget); + + /** + * @return True if the animation of the type \a type has been started + * for the widget \a widget.. + */ + bool isStarted(QGraphicsWidget *widget, AnimationType type) const; + + /** + * @return True if any animation has been started for the widget. + */ + bool isStarted(QGraphicsWidget* widget) const; + +signals: + void finished(QGraphicsWidget* widget, KItemListViewAnimation::AnimationType type); + +private slots: + void slotFinished(); + +private: + enum { AnimationTypeCount = 4 }; + + int m_animationDuration; + Qt::Orientation m_scrollOrientation; + qreal m_scrollOffset; + QHash m_animation[AnimationTypeCount]; +}; + +#endif + + diff --git a/src/kitemviews/private/kitemlistviewlayouter.cpp b/src/kitemviews/private/kitemlistviewlayouter.cpp new file mode 100644 index 000000000..c15b44e13 --- /dev/null +++ b/src/kitemviews/private/kitemlistviewlayouter.cpp @@ -0,0 +1,630 @@ +/*************************************************************************** + * Copyright (C) 2011 by Peter Penz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#include "kitemlistviewlayouter.h" + +#include +#include "kitemlistsizehintresolver.h" + +#include + +// #define KITEMLISTVIEWLAYOUTER_DEBUG + +KItemListViewLayouter::KItemListViewLayouter(QObject* parent) : + QObject(parent), + m_dirty(true), + m_visibleIndexesDirty(true), + m_scrollOrientation(Qt::Vertical), + m_size(), + m_itemSize(128, 128), + m_itemMargin(), + m_headerHeight(0), + m_model(0), + m_sizeHintResolver(0), + m_scrollOffset(0), + m_maximumScrollOffset(0), + m_itemOffset(0), + m_maximumItemOffset(0), + m_firstVisibleIndex(-1), + m_lastVisibleIndex(-1), + m_columnWidth(0), + m_xPosInc(0), + m_columnCount(0), + m_groupItemIndexes(), + m_groupHeaderHeight(0), + m_groupHeaderMargin(0), + m_itemInfos() +{ +} + +KItemListViewLayouter::~KItemListViewLayouter() +{ +} + +void KItemListViewLayouter::setScrollOrientation(Qt::Orientation orientation) +{ + if (m_scrollOrientation != orientation) { + m_scrollOrientation = orientation; + m_dirty = true; + } +} + +Qt::Orientation KItemListViewLayouter::scrollOrientation() const +{ + return m_scrollOrientation; +} + +void KItemListViewLayouter::setSize(const QSizeF& size) +{ + if (m_size != size) { + m_size = size; + m_dirty = true; + } +} + +QSizeF KItemListViewLayouter::size() const +{ + return m_size; +} + +void KItemListViewLayouter::setItemSize(const QSizeF& size) +{ + if (m_itemSize != size) { + m_itemSize = size; + m_dirty = true; + } +} + +QSizeF KItemListViewLayouter::itemSize() const +{ + return m_itemSize; +} + +void KItemListViewLayouter::setItemMargin(const QSizeF& margin) +{ + if (m_itemMargin != margin) { + m_itemMargin = margin; + m_dirty = true; + } +} + +QSizeF KItemListViewLayouter::itemMargin() const +{ + return m_itemMargin; +} + +void KItemListViewLayouter::setHeaderHeight(qreal height) +{ + if (m_headerHeight != height) { + m_headerHeight = height; + m_dirty = true; + } +} + +qreal KItemListViewLayouter::headerHeight() const +{ + return m_headerHeight; +} + +void KItemListViewLayouter::setGroupHeaderHeight(qreal height) +{ + if (m_groupHeaderHeight != height) { + m_groupHeaderHeight = height; + m_dirty = true; + } +} + +qreal KItemListViewLayouter::groupHeaderHeight() const +{ + return m_groupHeaderHeight; +} + +void KItemListViewLayouter::setGroupHeaderMargin(qreal margin) +{ + if (m_groupHeaderMargin != margin) { + m_groupHeaderMargin = margin; + m_dirty = true; + } +} + +qreal KItemListViewLayouter::groupHeaderMargin() const +{ + return m_groupHeaderMargin; +} + +void KItemListViewLayouter::setScrollOffset(qreal offset) +{ + if (m_scrollOffset != offset) { + m_scrollOffset = offset; + m_visibleIndexesDirty = true; + } +} + +qreal KItemListViewLayouter::scrollOffset() const +{ + return m_scrollOffset; +} + +qreal KItemListViewLayouter::maximumScrollOffset() const +{ + const_cast(this)->doLayout(); + return m_maximumScrollOffset; +} + +void KItemListViewLayouter::setItemOffset(qreal offset) +{ + if (m_itemOffset != offset) { + m_itemOffset = offset; + m_visibleIndexesDirty = true; + } +} + +qreal KItemListViewLayouter::itemOffset() const +{ + return m_itemOffset; +} + +qreal KItemListViewLayouter::maximumItemOffset() const +{ + const_cast(this)->doLayout(); + return m_maximumItemOffset; +} + +void KItemListViewLayouter::setModel(const KItemModelBase* model) +{ + if (m_model != model) { + m_model = model; + m_dirty = true; + } +} + +const KItemModelBase* KItemListViewLayouter::model() const +{ + return m_model; +} + +void KItemListViewLayouter::setSizeHintResolver(const KItemListSizeHintResolver* sizeHintResolver) +{ + if (m_sizeHintResolver != sizeHintResolver) { + m_sizeHintResolver = sizeHintResolver; + m_dirty = true; + } +} + +const KItemListSizeHintResolver* KItemListViewLayouter::sizeHintResolver() const +{ + return m_sizeHintResolver; +} + +int KItemListViewLayouter::firstVisibleIndex() const +{ + const_cast(this)->doLayout(); + return m_firstVisibleIndex; +} + +int KItemListViewLayouter::lastVisibleIndex() const +{ + const_cast(this)->doLayout(); + return m_lastVisibleIndex; +} + +QRectF KItemListViewLayouter::itemRect(int index) const +{ + const_cast(this)->doLayout(); + if (index < 0 || index >= m_itemInfos.count()) { + return QRectF(); + } + + if (m_scrollOrientation == Qt::Horizontal) { + // Rotate the logical direction which is always vertical by 90° + // to get the physical horizontal direction + const QRectF& b = m_itemInfos[index].rect; + QRectF bounds(b.y(), b.x(), b.height(), b.width()); + QPointF pos = bounds.topLeft(); + pos.rx() -= m_scrollOffset; + bounds.moveTo(pos); + return bounds; + } + + QRectF bounds = m_itemInfos[index].rect; + bounds.moveTo(bounds.topLeft() - QPointF(m_itemOffset, m_scrollOffset)); + return bounds; +} + +QRectF KItemListViewLayouter::groupHeaderRect(int index) const +{ + const_cast(this)->doLayout(); + + const QRectF firstItemRect = itemRect(index); + QPointF pos = firstItemRect.topLeft(); + if (pos.isNull()) { + return QRectF(); + } + + QSizeF size; + if (m_scrollOrientation == Qt::Vertical) { + pos.rx() = 0; + pos.ry() -= m_groupHeaderHeight; + size = QSizeF(m_size.width(), m_groupHeaderHeight); + } else { + pos.rx() -= m_itemMargin.width(); + pos.ry() = 0; + + // Determine the maximum width used in the + // current column. As the scroll-direction is + // Qt::Horizontal and m_itemRects is accessed directly, + // the logical height represents the visual width. + qreal width = minimumGroupHeaderWidth(); + const qreal y = m_itemInfos[index].rect.y(); + const int maxIndex = m_itemInfos.count() - 1; + while (index <= maxIndex) { + QRectF bounds = m_itemInfos[index].rect; + if (bounds.y() != y) { + break; + } + + if (bounds.height() > width) { + width = bounds.height(); + } + + ++index; + } + + size = QSizeF(width, m_size.height()); + } + return QRectF(pos, size); +} + +int KItemListViewLayouter::itemColumn(int index) const +{ + const_cast(this)->doLayout(); + if (index < 0 || index >= m_itemInfos.count()) { + return -1; + } + + return (m_scrollOrientation == Qt::Vertical) + ? m_itemInfos[index].column + : m_itemInfos[index].row; +} + +int KItemListViewLayouter::itemRow(int index) const +{ + const_cast(this)->doLayout(); + if (index < 0 || index >= m_itemInfos.count()) { + return -1; + } + + return (m_scrollOrientation == Qt::Vertical) + ? m_itemInfos[index].row + : m_itemInfos[index].column; +} + +int KItemListViewLayouter::maximumVisibleItems() const +{ + const_cast(this)->doLayout(); + + const int height = static_cast(m_size.height()); + const int rowHeight = static_cast(m_itemSize.height()); + int rows = height / rowHeight; + if (height % rowHeight != 0) { + ++rows; + } + + return rows * m_columnCount; +} + +bool KItemListViewLayouter::isFirstGroupItem(int itemIndex) const +{ + const_cast(this)->doLayout(); + return m_groupItemIndexes.contains(itemIndex); +} + +void KItemListViewLayouter::markAsDirty() +{ + m_dirty = true; +} + + +#ifndef QT_NO_DEBUG + bool KItemListViewLayouter::isDirty() + { + return m_dirty; + } +#endif + +void KItemListViewLayouter::doLayout() +{ + if (m_dirty) { +#ifdef KITEMLISTVIEWLAYOUTER_DEBUG + QElapsedTimer timer; + timer.start(); +#endif + m_visibleIndexesDirty = true; + + QSizeF itemSize = m_itemSize; + QSizeF itemMargin = m_itemMargin; + QSizeF size = m_size; + + const bool grouped = createGroupHeaders(); + + const bool horizontalScrolling = (m_scrollOrientation == Qt::Horizontal); + if (horizontalScrolling) { + // Flip everything so that the layout logically can work like having + // a vertical scrolling + itemSize.setWidth(m_itemSize.height()); + itemSize.setHeight(m_itemSize.width()); + itemMargin.setWidth(m_itemMargin.height()); + itemMargin.setHeight(m_itemMargin.width()); + size.setWidth(m_size.height()); + size.setHeight(m_size.width()); + + if (grouped) { + // In the horizontal scrolling case all groups are aligned + // at the top, which decreases the available height. For the + // flipped data this means that the width must be decreased. + size.rwidth() -= m_groupHeaderHeight; + } + } + + m_columnWidth = itemSize.width() + itemMargin.width(); + const qreal widthForColumns = size.width() - itemMargin.width(); + m_columnCount = qMax(1, int(widthForColumns / m_columnWidth)); + m_xPosInc = itemMargin.width(); + + const int itemCount = m_model->count(); + if (itemCount > m_columnCount && m_columnWidth >= 32) { + // Apply the unused width equally to each column + const qreal unusedWidth = widthForColumns - m_columnCount * m_columnWidth; + if (unusedWidth > 0) { + const qreal columnInc = unusedWidth / (m_columnCount + 1); + m_columnWidth += columnInc; + m_xPosInc += columnInc; + } + } + + int rowCount = itemCount / m_columnCount; + if (itemCount % m_columnCount != 0) { + ++rowCount; + } + + m_itemInfos.reserve(itemCount); + + qreal y = m_headerHeight + itemMargin.height(); + int row = 0; + + int index = 0; + while (index < itemCount) { + qreal x = m_xPosInc; + qreal maxItemHeight = itemSize.height(); + + if (grouped) { + if (horizontalScrolling) { + // All group headers will always be aligned on the top and not + // flipped like the other properties + x += m_groupHeaderHeight; + } + + if (m_groupItemIndexes.contains(index)) { + // The item is the first item of a group. + // Increase the y-position to provide space + // for the group header. + if (index > 0) { + // Only add a margin if there has been added another + // group already before + y += m_groupHeaderMargin; + } else if (!horizontalScrolling) { + // The first group header should be aligned on top + y -= itemMargin.height(); + } + + if (!horizontalScrolling) { + y += m_groupHeaderHeight; + } + } + } + + int column = 0; + while (index < itemCount && column < m_columnCount) { + qreal requiredItemHeight = itemSize.height(); + if (m_sizeHintResolver) { + const QSizeF sizeHint = m_sizeHintResolver->sizeHint(index); + const qreal sizeHintHeight = horizontalScrolling ? sizeHint.width() : sizeHint.height(); + if (sizeHintHeight > requiredItemHeight) { + requiredItemHeight = sizeHintHeight; + } + } + + const QRectF bounds(x, y, itemSize.width(), requiredItemHeight); + if (index < m_itemInfos.count()) { + m_itemInfos[index].rect = bounds; + m_itemInfos[index].column = column; + m_itemInfos[index].row = row; + } else { + ItemInfo itemInfo; + itemInfo.rect = bounds; + itemInfo.column = column; + itemInfo.row = row; + m_itemInfos.append(itemInfo); + } + + if (grouped && horizontalScrolling) { + // When grouping is enabled in the horizontal mode, the header alignment + // looks like this: + // Header-1 Header-2 Header-3 + // Item 1 Item 4 Item 7 + // Item 2 Item 5 Item 8 + // Item 3 Item 6 Item 9 + // In this case 'requiredItemHeight' represents the column-width. We don't + // check the content of the header in the layouter to determine the required + // width, hence assure that at least a minimal width of 15 characters is given + // (in average a character requires the halve width of the font height). + // + // TODO: Let the group headers provide a minimum width and respect this width here + const qreal headerWidth = minimumGroupHeaderWidth(); + if (requiredItemHeight < headerWidth) { + requiredItemHeight = headerWidth; + } + } + + maxItemHeight = qMax(maxItemHeight, requiredItemHeight); + x += m_columnWidth; + ++index; + ++column; + + if (grouped && m_groupItemIndexes.contains(index)) { + // The item represents the first index of a group + // and must aligned in the first column + break; + } + } + + y += maxItemHeight + itemMargin.height(); + ++row; + } + if (m_itemInfos.count() > itemCount) { + m_itemInfos.erase(m_itemInfos.begin() + itemCount, + m_itemInfos.end()); + } + + if (itemCount > 0) { + // Calculate the maximum y-range of the last row for m_maximumScrollOffset + m_maximumScrollOffset = m_itemInfos.last().rect.bottom(); + const qreal rowY = m_itemInfos.last().rect.y(); + + int index = m_itemInfos.count() - 2; + while (index >= 0 && m_itemInfos[index].rect.bottom() >= rowY) { + m_maximumScrollOffset = qMax(m_maximumScrollOffset, m_itemInfos[index].rect.bottom()); + --index; + } + + m_maximumScrollOffset += itemMargin.height(); + + m_maximumItemOffset = m_columnCount * m_columnWidth; + } else { + m_maximumScrollOffset = 0; + m_maximumItemOffset = 0; + } + +#ifdef KITEMLISTVIEWLAYOUTER_DEBUG + kDebug() << "[TIME] doLayout() for " << m_model->count() << "items:" << timer.elapsed(); +#endif + m_dirty = false; + } + + updateVisibleIndexes(); +} + +void KItemListViewLayouter::updateVisibleIndexes() +{ + if (!m_visibleIndexesDirty) { + return; + } + + Q_ASSERT(!m_dirty); + + if (m_model->count() <= 0) { + m_firstVisibleIndex = -1; + m_lastVisibleIndex = -1; + m_visibleIndexesDirty = false; + return; + } + + const int maxIndex = m_model->count() - 1; + + // Calculate the first visible index that is fully visible + int min = 0; + int max = maxIndex; + int mid = 0; + do { + mid = (min + max) / 2; + if (m_itemInfos[mid].rect.top() < m_scrollOffset) { + min = mid + 1; + } else { + max = mid - 1; + } + } while (min <= max); + + if (mid > 0) { + // Include the row before the first fully visible index, as it might + // be partly visible + if (m_itemInfos[mid].rect.top() >= m_scrollOffset) { + --mid; + Q_ASSERT(m_itemInfos[mid].rect.top() < m_scrollOffset); + } + + const qreal rowTop = m_itemInfos[mid].rect.top(); + while (mid > 0 && m_itemInfos[mid - 1].rect.top() == rowTop) { + --mid; + } + } + m_firstVisibleIndex = mid; + + // Calculate the last visible index that is (at least partly) visible + const int visibleHeight = (m_scrollOrientation == Qt::Horizontal) ? m_size.width() : m_size.height(); + qreal bottom = m_scrollOffset + visibleHeight; + if (m_model->groupedSorting()) { + bottom += m_groupHeaderHeight; + } + + min = m_firstVisibleIndex; + max = maxIndex; + do { + mid = (min + max) / 2; + if (m_itemInfos[mid].rect.y() <= bottom) { + min = mid + 1; + } else { + max = mid - 1; + } + } while (min <= max); + + while (mid > 0 && m_itemInfos[mid].rect.y() > bottom) { + --mid; + } + m_lastVisibleIndex = mid; + + m_visibleIndexesDirty = false; +} + +bool KItemListViewLayouter::createGroupHeaders() +{ + if (!m_model->groupedSorting()) { + return false; + } + + m_groupItemIndexes.clear(); + + const QList > groups = m_model->groups(); + if (groups.isEmpty()) { + return false; + } + + for (int i = 0; i < groups.count(); ++i) { + const int firstItemIndex = groups.at(i).first; + m_groupItemIndexes.insert(firstItemIndex); + } + + return true; +} + +qreal KItemListViewLayouter::minimumGroupHeaderWidth() const +{ + return 100; +} + +#include "kitemlistviewlayouter.moc" diff --git a/src/kitemviews/private/kitemlistviewlayouter.h b/src/kitemviews/private/kitemlistviewlayouter.h new file mode 100644 index 000000000..da5bd1d7d --- /dev/null +++ b/src/kitemviews/private/kitemlistviewlayouter.h @@ -0,0 +1,235 @@ +/*************************************************************************** + * Copyright (C) 2011 by Peter Penz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#ifndef KITEMLISTVIEWLAYOUTER_H +#define KITEMLISTVIEWLAYOUTER_H + +#include + +#include +#include +#include +#include + +class KItemModelBase; +class KItemListSizeHintResolver; + +/** + * @brief Internal helper class for KItemListView to layout the items. + * + * The layouter is capable to align the items within a grid. If the + * scroll-direction is horizontal the column-width of the grid can be + * variable. If the scroll-direction is vertical the row-height of + * the grid can be variable. + * + * The layouter is implemented in a way that it postpones the expensive + * layout operation until a property is read the first time after + * marking the layouter as dirty (see markAsDirty()). This means that + * changing properties of the layouter is not expensive, only the + * first read of a property can get expensive. + */ +class LIBDOLPHINPRIVATE_EXPORT KItemListViewLayouter : public QObject +{ + Q_OBJECT + +public: + KItemListViewLayouter(QObject* parent = 0); + virtual ~KItemListViewLayouter(); + + void setScrollOrientation(Qt::Orientation orientation); + Qt::Orientation scrollOrientation() const; + + void setSize(const QSizeF& size); + QSizeF size() const; + + void setItemSize(const QSizeF& size); + QSizeF itemSize() const; + + /** + * Margin between the rows and columns of items. + */ + void setItemMargin(const QSizeF& margin); + QSizeF itemMargin() const; + + /** + * Sets the height of the header that is always aligned + * at the top. A height of <= 0.0 means that no header is + * used. + */ + void setHeaderHeight(qreal height); + qreal headerHeight() const; + + /** + * Sets the height of the group header that is used + * to indicate a new item group. + */ + void setGroupHeaderHeight(qreal height); + qreal groupHeaderHeight() const; + + /** + * Sets the margin between the last items of the group n and + * the group header for the group n + 1. + */ + void setGroupHeaderMargin(qreal margin); + qreal groupHeaderMargin() const; + + void setScrollOffset(qreal scrollOffset); + qreal scrollOffset() const; + + qreal maximumScrollOffset() const; + + void setItemOffset(qreal scrollOffset); + qreal itemOffset() const; + + qreal maximumItemOffset() const; + + void setModel(const KItemModelBase* model); + const KItemModelBase* model() const; + + void setSizeHintResolver(const KItemListSizeHintResolver* sizeHintResolver); + const KItemListSizeHintResolver* sizeHintResolver() const; + + /** + * @return The first (at least partly) visible index. -1 is returned + * if the item count is 0. + */ + int firstVisibleIndex() const; + + /** + * @return The last (at least partly) visible index. -1 is returned + * if the item count is 0. + */ + int lastVisibleIndex() const; + + /** + * @return Rectangle of the item with the index \a index. + * The top/left of the bounding rectangle is related to + * the top/left of the KItemListView. An empty rectangle + * is returned if an invalid index is given. + */ + QRectF itemRect(int index) const; + + /** + * @return Rectangle of the group header for the item with the + * index \a index. Note that the layouter does not check + * whether the item really has a header: Usually only + * the first item of a group gets a header (see + * isFirstGroupItem()). + */ + QRectF groupHeaderRect(int index) const; + + /** + * @return Column of the item with the index \a index. + * -1 is returned if an invalid index is given. + */ + int itemColumn(int index) const; + + /** + * @return Row of the item with the index \a index. + * -1 is returned if an invalid index is given. + */ + int itemRow(int index) const; + + /** + * @return Maximum number of (at least partly) visible items for + * the given size. + */ + int maximumVisibleItems() const; + + /** + * @return True if the item with the index \p itemIndex + * is the first item within a group. + */ + bool isFirstGroupItem(int itemIndex) const; + + /** + * Marks the layouter as dirty. This means as soon as a property of + * the layouter gets read, an expensive relayout will be done. + */ + void markAsDirty(); + +#ifndef QT_NO_DEBUG + /** + * @return True if the layouter has been marked as dirty and hence has + * not called yet doLayout(). Is enabled only in the debugging + * mode, as it is not useful to check the dirty state otherwise. + */ + bool isDirty(); +#endif + +private: + void doLayout(); + void updateVisibleIndexes(); + bool createGroupHeaders(); + + /** + * @return Minimum width of group headers when grouping is enabled in the horizontal + * alignment mode. The header alignment is done like this: + * Header-1 Header-2 Header-3 + * Item 1 Item 4 Item 7 + * Item 2 Item 5 Item 8 + * Item 3 Item 6 Item 9 + */ + qreal minimumGroupHeaderWidth() const; + +private: + bool m_dirty; + bool m_visibleIndexesDirty; + + Qt::Orientation m_scrollOrientation; + QSizeF m_size; + + QSizeF m_itemSize; + QSizeF m_itemMargin; + qreal m_headerHeight; + const KItemModelBase* m_model; + const KItemListSizeHintResolver* m_sizeHintResolver; + + qreal m_scrollOffset; + qreal m_maximumScrollOffset; + + qreal m_itemOffset; + qreal m_maximumItemOffset; + + int m_firstVisibleIndex; + int m_lastVisibleIndex; + + qreal m_columnWidth; + qreal m_xPosInc; + int m_columnCount; + + // Stores all item indexes that are the first item of a group. + // Assures fast access for KItemListViewLayouter::isFirstGroupItem(). + QSet m_groupItemIndexes; + qreal m_groupHeaderHeight; + qreal m_groupHeaderMargin; + + struct ItemInfo { + QRectF rect; + int column; + int row; + }; + QList m_itemInfos; + + friend class KItemListControllerTest; +}; + +#endif + + diff --git a/src/kitemviews/private/knepomukdatamanagement_export.h b/src/kitemviews/private/knepomukdatamanagement_export.h new file mode 100644 index 000000000..929a737c9 --- /dev/null +++ b/src/kitemviews/private/knepomukdatamanagement_export.h @@ -0,0 +1,40 @@ +/* This file is part of the KDE project + Copyright (C) 2007 David Faure + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef NEPOMUKDATAMANAGEMENT_EXPORT_H +#define NEPOMUKDATAMANAGEMENT_EXPORT_H + +/* needed for KDE_EXPORT and KDE_IMPORT macros */ +#include + +#ifndef NEPOMUK_DATA_MANAGEMENT_EXPORT +# if defined(MAKE_NEPOMUKDATAMANAGEMENT_LIB) + /* We are building this library */ +# define NEPOMUK_DATA_MANAGEMENT_EXPORT KDE_EXPORT +# else + /* We are using this library */ +# define NEPOMUK_DATA_MANAGEMENT_EXPORT KDE_IMPORT +# endif +#endif + +# ifndef NEPOMUK_DATA_MANAGEMENT_EXPORT_DEPRECATED +# define NEPOMUK_DATA_MANAGEMENT_EXPORT_DEPRECATED KDE_DEPRECATED NEPOMUK_DATA_MANAGEMENT_EXPORT +# endif + +#endif diff --git a/src/kitemviews/private/knepomukresourcewatcher.h b/src/kitemviews/private/knepomukresourcewatcher.h new file mode 100644 index 000000000..3f6643fc8 --- /dev/null +++ b/src/kitemviews/private/knepomukresourcewatcher.h @@ -0,0 +1,288 @@ +/* + This file is part of the Nepomuk KDE project. + Copyright (C) 2011 Vishesh Handa + Copyright (C) 2011 Sebastian Trueg + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef RESOURCEWATCHER_H +#define RESOURCEWATCHER_H + +#include +#include +#include + +#include +#include + +#include "knepomukdatamanagement_export.h" + +namespace Nepomuk { + + /** + * \class ResourceWatcher resourcewatcher.h + * + * \brief Selectively monitor the nepomuk repository for changes. + * + * Resources may be monitored on the basis of types, properties, and uris. + * + * Changes may be monitored in one of the following ways: + * -# By resources - + * Specify the exact resources that should be watched. Any changes made to the specified resources + * (Excluding \ref nepomuk_dms_metadata) will be notified through the propertyAdded() and propertyRemoved() + * signals. Notifications will also be sent if any of the watched resources is deleted. + * -# By resources and properties - + * Specify the exact resources and their properties. Any changes made to the specified resources + * which touch one of the specified properties will be notified through the propertyAdded() and propertyRemoved() + * signals. + * -# By types - + * Specific types may be specified via add/setType. If types are set, then notifications will be + * sent for all new resources of that type. This includes property changes and resource creation and removal. + * TODO: add flags that allow to only watch for resource creation and removal. + * -# By types and properties - + * Both the types and properties may be specified. Notifications will be sent for property changes + * in resource with the specified types. + * + * \section nepomuk_rw_examples Resource Watcher Usage Example + * + * The following code creates a new ResourceWatcher, configures it to listen to changes on the \c nmm:performer + * property on one specific resource \c res. + * + * \code + * Nepomuk::ResourceWatcher* watcher = new Nepomuk::ResourceWatcher(this); + * watcher->addResource(res); + * watcher->addProperty(NMM:performer()); + * connect(watcher, SIGNAL(propertyAdded(Nepomuk::Resource, Nepomuk::Types::Property, QVariant)), + * this, SLOT(slotPropertyChanged())); + * connect(watcher, SIGNAL(propertyRemoved(Nepomuk::Resource, Nepomuk::Types::Property, QVariant)), + * this, SLOT(slotPropertyChanged())); + * rwatcher->start(); + * \endcode + * + * \author Vishesh Handa , Sebastian Trueg + * + * \ingroup nepomuk_datamanagement + */ + class NEPOMUK_DATA_MANAGEMENT_EXPORT ResourceWatcher : public QObject + { + Q_OBJECT + + public: + /** + * \brief Create a new %ResourceWatcher instance. + * + * This instance will not emit any signals before it has been configured + * and started. + */ + ResourceWatcher( QObject* parent = 0 ); + + /** + * \brief Destructor. + */ + virtual ~ResourceWatcher(); + + /** + * \brief Add a type to be watched. + * + * Every resource of this type will be watched for changes. + * + * \sa setTypes() + */ + void addType( const Types::Class & type ); + + /** + * \brief Add a resource to be watched. + * + * Every change to this resource will be + * signalled, depending on the configured properties(). + * + * \sa setResources() + */ + void addResource( const Nepomuk::Resource & res ); + + /** + * \brief Add a property to be watched. + * + * Every change to a value of this property + * will be signalled, depending on the configured resources() or types(). + * + * \sa setProperties() + */ + void addProperty( const Types::Property & property ); + + /** + * \brief Set the types to be watched. + * + * Every resource having one of these types will be watched for changes. + * + * \sa addType() + */ + void setTypes( const QList & types_ ); + + /** + * \brief Set the resources to be watched. + * + * Every change to one of these resources will be + * signalled, depending on the configured properties(). + * + * \sa addResource() + */ + void setResources( const QList & resources_ ); + + /** + * \brief Set the properties to be watched. + * + * Every change to a value of any of these properties + * will be signalled, depending on the configured resources() or types(). + * + * \sa addProperty() + */ + void setProperties( const QList & properties_ ); + + /** + * \brief The types that have been configured via addType() and setTypes(). + * + * Every resource having one of these types will be watched + * for changes. + */ + QList types() const; + + /** + * \brief The resources that have been configured via addResource() and setResources(). + * + * Every change to one of these resources will be + * signalled, depending on the configured properties(). + */ + QList resources() const; + + /** + * \brief The properties that have been configured via addProperty() and setProperties(). + * + * Every change to a value of any of these properties + * will be signalled, depending on the configured resources() or types(). + */ + QList properties() const; + + public Q_SLOTS: + /** + * \brief Start the signalling of changes. + * + * Before calling this method no signal will be emitted. In + * combination with stop() this allows to suspend the watching. + * Calling start() multiple times has no effect. + */ + bool start(); + + /** + * \brief Stop the signalling of changes. + * + * Allows to stop the watcher which has been started + * via start(). Calling stop() multiple times has no effect. + */ + void stop(); + + Q_SIGNALS: + /** + * \brief This signal is emitted when a new resource is created. + * \param resource The newly created resource. + * \param types The types the new resource has. If types() have been configured this list will always + * contain one of the configured types. + */ + void resourceCreated( const Nepomuk::Resource & resource, const QList& types ); //FIXME: Use either Resource or uri, not a mix + + /** + * \brief This signal is emitted when a resource is deleted. + * \param uri The resource URI of the removed resource. + * \param types The types the removed resource had. If types() have been configured this list will always + * contain one of the configured types. + */ + void resourceRemoved( const QUrl & uri, const QList& types ); + + /** + * \brief This signal is emitted when a type has been added to a resource. This does not include creation which + * is signalled via resourceCreated(). It only applies to changes in a resource's types. + * \param res The changed resource. + * \param type The newly added type. If types() have been configured it will be one of them. + */ + void resourceTypeAdded( const Nepomuk::Resource & res, const Types::Class & type ); + + /** + * \brief This signal is emitted when a type has been removed from a resource. + * + * This does not include removal of entire resources which is signalled via resourceRemoved(). + * It only applies to changes in a resource's types. + * \param res The changed resource. + * \param type The removed type. If types() have been configured it will be one of them. + */ + void resourceTypeRemoved( const Nepomuk::Resource & res, const Types::Class & type ); + + /** + * \brief This signal is emitted when a property value is added. + * \param resource The changed resource. + * \param property The property which has a new value. + * \param value The newly added property value. + */ + void propertyAdded( const Nepomuk::Resource & resource, + const Nepomuk::Types::Property & property, + const QVariant & value ); + + /** + * \brief This signal is emitted when a property value is removed. + * \param resource The changed resource. + * \param property The property which was changed. + * \param value The removed property value. + */ + void propertyRemoved( const Nepomuk::Resource & resource, + const Nepomuk::Types::Property & property, + const QVariant & value ); + + /** + * \brief This signal is emitted when a property value is changed. + * + * This signal cannot be emitted for all changes. It doesn't work if a property is first + * removed and then set, cause the Data Mangement Service does not maintain an internal + * cache for the purpose of emitting the propertyChanged signal. + * + * Specially, since one could theoretically take forever between the removal and the + * setting of the property. + * + * \param resource The changed resource. + * \param property The property which was changed. + * \param oldValue The removed property value. + */ + void propertyChanged( const Nepomuk::Resource & resource, + const Nepomuk::Types::Property & property, + const QVariantList & oldValue, + const QVariantList & newValue ); + + private Q_SLOTS: + void slotResourceCreated(const QString& res, const QStringList& types); + void slotResourceRemoved(const QString& res, const QStringList& types); + void slotResourceTypeAdded(const QString& res, const QString& type); + void slotResourceTypeRemoved(const QString& res, const QString& type); + void slotPropertyAdded(const QString& res, const QString& prop, const QDBusVariant& object); + void slotPropertyRemoved(const QString& res, const QString& prop, const QDBusVariant& object); + void slotPropertyChanged(const QString& res, const QString& prop, + const QVariantList & oldObjs, + const QVariantList & newObjs); + private: + class Private; + Private * d; + }; +} + +#endif // RESOURCEWATCHER_H diff --git a/src/kitemviews/private/knepomukrolesprovider.cpp b/src/kitemviews/private/knepomukrolesprovider.cpp new file mode 100644 index 000000000..7af887cbf --- /dev/null +++ b/src/kitemviews/private/knepomukrolesprovider.cpp @@ -0,0 +1,181 @@ +/*************************************************************************** + * Copyright (C) 2012 by Peter Penz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#include "knepomukrolesprovider.h" + +#include +#include +#include + +#include +#include +#include +#include + +struct KNepomukRolesProviderSingleton +{ + KNepomukRolesProvider instance; +}; +K_GLOBAL_STATIC(KNepomukRolesProviderSingleton, s_nepomukRolesProvider) + + +KNepomukRolesProvider& KNepomukRolesProvider::instance() +{ + return s_nepomukRolesProvider->instance; +} + +KNepomukRolesProvider::~KNepomukRolesProvider() +{ +} + +QSet KNepomukRolesProvider::roles() const +{ + return m_roles; +} + +QHash KNepomukRolesProvider::roleValues(const Nepomuk::Resource& resource, + const QSet& roles) const +{ + if (!resource.isValid()) { + return QHash(); + } + + QHash values; + + int width = -1; + int height = -1; + + QHashIterator it(resource.properties()); + while (it.hasNext()) { + it.next(); + + const Nepomuk::Types::Property property = it.key(); + const QByteArray role = m_roleForUri.value(property.uri()); + if (role.isEmpty() || !roles.contains(role)) { + continue; + } + + const Nepomuk::Variant value = it.value(); + + if (role == "imageSize") { + // Merge the two Nepomuk properties for width and height + // as one string into the "imageSize" role + const QString uri = property.uri().toString(); + if (uri.endsWith("#width")) { + width = value.toInt(); + } else if (uri.endsWith("#height")) { + height = value.toInt(); + } + + if (width >= 0 && height >= 0) { + const QString widthAndHeight = QString::number(width) + + QLatin1String(" x ") + + QString::number(height); + values.insert(role, widthAndHeight); + } + } else if (role == "tags") { + const QString tags = tagsFromValues(value.toStringList()); + values.insert(role, tags); + } else if (role == "orientation") { + const QString orientation = orientationFromValue(value.toInt()); + values.insert(role, orientation); + } else { + values.insert(role, value.toString()); + } + } + + // Assure that empty values get replaced by "-" + foreach (const QByteArray& role, roles) { + if (m_roles.contains(role) && values.value(role).toString().isEmpty()) { + values.insert(role, QLatin1String("-")); + } + } + + return values; +} + +KNepomukRolesProvider::KNepomukRolesProvider() : + m_roles(), + m_roleForUri() +{ + struct UriInfo + { + const char* const uri; + const char* const role; + }; + + // 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") + static const UriInfo uriInfoList[] = { + { "http://www.semanticdesktop.org/ontologies/2007/08/15/nao#numericRating", "rating" }, + { "http://www.semanticdesktop.org/ontologies/2007/08/15/nao#hasTag", "tags" }, + { "http://www.semanticdesktop.org/ontologies/2007/08/15/nao#description", "comment" }, + { "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#wordCount", "wordCount" }, + { "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#lineCount", "lineCount" }, + { "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#width", "imageSize" }, + { "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#height", "imageSize" }, + { "http://www.semanticdesktop.org/ontologies/2007/05/10/nexif#orientation", "orientation", }, + { "http://www.semanticdesktop.org/ontologies/2009/02/19/nmm#performer", "artist" }, + { "http://www.semanticdesktop.org/ontologies/2009/02/19/nmm#musicAlbum", "album" }, + { "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#duration", "duration" }, + { "http://www.semanticdesktop.org/ontologies/2009/02/19/nmm#trackNumber", "track" }, + { "http://www.semanticdesktop.org/ontologies/2010/04/30/ndo#copiedFrom", "copiedFrom" } + }; + + for (unsigned int i = 0; i < sizeof(uriInfoList) / sizeof(UriInfo); ++i) { + m_roleForUri.insert(QUrl(uriInfoList[i].uri), uriInfoList[i].role); + m_roles.insert(uriInfoList[i].role); + } +} + +QString KNepomukRolesProvider::tagsFromValues(const QStringList& values) const +{ + QString tags; + + for (int i = 0; i < values.count(); ++i) { + if (i > 0) { + tags.append(QLatin1String(", ")); + } + + const Nepomuk::Tag tag(values[i]); + tags += tag.genericLabel(); + } + + return tags; +} + +QString KNepomukRolesProvider::orientationFromValue(int value) const +{ + QString string; + switch (value) { + case 1: string = i18nc("@item:intable Image orientation", "Unchanged"); break; + case 2: string = i18nc("@item:intable Image orientation", "Horizontally flipped"); break; + case 3: string = i18nc("@item:intable image orientation", "180° rotated"); break; + case 4: string = i18nc("@item:intable image orientation", "Vertically flipped"); break; + case 5: string = i18nc("@item:intable image orientation", "Transposed"); break; + case 6: string = i18nc("@item:intable image orientation", "90° rotated"); break; + case 7: string = i18nc("@item:intable image orientation", "Transversed"); break; + case 8: string = i18nc("@item:intable image orientation", "270° rotated"); break; + default: + break; + } + return string; +} + diff --git a/src/kitemviews/private/knepomukrolesprovider.h b/src/kitemviews/private/knepomukrolesprovider.h new file mode 100644 index 000000000..46a78d4ee --- /dev/null +++ b/src/kitemviews/private/knepomukrolesprovider.h @@ -0,0 +1,82 @@ +/*************************************************************************** + * Copyright (C) 2012 by Peter Penz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#ifndef KNEPOMUKROLESPROVIDER_H +#define KNEPOMUKROLESPROVIDER_H + +#include + +#include +#include +#include + +namespace Nepomuk +{ + class Resource; +} + +/** + * @brief Allows accessing metadata of a file by providing KFileItemModel roles. + * + * Is a helper class for KFileItemModelRolesUpdater to retrieve roles that + * are only accessible with Nepomuk. + */ +class LIBDOLPHINPRIVATE_EXPORT KNepomukRolesProvider +{ +public: + static KNepomukRolesProvider& instance(); + virtual ~KNepomukRolesProvider(); + + /** + * @return Roles that can be provided by KNepomukRolesProvider. + */ + QSet roles() const; + + /** + * @return Values for the roles \a roles that can be determined from the file + * with the URL \a url. + */ + QHash roleValues(const Nepomuk::Resource& resource, + const QSet& roles) const; + +protected: + KNepomukRolesProvider(); + +private: + /** + * @return User visible string for the given tag-values. + */ + QString tagsFromValues(const QStringList& values) const; + + /** + * @return User visible string for the EXIF-orientation property + * which can have the values 0 to 8. + * (see http://sylvana.net/jpegcrop/exif_orientation.html) + */ + QString orientationFromValue(int value) const; + +private: + QSet m_roles; + QHash m_roleForUri; + + friend class KNepomukRolesProviderSingleton; +}; + +#endif + diff --git a/src/kitemviews/private/kpixmapmodifier.cpp b/src/kitemviews/private/kpixmapmodifier.cpp new file mode 100644 index 000000000..29aceb66b --- /dev/null +++ b/src/kitemviews/private/kpixmapmodifier.cpp @@ -0,0 +1,400 @@ +// krazy:excludeall=copyright (email of Maxim is missing) +/* + This file is a part of the KDE project + + Copyright © 2006 Zack Rusin + Copyright © 2006-2007, 2008 Fredrik Höglund + + The stack blur algorithm was invented by Mario Klingemann + + This implementation is based on the version in Anti-Grain Geometry Version 2.4, + Copyright © 2002-2005 Maxim Shemanarev (http://www.antigrain.com) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "kpixmapmodifier.h" + +#include +#include +#include +#include + +#include + +#include // for HAVE_XRENDER +#if defined(Q_WS_X11) && defined(HAVE_XRENDER) +# include +# include +# include +#endif + +static const quint32 stackBlur8Mul[255] = +{ + 512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512, + 454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512, + 482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456, + 437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512, + 497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328, + 320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456, + 446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335, + 329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512, + 505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405, + 399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328, + 324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271, + 268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456, + 451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388, + 385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335, + 332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292, + 289,287,285,282,280,278,275,273,271,269,267,265,263,261,259 +}; + +static const quint32 stackBlur8Shr[255] = +{ + 9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, + 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24 +}; + +static void blurHorizontal(QImage& image, unsigned int* stack, int div, int radius) +{ + int stackindex; + int stackstart; + + quint32 * const pixels = reinterpret_cast(image.bits()); + quint32 pixel; + + int w = image.width(); + int h = image.height(); + int wm = w - 1; + + unsigned int mulSum = stackBlur8Mul[radius]; + unsigned int shrSum = stackBlur8Shr[radius]; + + unsigned int sum, sumIn, sumOut; + + for (int y = 0; y < h; y++) { + sum = 0; + sumIn = 0; + sumOut = 0; + + const int yw = y * w; + pixel = pixels[yw]; + for (int i = 0; i <= radius; i++) { + stack[i] = qAlpha(pixel); + + sum += stack[i] * (i + 1); + sumOut += stack[i]; + } + + for (int i = 1; i <= radius; i++) { + pixel = pixels[yw + qMin(i, wm)]; + + unsigned int* stackpix = &stack[i + radius]; + *stackpix = qAlpha(pixel); + + sum += *stackpix * (radius + 1 - i); + sumIn += *stackpix; + } + + stackindex = radius; + for (int x = 0, i = yw; x < w; x++) { + pixels[i++] = (((sum * mulSum) >> shrSum) << 24) & 0xff000000; + + sum -= sumOut; + + stackstart = stackindex + div - radius; + if (stackstart >= div) { + stackstart -= div; + } + + unsigned int* stackpix = &stack[stackstart]; + + sumOut -= *stackpix; + + pixel = pixels[yw + qMin(x + radius + 1, wm)]; + + *stackpix = qAlpha(pixel); + + sumIn += *stackpix; + sum += sumIn; + + if (++stackindex >= div) { + stackindex = 0; + } + + stackpix = &stack[stackindex]; + + sumOut += *stackpix; + sumIn -= *stackpix; + } + } +} + +static void blurVertical(QImage& image, unsigned int* stack, int div, int radius) +{ + int stackindex; + int stackstart; + + quint32 * const pixels = reinterpret_cast(image.bits()); + quint32 pixel; + + int w = image.width(); + int h = image.height(); + int hm = h - 1; + + int mul_sum = stackBlur8Mul[radius]; + int shr_sum = stackBlur8Shr[radius]; + + unsigned int sum, sumIn, sumOut; + + for (int x = 0; x < w; x++) { + sum = 0; + sumIn = 0; + sumOut = 0; + + pixel = pixels[x]; + for (int i = 0; i <= radius; i++) { + stack[i] = qAlpha(pixel); + + sum += stack[i] * (i + 1); + sumOut += stack[i]; + } + + for (int i = 1; i <= radius; i++) { + pixel = pixels[qMin(i, hm) * w + x]; + + unsigned int* stackpix = &stack[i + radius]; + *stackpix = qAlpha(pixel); + + sum += *stackpix * (radius + 1 - i); + sumIn += *stackpix; + } + + stackindex = radius; + for (int y = 0, i = x; y < h; y++, i += w) { + pixels[i] = (((sum * mul_sum) >> shr_sum) << 24) & 0xff000000; + + sum -= sumOut; + + stackstart = stackindex + div - radius; + if (stackstart >= div) + stackstart -= div; + + unsigned int* stackpix = &stack[stackstart]; + + sumOut -= *stackpix; + + pixel = pixels[qMin(y + radius + 1, hm) * w + x]; + + *stackpix = qAlpha(pixel); + + sumIn += *stackpix; + sum += sumIn; + + if (++stackindex >= div) { + stackindex = 0; + } + + stackpix = &stack[stackindex]; + + sumOut += *stackpix; + sumIn -= *stackpix; + } + } +} + +static void stackBlur(QImage& image, float radius) +{ + radius = qRound(radius); + + int div = int(radius * 2) + 1; + unsigned int* stack = new unsigned int[div]; + + blurHorizontal(image, stack, div, radius); + blurVertical(image, stack, div, radius); + + delete [] stack; +} + +static void shadowBlur(QImage& image, float radius, const QColor& color) +{ + if (radius < 0) { + return; + } + + if (radius > 0) { + stackBlur(image, radius); + } + + // Correct the color and opacity of the shadow + QPainter p(&image); + p.setCompositionMode(QPainter::CompositionMode_SourceIn); + p.fillRect(image.rect(), color); +} + +namespace { + /** Helper class for drawing frames for KPixmapModifier::applyFrame(). */ + class TileSet + { + public: + enum { LeftMargin = 3, TopMargin = 2, RightMargin = 3, BottomMargin = 4 }; + + enum Tile { TopLeftCorner = 0, TopSide, TopRightCorner, LeftSide, + RightSide, BottomLeftCorner, BottomSide, BottomRightCorner, + NumTiles }; + + TileSet() + { + QImage image(8 * 3, 8 * 3, QImage::Format_ARGB32_Premultiplied); + + QPainter p(&image); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.fillRect(image.rect(), Qt::transparent); + p.fillRect(image.rect().adjusted(3, 3, -3, -3), Qt::black); + p.end(); + + shadowBlur(image, 3, Qt::black); + + QPixmap pixmap = QPixmap::fromImage(image); + m_tiles[TopLeftCorner] = pixmap.copy(0, 0, 8, 8); + m_tiles[TopSide] = pixmap.copy(8, 0, 8, 8); + m_tiles[TopRightCorner] = pixmap.copy(16, 0, 8, 8); + m_tiles[LeftSide] = pixmap.copy(0, 8, 8, 8); + m_tiles[RightSide] = pixmap.copy(16, 8, 8, 8); + m_tiles[BottomLeftCorner] = pixmap.copy(0, 16, 8, 8); + m_tiles[BottomSide] = pixmap.copy(8, 16, 8, 8); + m_tiles[BottomRightCorner] = pixmap.copy(16, 16, 8, 8); + } + + void paint(QPainter* p, const QRect& r) + { + p->drawPixmap(r.topLeft(), m_tiles[TopLeftCorner]); + if (r.width() - 16 > 0) { + p->drawTiledPixmap(r.x() + 8, r.y(), r.width() - 16, 8, m_tiles[TopSide]); + } + p->drawPixmap(r.right() - 8 + 1, r.y(), m_tiles[TopRightCorner]); + if (r.height() - 16 > 0) { + p->drawTiledPixmap(r.x(), r.y() + 8, 8, r.height() - 16, m_tiles[LeftSide]); + p->drawTiledPixmap(r.right() - 8 + 1, r.y() + 8, 8, r.height() - 16, m_tiles[RightSide]); + } + p->drawPixmap(r.x(), r.bottom() - 8 + 1, m_tiles[BottomLeftCorner]); + if (r.width() - 16 > 0) { + p->drawTiledPixmap(r.x() + 8, r.bottom() - 8 + 1, r.width() - 16, 8, m_tiles[BottomSide]); + } + p->drawPixmap(r.right() - 8 + 1, r.bottom() - 8 + 1, m_tiles[BottomRightCorner]); + + const QRect contentRect = r.adjusted(LeftMargin + 1, TopMargin + 1, + -(RightMargin + 1), -(BottomMargin + 1)); + p->fillRect(contentRect, Qt::transparent); + } + + QPixmap m_tiles[NumTiles]; + }; +} + +void KPixmapModifier::scale(QPixmap& pixmap, const QSize& scaledSize) +{ + if (scaledSize.isEmpty()) { + pixmap = QPixmap(); + return; + } + +#if defined(Q_WS_X11) && defined(HAVE_XRENDER) + // Assume that the texture size limit is 2048x2048 + if ((pixmap.width() <= 2048) && (pixmap.height() <= 2048) && pixmap.x11PictureHandle()) { + const QPixmap unscaledPixmap = pixmap.copy(); // Make a deep copy for XRender + QSize scaledPixmapSize = pixmap.size(); + scaledPixmapSize.scale(scaledSize, Qt::KeepAspectRatio); + + const qreal factor = scaledPixmapSize.width() / qreal(unscaledPixmap.width()); + + XTransform xform = {{ + { XDoubleToFixed(1 / factor), 0, 0 }, + { 0, XDoubleToFixed(1 / factor), 0 }, + { 0, 0, XDoubleToFixed(1) } + }}; + + QPixmap scaledPixmap(scaledPixmapSize); + scaledPixmap.fill(Qt::transparent); + + Display* dpy = QX11Info::display(); + + XRenderPictureAttributes attr; + attr.repeat = RepeatPad; + XRenderChangePicture(dpy, unscaledPixmap.x11PictureHandle(), CPRepeat, &attr); + + XRenderSetPictureFilter(dpy, unscaledPixmap.x11PictureHandle(), FilterBilinear, 0, 0); + XRenderSetPictureTransform(dpy, unscaledPixmap.x11PictureHandle(), &xform); + XRenderComposite(dpy, PictOpOver, unscaledPixmap.x11PictureHandle(), None, scaledPixmap.x11PictureHandle(), + 0, 0, 0, 0, 0, 0, scaledPixmap.width(), scaledPixmap.height()); + pixmap = scaledPixmap; + } else { + pixmap = pixmap.scaled(scaledSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); + } +#else + pixmap = pixmap.scaled(scaledSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); +#endif +} + +void KPixmapModifier::applyFrame(QPixmap& icon, const QSize& scaledSize) +{ + static TileSet tileSet; + + // Resize the icon to the maximum size minus the space required for the frame + const QSize size(scaledSize.width() - TileSet::LeftMargin - TileSet::RightMargin, + scaledSize.height() - TileSet::TopMargin - TileSet::BottomMargin); + scale(icon, size); + + QPixmap framedIcon(icon.size().width() + TileSet::LeftMargin + TileSet::RightMargin, + icon.size().height() + TileSet::TopMargin + TileSet::BottomMargin); + framedIcon.fill(Qt::transparent); + + QPainter painter; + painter.begin(&framedIcon); + painter.setCompositionMode(QPainter::CompositionMode_Source); + tileSet.paint(&painter, framedIcon.rect()); + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + painter.drawPixmap(TileSet::LeftMargin, TileSet::TopMargin, icon); + + icon = framedIcon; +} + +QSize KPixmapModifier::sizeInsideFrame(const QSize& frameSize) +{ + return QSize(frameSize.width() - TileSet::LeftMargin - TileSet::RightMargin, + frameSize.height() - TileSet::TopMargin - TileSet::BottomMargin); +} + diff --git a/src/kitemviews/private/kpixmapmodifier.h b/src/kitemviews/private/kpixmapmodifier.h new file mode 100644 index 000000000..4f863c349 --- /dev/null +++ b/src/kitemviews/private/kpixmapmodifier.h @@ -0,0 +1,38 @@ +/*************************************************************************** + * Copyright (C) 2011 by Peter Penz * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +#ifndef KPIXMAPMODIFIER_H +#define KPIXMAPMODIFIER_H + +#include + +class QPixmap; +class QSize; + +class LIBDOLPHINPRIVATE_EXPORT KPixmapModifier +{ +public: + static void scale(QPixmap& pixmap, const QSize& scaledSize); + static void applyFrame(QPixmap& icon, const QSize& scaledSize); + static QSize sizeInsideFrame(const QSize& frameSize); +}; + +#endif + + diff --git a/src/panels/folders/folderspanel.cpp b/src/panels/folders/folderspanel.cpp index 87b0297c2..2f9e1d323 100644 --- a/src/panels/folders/folderspanel.cpp +++ b/src/panels/folders/folderspanel.cpp @@ -30,7 +30,6 @@ #include #include -#include #include #include @@ -50,7 +49,6 @@ FoldersPanel::FoldersPanel(QWidget* parent) : Panel(parent), m_updateCurrentItem(false), - m_dirLister(0), m_controller(0) { setLayoutDirection(Qt::LeftToRight); @@ -65,9 +63,6 @@ FoldersPanel::~FoldersPanel() m_controller->setView(0); delete view; } - - delete m_dirLister; - m_dirLister = 0; } void FoldersPanel::setShowHiddenFiles(bool show) @@ -116,7 +111,7 @@ bool FoldersPanel::urlChanged() return false; } - if (m_dirLister) { + if (m_controller) { loadTree(url()); } @@ -130,16 +125,10 @@ void FoldersPanel::showEvent(QShowEvent* event) return; } - if (!m_dirLister) { + if (!m_controller) { // Postpone the creating of the dir lister to the first show event. // This assures that no performance and memory overhead is given when the TreeView is not // used at all (see FoldersPanel::setUrl()). - m_dirLister = new KDirLister(); - m_dirLister->setAutoUpdate(true); - m_dirLister->setMainWindow(window()); - m_dirLister->setDelayedMimeTypes(true); - m_dirLister->setAutoErrorHandlingEnabled(false, this); - KFileItemListView* view = new KFileItemListView(); view->setWidgetCreator(new KItemListWidgetCreator()); @@ -158,12 +147,12 @@ void FoldersPanel::showEvent(QShowEvent* event) // opening the folders panel. view->setOpacity(0); - KFileItemModel* model = new KFileItemModel(m_dirLister, this); + KFileItemModel* model = new KFileItemModel(this); model->setShowFoldersOnly(true); model->setShowHiddenFiles(FoldersPanelSettings::hiddenFilesShown()); // Use a QueuedConnection to give the view the possibility to react first on the // finished loading. - connect(model, SIGNAL(loadingCompleted()), this, SLOT(slotLoadingCompleted()), Qt::QueuedConnection); + connect(model, SIGNAL(dirLoadingCompleted()), this, SLOT(slotLoadingCompleted()), Qt::QueuedConnection); KItemListContainer* container = new KItemListContainer(this); m_controller = container->controller(); @@ -305,7 +294,7 @@ void FoldersPanel::startFadeInAnimation() void FoldersPanel::loadTree(const KUrl& url) { - Q_ASSERT(m_dirLister); + Q_ASSERT(m_controller); m_updateCurrentItem = false; @@ -319,13 +308,12 @@ void FoldersPanel::loadTree(const KUrl& url) baseUrl.setPath(QString('/')); } - if (m_dirLister->url() != baseUrl) { + KFileItemModel* model = fileItemModel(); + if (model->dir() != baseUrl) { m_updateCurrentItem = true; - m_dirLister->stop(); - m_dirLister->openUrl(baseUrl, KDirLister::Reload); + model->refreshDir(baseUrl); } - KFileItemModel* model = fileItemModel(); const int index = model->index(url); if (index >= 0) { updateCurrentItem(index); diff --git a/src/panels/folders/folderspanel.h b/src/panels/folders/folderspanel.h index 44acfb88f..babcde64a 100644 --- a/src/panels/folders/folderspanel.h +++ b/src/panels/folders/folderspanel.h @@ -23,7 +23,6 @@ #include #include -class KDirLister; class KFileItemModel; class KItemListController; class QGraphicsSceneDragDropEvent; @@ -100,7 +99,6 @@ private: private: bool m_updateCurrentItem; - KDirLister* m_dirLister; KItemListController* m_controller; }; diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 43d1c9bf7..de254f6da 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -49,7 +49,7 @@ target_link_libraries(kfileitemmodeltest dolphinprivate ${KDE4_KIO_LIBS} ${QT_QT # KItemListKeyboardSearchManagerTest set(kitemlistkeyboardsearchmanagertest_SRCS kitemlistkeyboardsearchmanagertest.cpp - ../kitemviews/kitemlistkeyboardsearchmanager.cpp + ../kitemviews/private/kitemlistkeyboardsearchmanager.cpp ) kde4_add_unit_test(kitemlistkeyboardsearchmanagertest TEST ${kitemlistkeyboardsearchmanagertest_SRCS}) target_link_libraries(kitemlistkeyboardsearchmanagertest ${KDE4_KIO_LIBS} ${QT_QTTEST_LIBRARY}) diff --git a/src/tests/kfileitemmodeltest.cpp b/src/tests/kfileitemmodeltest.cpp index cce92626d..e96aee6d7 100644 --- a/src/tests/kfileitemmodeltest.cpp +++ b/src/tests/kfileitemmodeltest.cpp @@ -22,6 +22,7 @@ #include #include "kitemviews/kfileitemmodel.h" +#include "kitemviews/private/kfileitemmodeldirlister.h" #include "testdir.h" void myMessageOutput(QtMsgType type, const char* msg) @@ -62,7 +63,7 @@ private slots: void testDefaultGroupedSorting(); void testNewItems(); void testRemoveItems(); - void testLoadingCompleted(); + void testDirLoadingCompleted(); void testSetData(); void testSetDataWithModifiedSortRole_data(); void testSetDataWithModifiedSortRole(); @@ -82,7 +83,6 @@ private: private: KFileItemModel* m_model; - KDirLister* m_dirLister; TestDir* m_testDir; }; @@ -97,9 +97,8 @@ void KFileItemModelTest::init() qRegisterMetaType("KFileItemList"); m_testDir = new TestDir(); - m_dirLister = new KDirLister(); - m_dirLister->setAutoUpdate(false); - m_model = new KFileItemModel(m_dirLister); + m_model = new KFileItemModel(); + m_model->m_dirLister->setAutoUpdate(false); } void KFileItemModelTest::cleanup() @@ -107,9 +106,6 @@ void KFileItemModelTest::cleanup() delete m_model; m_model = 0; - delete m_dirLister; - m_dirLister = 0; - delete m_testDir; m_testDir = 0; } @@ -131,7 +127,7 @@ void KFileItemModelTest::testDefaultSortRole() m_testDir->createFiles(files); - m_dirLister->openUrl(m_testDir->url()); + m_model->loadDir(m_testDir->url()); QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout)); QCOMPARE(m_model->count(), 3); @@ -151,7 +147,7 @@ void KFileItemModelTest::testNewItems() files << "a.txt" << "b.txt" << "c.txt"; m_testDir->createFiles(files); - m_dirLister->openUrl(m_testDir->url()); + m_model->loadDir(m_testDir->url()); QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout)); QCOMPARE(m_model->count(), 3); @@ -163,36 +159,36 @@ void KFileItemModelTest::testRemoveItems() { m_testDir->createFile("a.txt"); m_testDir->createFile("b.txt"); - m_dirLister->openUrl(m_testDir->url()); + m_model->loadDir(m_testDir->url()); QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout)); QCOMPARE(m_model->count(), 2); QVERIFY(isModelConsistent()); m_testDir->removeFile("a.txt"); - m_dirLister->updateDirectory(m_testDir->url()); + m_model->m_dirLister->updateDirectory(m_testDir->url()); QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsRemoved(KItemRangeList)), DefaultTimeout)); QCOMPARE(m_model->count(), 1); QVERIFY(isModelConsistent()); } -void KFileItemModelTest::testLoadingCompleted() +void KFileItemModelTest::testDirLoadingCompleted() { - QSignalSpy loadingCompletedSpy(m_model, SIGNAL(loadingCompleted())); + QSignalSpy loadingCompletedSpy(m_model, SIGNAL(dirLoadingCompleted())); QSignalSpy itemsInsertedSpy(m_model, SIGNAL(itemsInserted(KItemRangeList))); QSignalSpy itemsRemovedSpy(m_model, SIGNAL(itemsRemoved(KItemRangeList))); m_testDir->createFiles(QStringList() << "a.txt" << "b.txt" << "c.txt"); - m_dirLister->openUrl(m_testDir->url()); - QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(loadingCompleted()), DefaultTimeout)); + m_model->loadDir(m_testDir->url()); + QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(dirLoadingCompleted()), DefaultTimeout)); QCOMPARE(loadingCompletedSpy.count(), 1); QCOMPARE(itemsInsertedSpy.count(), 1); QCOMPARE(itemsRemovedSpy.count(), 0); QCOMPARE(m_model->count(), 3); m_testDir->createFiles(QStringList() << "d.txt" << "e.txt"); - m_dirLister->updateDirectory(m_testDir->url()); - QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(loadingCompleted()), DefaultTimeout)); + m_model->m_dirLister->updateDirectory(m_testDir->url()); + QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(dirLoadingCompleted()), DefaultTimeout)); QCOMPARE(loadingCompletedSpy.count(), 2); QCOMPARE(itemsInsertedSpy.count(), 2); QCOMPARE(itemsRemovedSpy.count(), 0); @@ -200,15 +196,15 @@ void KFileItemModelTest::testLoadingCompleted() m_testDir->removeFile("a.txt"); m_testDir->createFile("f.txt"); - m_dirLister->updateDirectory(m_testDir->url()); - QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(loadingCompleted()), DefaultTimeout)); + m_model->m_dirLister->updateDirectory(m_testDir->url()); + QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(dirLoadingCompleted()), DefaultTimeout)); QCOMPARE(loadingCompletedSpy.count(), 3); QCOMPARE(itemsInsertedSpy.count(), 3); QCOMPARE(itemsRemovedSpy.count(), 1); QCOMPARE(m_model->count(), 5); m_testDir->removeFile("b.txt"); - m_dirLister->updateDirectory(m_testDir->url()); + m_model->m_dirLister->updateDirectory(m_testDir->url()); QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsRemoved(KItemRangeList)), DefaultTimeout)); QCOMPARE(loadingCompletedSpy.count(), 4); QCOMPARE(itemsInsertedSpy.count(), 3); @@ -222,7 +218,7 @@ void KFileItemModelTest::testSetData() { m_testDir->createFile("a.txt"); - m_dirLister->openUrl(m_testDir->url()); + m_model->loadDir(m_testDir->url()); QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout)); QHash values; @@ -279,7 +275,7 @@ void KFileItemModelTest::testSetDataWithModifiedSortRole() files << "a.txt" << "b.txt" << "c.txt"; m_testDir->createFiles(files); - m_dirLister->openUrl(m_testDir->url()); + m_model->loadDir(m_testDir->url()); QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout)); // Fill the "rating" role of each file: @@ -331,7 +327,7 @@ void KFileItemModelTest::testModelConsistencyWhenInsertingItems() // KFileItemModel to do a lot of insert operation and hence decrease // the timeout to 1 millisecond. m_testDir->createFile("1"); - m_dirLister->openUrl(m_testDir->url()); + m_model->loadDir(m_testDir->url()); QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout)); QCOMPARE(m_model->count(), 1); @@ -351,7 +347,7 @@ void KFileItemModelTest::testModelConsistencyWhenInsertingItems() m_testDir->createFile(QString::number(itemName)); } - m_dirLister->updateDirectory(m_testDir->url()); + m_model->m_dirLister->updateDirectory(m_testDir->url()); if (spy.count() == 0) { QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout)); } @@ -371,7 +367,7 @@ void KFileItemModelTest::testItemRangeConsistencyWhenInsertingItems() // Due to inserting the 3 items one item-range with index == 0 and // count == 3 must be given QSignalSpy spy1(m_model, SIGNAL(itemsInserted(KItemRangeList))); - m_dirLister->openUrl(m_testDir->url()); + m_model->loadDir(m_testDir->url()); QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout)); QCOMPARE(spy1.count(), 1); @@ -396,7 +392,7 @@ void KFileItemModelTest::testItemRangeConsistencyWhenInsertingItems() m_testDir->createFiles(files); QSignalSpy spy2(m_model, SIGNAL(itemsInserted(KItemRangeList))); - m_dirLister->updateDirectory(m_testDir->url()); + m_model->m_dirLister->updateDirectory(m_testDir->url()); QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout)); QCOMPARE(spy2.count(), 1); @@ -424,7 +420,7 @@ void KFileItemModelTest::testExpandItems() QSet allFolders; allFolders << KUrl(m_testDir->name() + "a") << KUrl(m_testDir->name() + "a/a") << KUrl(m_testDir->name() + "a/a-1"); - m_dirLister->openUrl(m_testDir->url()); + m_model->loadDir(m_testDir->url()); QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout)); // So far, the model contains only "a/" @@ -496,9 +492,9 @@ void KFileItemModelTest::testExpandItems() QCOMPARE(m_model->count(), 0); QVERIFY(m_model->expandedUrls().empty()); - m_dirLister->openUrl(m_testDir->url()); + m_model->loadDir(m_testDir->url()); m_model->restoreExpandedUrls(allFolders); - QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(loadingCompleted()), DefaultTimeout)); + QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(dirLoadingCompleted()), DefaultTimeout)); QCOMPARE(m_model->count(), 5); // 5 items: "a/", "a/a/", "a/a/1", "a/a-1/", "a/a-1/1" QVERIFY(m_model->isExpanded(0)); QVERIFY(m_model->isExpanded(1)); @@ -509,12 +505,12 @@ void KFileItemModelTest::testExpandItems() // Move to a sub folder, then call restoreExpandedFolders() *before* going back. // This is how DolphinView restores the expanded folders when navigating in history. - m_dirLister->openUrl(KUrl(m_testDir->name() + "a/a/")); - QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(loadingCompleted()), DefaultTimeout)); + m_model->loadDir(KUrl(m_testDir->name() + "a/a/")); + QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(dirLoadingCompleted()), DefaultTimeout)); QCOMPARE(m_model->count(), 1); // 1 item: "1" m_model->restoreExpandedUrls(allFolders); - m_dirLister->openUrl(m_testDir->url()); - QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(loadingCompleted()), DefaultTimeout)); + m_model->loadDir(m_testDir->url()); + QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(dirLoadingCompleted()), DefaultTimeout)); QCOMPARE(m_model->count(), 5); // 5 items: "a/", "a/a/", "a/a/1", "a/a-1/", "a/a-1/1" QCOMPARE(m_model->expandedUrls(), allFolders); } @@ -537,7 +533,7 @@ void KFileItemModelTest::testExpandParentItems() files << "a 1/b1/c1/file.txt" << "a2/b2/c2/d2/file.txt"; // missing folders are created automatically m_testDir->createFiles(files); - m_dirLister->openUrl(m_testDir->url()); + m_model->loadDir(m_testDir->url()); QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout)); // So far, the model contains only "a 1/" and "a2/". @@ -546,7 +542,7 @@ void KFileItemModelTest::testExpandParentItems() // Expand the parents of "a2/b2/c2". m_model->expandParentItems(KUrl(m_testDir->name() + "a2/b2/c2")); - QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(loadingCompleted()), DefaultTimeout)); + QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(dirLoadingCompleted()), DefaultTimeout)); // The model should now contain "a 1/", "a2/", "a2/b2/", and "a2/b2/c2/". // It's important that only the parents of "a1/b1/c1" are expanded. @@ -558,7 +554,7 @@ void KFileItemModelTest::testExpandParentItems() // Expand the parents of "a 1/b1". m_model->expandParentItems(KUrl(m_testDir->name() + "a 1/b1")); - QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(loadingCompleted()), DefaultTimeout)); + QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(dirLoadingCompleted()), DefaultTimeout)); // The model should now contain "a 1/", "a 1/b1/", "a2/", "a2/b2", and "a2/b2/c2/". // It's important that only the parents of "a 1/b1/" and "a2/b2/c2/" are expanded. @@ -593,7 +589,7 @@ void KFileItemModelTest::testSorting() m_testDir->createFile("e", "An even larger file", now.addDays(-4)); m_testDir->createFile(".f"); - m_dirLister->openUrl(m_testDir->url()); + m_model->loadDir(m_testDir->url()); QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout)); int index = m_model->index(KUrl(m_testDir->url().url() + "c")); @@ -705,7 +701,7 @@ void KFileItemModelTest::testIndexForKeyboardSearch() files << "a" << "aa" << "Image.jpg" << "Image.png" << "Text" << "Text1" << "Text2" << "Text11"; m_testDir->createFiles(files); - m_dirLister->openUrl(m_testDir->url()); + m_model->loadDir(m_testDir->url()); QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout)); // Search from index 0 @@ -755,7 +751,7 @@ void KFileItemModelTest::testNameFilter() files << "A1" << "A2" << "Abc" << "Bcd" << "Cde"; m_testDir->createFiles(files); - m_dirLister->openUrl(m_testDir->url()); + m_model->loadDir(m_testDir->url()); QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout)); m_model->setNameFilter("A"); // Shows A1, A2 and Abc diff --git a/src/tests/kitemlistcontrollertest.cpp b/src/tests/kitemlistcontrollertest.cpp index b446e8477..486ccd46a 100644 --- a/src/tests/kitemlistcontrollertest.cpp +++ b/src/tests/kitemlistcontrollertest.cpp @@ -21,13 +21,12 @@ #include #include -#include #include "kitemviews/kitemlistcontainer.h" #include "kitemviews/kfileitemlistview.h" #include "kitemviews/kfileitemmodel.h" #include "kitemviews/kitemlistcontroller.h" #include "kitemviews/kitemlistselectionmanager.h" -#include "kitemviews/kitemlistviewlayouter_p.h" +#include "kitemviews/private/kitemlistviewlayouter.h" #include "testdir.h" namespace { @@ -65,7 +64,6 @@ private: KItemListController* m_controller; KItemListSelectionManager* m_selectionManager; KFileItemModel* m_model; - KDirLister* m_dirLister; TestDir* m_testDir; KItemListContainer* m_container; }; @@ -80,8 +78,7 @@ void KItemListControllerTest::initTestCase() qRegisterMetaType >("QSet"); m_testDir = new TestDir(); - m_dirLister = new KDirLister(); - m_model = new KFileItemModel(m_dirLister); + m_model = new KFileItemModel(); m_container = new KItemListContainer(); m_controller = m_container->controller(); m_controller->setSelectionBehavior(KItemListController::MultiSelection); @@ -100,8 +97,8 @@ void KItemListControllerTest::initTestCase() << "e1" << "e2" << "e3" << "e4" << "e5" << "e6" << "e7"; m_testDir->createFiles(files); - m_dirLister->openUrl(m_testDir->url()); - QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(loadingCompleted()), DefaultTimeout)); + m_model->loadDir(m_testDir->url()); + QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(dirLoadingCompleted()), DefaultTimeout)); m_container->show(); QTest::qWaitForWindowShown(m_container); @@ -119,9 +116,6 @@ void KItemListControllerTest::cleanupTestCase() delete m_model; m_model = 0; - delete m_dirLister; - m_dirLister = 0; - delete m_testDir; m_testDir = 0; } diff --git a/src/tests/kitemlistkeyboardsearchmanagertest.cpp b/src/tests/kitemlistkeyboardsearchmanagertest.cpp index aeca1f779..cf15324e2 100644 --- a/src/tests/kitemlistkeyboardsearchmanagertest.cpp +++ b/src/tests/kitemlistkeyboardsearchmanagertest.cpp @@ -19,7 +19,7 @@ #include -#include "kitemviews/kitemlistkeyboardsearchmanager_p.h" +#include "kitemviews/private/kitemlistkeyboardsearchmanager.h" class KItemListKeyboardSearchManagerTest : public QObject { diff --git a/src/views/dolphindirlister.cpp b/src/views/dolphindirlister.cpp deleted file mode 100644 index b62abe167..000000000 --- a/src/views/dolphindirlister.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2006-2010 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "dolphindirlister.h" -#include -#include - -DolphinDirLister::DolphinDirLister(QObject* parent) : - KDirLister(parent) -{ - setAutoErrorHandlingEnabled(false, 0); -} - -DolphinDirLister::~DolphinDirLister() -{ -} - -void DolphinDirLister::handleError(KIO::Job* job) -{ - if (job->error() == KIO::ERR_IS_FILE) { - emit urlIsFileError(url()); - } else { - const QString errorString = job->errorString(); - if (errorString.isEmpty()) { - emit errorMessage(i18nc("@info:status", "Unknown error.")); - } else { - emit errorMessage(errorString); - } - } -} - -#include "dolphindirlister.moc" diff --git a/src/views/dolphindirlister.h b/src/views/dolphindirlister.h deleted file mode 100644 index 0955df232..000000000 --- a/src/views/dolphindirlister.h +++ /dev/null @@ -1,49 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2006-2009 by Peter Penz * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef DOLPHINDIRLISTER_H -#define DOLPHINDIRLISTER_H - -#include -#include - -/** - * @brief Extends the class KDirLister by emitting a signal when an - * error occurred instead of showing an error dialog. - */ -class LIBDOLPHINPRIVATE_EXPORT DolphinDirLister : public KDirLister -{ - Q_OBJECT - -public: - DolphinDirLister(QObject* parent = 0); - virtual ~DolphinDirLister(); - -signals: - /** Is emitted whenever an error has occurred. */ - void errorMessage(const QString& msg); - - /** Is emitted when the URL of the directory lister represents a file. */ - void urlIsFileError(const KUrl& url); - -protected: - virtual void handleError(KIO::Job* job); -}; - -#endif diff --git a/src/views/dolphinitemlistcontainer.cpp b/src/views/dolphinitemlistcontainer.cpp index 5b7522f00..e8c373492 100644 --- a/src/views/dolphinitemlistcontainer.cpp +++ b/src/views/dolphinitemlistcontainer.cpp @@ -31,7 +31,6 @@ #include #include -#include #include #include @@ -39,13 +38,12 @@ #include "zoomlevelinfo.h" -DolphinItemListContainer::DolphinItemListContainer(KDirLister* dirLister, - QWidget* parent) : +DolphinItemListContainer::DolphinItemListContainer(QWidget* parent) : KItemListContainer(parent), m_zoomLevel(0), m_fileItemListView(0) { - controller()->setModel(new KFileItemModel(dirLister, this)); + controller()->setModel(new KFileItemModel(this)); m_fileItemListView = new KFileItemListView(); controller()->setView(m_fileItemListView); diff --git a/src/views/dolphinitemlistcontainer.h b/src/views/dolphinitemlistcontainer.h index c5a30ad74..f3505b663 100644 --- a/src/views/dolphinitemlistcontainer.h +++ b/src/views/dolphinitemlistcontainer.h @@ -26,7 +26,6 @@ #include -class KDirLister; class KFileItemListView; /** @@ -44,8 +43,7 @@ class LIBDOLPHINPRIVATE_EXPORT DolphinItemListContainer : public KItemListContai Q_OBJECT public: - explicit DolphinItemListContainer(KDirLister* dirLister, - QWidget* parent = 0); + explicit DolphinItemListContainer(QWidget* parent = 0); virtual ~DolphinItemListContainer(); diff --git a/src/views/dolphinview.cpp b/src/views/dolphinview.cpp index 2ffc33e08..137b73d09 100644 --- a/src/views/dolphinview.cpp +++ b/src/views/dolphinview.cpp @@ -35,7 +35,6 @@ #include #include -#include #include #include #include @@ -59,7 +58,6 @@ #include #include -#include "dolphindirlister.h" #include "dolphinnewfilemenuobserver.h" #include "dolphin_detailsmodesettings.h" #include "dolphin_generalsettings.h" @@ -91,7 +89,6 @@ DolphinView::DolphinView(const KUrl& url, QWidget* parent) : m_mode(DolphinView::IconsView), m_visibleRoles(), m_topLayout(0), - m_dirLister(0), m_container(0), m_toolTipManager(0), m_selectionChangedTimer(0), @@ -117,24 +114,7 @@ DolphinView::DolphinView(const KUrl& url, QWidget* parent) : connect(m_selectionChangedTimer, SIGNAL(timeout()), this, SLOT(emitSelectionChangedSignal())); - m_dirLister = new DolphinDirLister(this); - m_dirLister->setAutoUpdate(true); - m_dirLister->setDelayedMimeTypes(true); - - connect(m_dirLister, SIGNAL(redirection(KUrl,KUrl)), this, SLOT(slotRedirection(KUrl,KUrl))); - connect(m_dirLister, SIGNAL(started(KUrl)), this, SLOT(slotDirListerStarted(KUrl))); - connect(m_dirLister, SIGNAL(refreshItems(QList >)), - this, SLOT(slotRefreshItems())); - - connect(m_dirLister, SIGNAL(clear()), this, SIGNAL(itemCountChanged())); - connect(m_dirLister, SIGNAL(newItems(KFileItemList)), this, SIGNAL(itemCountChanged())); - connect(m_dirLister, SIGNAL(infoMessage(QString)), this, SIGNAL(infoMessage(QString))); - connect(m_dirLister, SIGNAL(errorMessage(QString)), this, SIGNAL(infoMessage(QString))); - connect(m_dirLister, SIGNAL(percent(int)), this, SIGNAL(pathLoadingProgress(int))); - connect(m_dirLister, SIGNAL(urlIsFileError(KUrl)), this, SIGNAL(urlIsFileError(KUrl))); - connect(m_dirLister, SIGNAL(itemsDeleted(KFileItemList)), this, SIGNAL(itemCountChanged())); - - m_container = new DolphinItemListContainer(m_dirLister, this); + m_container = new DolphinItemListContainer(this); m_container->setVisibleRoles(QList() << "name"); m_container->installEventFilter(this); setFocusProxy(m_container); @@ -156,10 +136,17 @@ DolphinView::DolphinView(const KUrl& url, QWidget* parent) : connect(controller, SIGNAL(modelChanged(KItemModelBase*,KItemModelBase*)), this, SLOT(slotModelChanged(KItemModelBase*,KItemModelBase*))); KFileItemModel* model = fileItemModel(); - if (model) { - connect(model, SIGNAL(loadingCompleted()), this, SLOT(slotLoadingCompleted())); - connect(model, SIGNAL(sortProgress(int)), this, SIGNAL(sortProgress(int))); - } + connect(model, SIGNAL(dirLoadingStarted()), this, SLOT(slotDirLoadingStarted())); + connect(model, SIGNAL(dirLoadingCompleted()), this, SLOT(slotDirLoadingCompleted())); + connect(model, SIGNAL(dirLoadingProgress(int)), this, SIGNAL(dirLoadingProgress(int))); + connect(model, SIGNAL(dirSortingProgress(int)), this, SIGNAL(dirSortingProgress(int))); + connect(model, SIGNAL(itemsChanged(KItemRangeList,QSet)), + this, SLOT(slotItemsChanged())); + connect(model, SIGNAL(itemsRemoved(KItemRangeList)), this, SIGNAL(itemCountChanged())); + connect(model, SIGNAL(itemsInserted(KItemRangeList)), this, SIGNAL(itemCountChanged())); + connect(model, SIGNAL(infoMessage(QString)), this, SIGNAL(infoMessage(QString))); + connect(model, SIGNAL(errorMessage(QString)), this, SIGNAL(errorMessage(QString))); + connect(model, SIGNAL(redirection(KUrl,KUrl)), this, SLOT(slotRedirection(KUrl,KUrl))); KItemListView* view = controller->view(); view->installEventFilter(this); @@ -269,7 +256,8 @@ bool DolphinView::previewsShown() const void DolphinView::setHiddenFilesShown(bool show) { - if (m_dirLister->showingDotFiles() == show) { + KFileItemModel* model = fileItemModel(); + if (model->showHiddenFiles() == show) { return; } @@ -280,13 +268,13 @@ void DolphinView::setHiddenFilesShown(bool show) ViewProperties props(url()); props.setHiddenFilesShown(show); - fileItemModel()->setShowHiddenFiles(show); + model->setShowHiddenFiles(show); emit hiddenFilesShownChanged(show); } bool DolphinView::hiddenFilesShown() const { - return m_dirLister->showingDotFiles(); + return fileItemModel()->showHiddenFiles(); } void DolphinView::setGroupedSorting(bool grouped) @@ -311,7 +299,21 @@ bool DolphinView::groupedSorting() const KFileItemList DolphinView::items() const { - return m_dirLister->items(); + KFileItemList list; + const KFileItemModel* model = fileItemModel(); + const int itemCount = model->count(); + list.reserve(itemCount); + + for (int i = 0; i < itemCount; ++i) { + list.append(model->fileItem(i)); + } + + return list; +} + +int DolphinView::itemsCount() const +{ + return fileItemModel()->count(); } KFileItemList DolphinView::selectedItems() const @@ -455,7 +457,7 @@ void DolphinView::reload() void DolphinView::stopLoading() { - m_dirLister->stop(); + fileItemModel()->cancelDirLoading(); } void DolphinView::readSettings() @@ -492,7 +494,10 @@ void DolphinView::calculateItemCount(int& fileCount, int& folderCount, KIO::filesize_t& totalFileSize) const { - foreach (const KFileItem& item, m_dirLister->items()) { + const KFileItemModel* model = fileItemModel(); + const int itemCount = model->count(); + for (int i = 0; i < itemCount; ++i) { + const KFileItem item = model->fileItem(i); if (item.isDir()) { ++folderCount; } else { @@ -628,8 +633,9 @@ void DolphinView::renameSelectedItems() dialog->activateWindow(); //} - // assure that the current index remains visible when KDirLister - // will notify the view about changed items + // Assure that the current index remains visible when KFileItemModel + // will notify the view about changed items (which might result in + // a changed sorting). m_assureVisibleCurrentIndex = true; } @@ -979,11 +985,11 @@ void DolphinView::slotItemDropEvent(int index, QGraphicsSceneDragDropEvent* even void DolphinView::slotModelChanged(KItemModelBase* current, KItemModelBase* previous) { if (previous != 0) { - disconnect(previous, SIGNAL(loadingCompleted()), this, SLOT(slotLoadingCompleted())); + disconnect(previous, SIGNAL(dirLoadingCompleted()), this, SLOT(slotDirLoadingCompleted())); } Q_ASSERT(qobject_cast(current)); - connect(current, SIGNAL(loadingCompleted()), this, SLOT(slotLoadingCompleted())); + connect(current, SIGNAL(loadingCompleted()), this, SLOT(slotDirLoadingCompleted())); KFileItemModel* fileItemModel = static_cast(current); m_versionControlObserver->setModel(fileItemModel); @@ -1121,7 +1127,7 @@ bool DolphinView::hasSelection() const KFileItem DolphinView::rootItem() const { - return m_dirLister->rootItem(); + return fileItemModel()->rootItem(); } void DolphinView::observeCreatedItem(const KUrl& url) @@ -1222,7 +1228,7 @@ void DolphinView::slotDeleteFileFinished(KJob* job) } } -void DolphinView::slotDirListerStarted(const KUrl& url) +void DolphinView::slotDirLoadingStarted() { // Disable the writestate temporary until it can be determined in a fast way // in DolphinView::slotLoadingCompleted() @@ -1231,29 +1237,23 @@ void DolphinView::slotDirListerStarted(const KUrl& url) emit writeStateChanged(m_isFolderWritable); } - emit startedPathLoading(url); + emit startedDirLoading(url()); } -void DolphinView::slotLoadingCompleted() +void DolphinView::slotDirLoadingCompleted() { // Update the view-state. This has to be done using a Qt::QueuedConnection // because the view might not be in its final state yet. QTimer::singleShot(0, this, SLOT(updateViewState())); - emit finishedPathLoading(url()); + emit finishedDirLoading(url()); updateWritableState(); } -void DolphinView::slotRefreshItems() +void DolphinView::slotItemsChanged() { - if (m_assureVisibleCurrentIndex) { - m_assureVisibleCurrentIndex = false; - //QAbstractItemView* view = m_viewAccessor.itemView(); - //if (view) { - // m_viewAccessor.itemView()->scrollTo(m_viewAccessor.itemView()->currentIndex()); - //} - } + m_assureVisibleCurrentIndex = false; } void DolphinView::slotSortOrderChangedByHeader(Qt::SortOrder current, Qt::SortOrder previous) @@ -1311,7 +1311,12 @@ void DolphinView::loadDirectory(const KUrl& url, bool reload) return; } - m_dirLister->openUrl(url, reload ? KDirLister::Reload : KDirLister::NoFlags); + KFileItemModel* model = fileItemModel(); + if (reload) { + model->refreshDir(url); + } else { + model->loadDir(url); + } } void DolphinView::applyViewProperties() @@ -1465,7 +1470,7 @@ void DolphinView::updateWritableState() const bool wasFolderWritable = m_isFolderWritable; m_isFolderWritable = true; - const KFileItem item = m_dirLister->rootItem(); + const KFileItem item = fileItemModel()->rootItem(); if (!item.isNull()) { KFileItemListProperties capabilities(KFileItemList() << item); m_isFolderWritable = capabilities.supportsWriting(); diff --git a/src/views/dolphinview.h b/src/views/dolphinview.h index b1d057e6f..9c674d03a 100644 --- a/src/views/dolphinview.h +++ b/src/views/dolphinview.h @@ -39,7 +39,6 @@ typedef KIO::FileUndoManager::CommandType CommandType; -class DolphinDirLister; class DolphinItemListContainer; class KAction; class KActionCollection; @@ -154,6 +153,12 @@ public: */ KFileItemList items() const; + /** + * @return The number of items. itemsCount() is faster in comparison + * to items().count(). + */ + int itemsCount() const; + /** * Returns the selected items. The list is empty if no item has been * selected. @@ -474,25 +479,29 @@ signals: /** * Is emitted after DolphinView::setUrl() has been invoked and - * the path \a url is currently loaded. If this signal is emitted, + * the directory \a url is currently loaded. If this signal is emitted, * it is assured that the view contains already the correct root * URL and property settings. */ - void startedPathLoading(const KUrl& url); + void startedDirLoading(const KUrl& url); /** - * Is emitted after the path triggered by DolphinView::setUrl() + * Is emitted after the directory triggered by DolphinView::setUrl() * has been loaded. */ - void finishedPathLoading(const KUrl& url); + void finishedDirLoading(const KUrl& url); /** * Is emitted after DolphinView::setUrl() has been invoked and provides - * the information how much percent of the current path have been loaded. + * the information how much percent of the current directory have been loaded. */ - void pathLoadingProgress(int percent); + void dirLoadingProgress(int percent); - void sortProgress(int percent); + /** + * Is emitted if the sorting is done asynchronously and provides the + * progress information of the sorting. + */ + void dirSortingProgress(int percent); /** * Is emitted if the DolphinView::setUrl() is invoked but the URL is not @@ -501,7 +510,7 @@ signals: void urlIsFileError(const KUrl& file); /** - * Emitted when KDirLister emits redirection. + * Emitted when the file-item-model emits redirection. * Testcase: fish://localhost */ void redirection(const KUrl& oldUrl, const KUrl& newUrl); @@ -606,23 +615,21 @@ private slots: void slotDeleteFileFinished(KJob* job); /** - * Invoked when the directory lister has been started the - * loading of \a url. + * Invoked when the file item model has started the loading + * of the directory specified by DolphinView::url(). */ - void slotDirListerStarted(const KUrl& url); + void slotDirLoadingStarted(); /** - * Invoked when the file item model indicates that the directory lister has completed the loading - * of items, and that expanded folders have been restored (if the view mode is 'Details', and the - * view state is restored after navigating back or forward in history). Assures that pasted items - * and renamed items get seleced. + * Invoked when the file item model indicates that the loading of a directory has + * been completed. Assures that pasted items and renamed items get seleced. */ - void slotLoadingCompleted(); + void slotDirLoadingCompleted(); /** - * Is invoked when the KDirLister indicates refreshed items. + * Is invoked when items of KFileItemModel have been changed. */ - void slotRefreshItems(); + void slotItemsChanged(); /** * Is invoked when the sort order has been changed by the user by clicking @@ -730,7 +737,6 @@ private: QVBoxLayout* m_topLayout; - DolphinDirLister* m_dirLister; DolphinItemListContainer* m_container; ToolTipManager* m_toolTipManager; diff --git a/src/views/versioncontrol/versioncontrolobserver.cpp b/src/views/versioncontrol/versioncontrolobserver.cpp index ac4709069..bbabd2e4e 100644 --- a/src/views/versioncontrol/versioncontrolobserver.cpp +++ b/src/views/versioncontrol/versioncontrolobserver.cpp @@ -21,7 +21,6 @@ #include "dolphin_versioncontrolsettings.h" -#include #include #include #include @@ -30,6 +29,7 @@ #include "updateitemstatesthread.h" +#include #include #include @@ -298,7 +298,6 @@ KVersionControlPlugin* VersionControlObserver::searchPlugin(const KUrl& director // Verify whether the current directory contains revision information // like .svn, .git, ... foreach (KVersionControlPlugin* plugin, plugins) { - // Use the KDirLister cache to check for .svn, .git, ... files const QString fileName = directory.path(KUrl::AddTrailingSlash) + plugin->fileName(); if (QFile::exists(fileName)) { return plugin; -- cgit v1.3