macro_bool_to_01(Nepomuk_FOUND HAVE_NEPOMUK)
configure_file(config-nepomuk.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-nepomuk.h )
+macro_bool_to_01(X11_Xrender_FOUND HAVE_XRENDER)
+configure_file(config-X11.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-X11.h )
+
include_directories( ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} )
if (Nepomuk_FOUND)
########### next target ###############
set(dolphinprivate_LIB_SRCS
+ kitemviews/kfileitemlistview.cpp
+ kitemviews/kfileitemlistwidget.cpp
+ kitemviews/kfileitemmodel.cpp
+ kitemviews/kfileitemmodelrolesupdater.cpp
+ kitemviews/kitemlistcontainer.cpp
+ kitemviews/kitemlistcontroller.cpp
+ kitemviews/kitemlistgroupheader.cpp
+ kitemviews/kitemlistselectionmanager.cpp
+ kitemviews/kitemlistsizehintresolver.cpp
+ kitemviews/kitemliststyleoption.cpp
+ kitemviews/kitemlistview.cpp
+ kitemviews/kitemlistviewanimation.cpp
+ kitemviews/kitemlistviewlayouter.cpp
+ kitemviews/kitemlistwidget.cpp
+ kitemviews/kitemmodelbase.cpp
+ kitemviews/kpixmapmodifier.cpp
settings/additionalinfodialog.cpp
settings/applyviewpropsjob.cpp
settings/dolphinsettings.cpp
settings/viewpropertiesdialog.cpp
settings/viewpropsprogressinfo.cpp
views/additionalinfoaccessor.cpp
- views/dolphincategorydrawer.cpp
views/dolphindirlister.cpp
views/dolphinview.cpp
- views/dolphindetailsview.cpp
- views/dolphindetailsviewexpander.cpp
- views/dolphinfileitemdelegate.cpp
- views/dolphiniconsview.cpp
- views/dolphincolumnview.cpp
- views/dolphincolumnviewcontainer.cpp
- views/dolphinmodel.cpp
+ views/dolphinitemlistcontainer.cpp
views/dolphinnewfilemenuobserver.cpp
views/dolphinremoteencoding.cpp
- views/dolphinsortfilterproxymodel.cpp
- views/dolphintreeview.cpp
views/dolphinviewactionhandler.cpp
views/dolphinviewautoscroller.cpp
- views/dolphinviewcontroller.cpp
- views/draganddrophelper.cpp
views/folderexpander.cpp
views/renamedialog.cpp
- views/selectiontoggle.cpp
- views/selectionmanager.cpp
views/tooltips/filemetadatatooltip.cpp
views/tooltips/tooltipmanager.cpp
views/versioncontrol/pendingthreadsmaintainer.cpp
views/versioncontrol/updateitemstatesthread.cpp
views/versioncontrol/versioncontrolobserver.cpp
- views/viewextensionsfactory.cpp
views/viewmodecontroller.cpp
views/viewproperties.cpp
views/zoomlevelinfo.cpp
)
kde4_add_kcfg_files(dolphinprivate_LIB_SRCS
- settings/dolphin_columnmodesettings.kcfgc
+ settings/dolphin_compactmodesettings.kcfgc
settings/dolphin_directoryviewpropertysettings.kcfgc
settings/dolphin_detailsmodesettings.kcfgc
settings/dolphin_iconsmodesettings.kcfgc
if (Nepomuk_FOUND)
target_link_libraries(dolphinprivate ${NEPOMUK_LIBRARIES} ${NEPOMUK_QUERY_LIBRARIES} nepomukutils ${SOPRANO_LIBRARIES})
endif (Nepomuk_FOUND)
+if(X11_Xrender_FOUND)
+ target_link_libraries(dolphinprivate ${X11_Xrender_LIB} )
+endif(X11_Xrender_FOUND)
+
set_target_properties(dolphinprivate PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION} )
settings/servicemodel.cpp
settings/startup/startupsettingspage.cpp
settings/trash/trashsettingspage.cpp
- settings/viewmodes/columnviewsettingspage.cpp
settings/viewmodes/detailsviewsettingspage.cpp
settings/viewmodes/dolphinfontrequester.cpp
settings/viewmodes/iconsizegroupbox.cpp
kde4_add_kcfg_files(dolphin_SRCS
panels/folders/dolphin_folderspanelsettings.kcfgc
panels/information/dolphin_informationpanelsettings.kcfgc
+ settings/dolphin_compactmodesettings.kcfgc
+ settings/dolphin_detailsmodesettings.kcfgc
+ settings/dolphin_iconsmodesettings.kcfgc
search/dolphin_searchsettings.kcfgc
settings/dolphin_versioncontrolsettings.kcfgc
)
set(kcm_dolphinviewmodes_PART_SRCS
settings/kcm/kcmdolphinviewmodes.cpp
- settings/viewmodes/columnviewsettingspage.cpp
settings/viewmodes/detailsviewsettingspage.cpp
settings/viewmodes/dolphinfontrequester.cpp
settings/viewmodes/iconsizegroupbox.cpp
settings/servicemodel.cpp)
kde4_add_kcfg_files(kcm_dolphinviewmodes_PART_SRCS
- settings/dolphin_columnmodesettings.kcfgc
+ settings/dolphin_compactmodesettings.kcfgc
settings/dolphin_directoryviewpropertysettings.kcfgc
settings/dolphin_detailsmodesettings.kcfgc
settings/dolphin_iconsmodesettings.kcfgc
install( PROGRAMS dolphin.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} )
install( FILES settings/dolphin_directoryviewpropertysettings.kcfg
settings/dolphin_generalsettings.kcfg
- settings/dolphin_columnmodesettings.kcfg
+ settings/dolphin_compactmodesettings.kcfg
settings/dolphin_iconsmodesettings.kcfg
settings/dolphin_detailsmodesettings.kcfg
settings/dolphin_versioncontrolsettings.kcfg
--- /dev/null
+#cmakedefine HAVE_XRENDER 1
// setup 'Create New' menu
DolphinNewFileMenu* newFileMenu = new DolphinNewFileMenu(m_mainWindow);
const DolphinView* view = m_mainWindow->activeViewContainer()->view();
- newFileMenu->setViewShowsHiddenFiles(view->showHiddenFiles());
+ newFileMenu->setViewShowsHiddenFiles(view->hiddenFilesShown());
newFileMenu->checkUpToDate();
newFileMenu->setPopupFiles(m_fileInfo.url());
newFileMenu->setEnabled(selectedItemsProperties().supportsWriting());
// setup 'Create New' menu
KNewFileMenu* newFileMenu = m_mainWindow->newFileMenu();
const DolphinView* view = m_mainWindow->activeViewContainer()->view();
- newFileMenu->setViewShowsHiddenFiles(view->showHiddenFiles());
+ newFileMenu->setViewShowsHiddenFiles(view->hiddenFilesShown());
newFileMenu->checkUpToDate();
newFileMenu->setPopupFiles(m_baseUrl);
m_popup->addMenu(newFileMenu->menu());
#include "statusbar/dolphinstatusbar.h"
#include "views/dolphinviewactionhandler.h"
#include "views/dolphinremoteencoding.h"
-#include "views/draganddrophelper.h"
#include "views/viewproperties.h"
#ifndef Q_OS_WIN
this, SLOT(showCommand(CommandType)));
connect(DolphinSettings::instance().placesModel(), SIGNAL(errorMessage(const QString&)),
this, SLOT(showErrorMessage(const QString&)));
- connect(&DragAndDropHelper::instance(), SIGNAL(errorMessage(const QString&)),
- this, SLOT(showErrorMessage(const QString&)));
+ //connect(&DragAndDropHelper::instance(), SIGNAL(errorMessage(const QString&)),
+ // this, SLOT(showErrorMessage(const QString&)));
const DolphinSettings& settings = DolphinSettings::instance();
void DolphinMainWindow::updateNewMenu()
{
- m_newFileMenu->setViewShowsHiddenFiles(activeViewContainer()->view()->showHiddenFiles());
+ m_newFileMenu->setViewShowsHiddenFiles(activeViewContainer()->view()->hiddenFilesShown());
m_newFileMenu->checkUpToDate();
m_newFileMenu->setPopupFiles(activeViewContainer()->url());
}
void DolphinMainWindow::createDirectory()
{
- m_newFileMenu->setViewShowsHiddenFiles(activeViewContainer()->view()->showHiddenFiles());
+ m_newFileMenu->setViewShowsHiddenFiles(activeViewContainer()->view()->hiddenFilesShown());
m_newFileMenu->setPopupFiles(activeViewContainer()->url());
m_newFileMenu->createDirectory();
}
if (!urls.isEmpty() && tab != -1) {
const ViewTab& viewTab = m_viewTab[tab];
const KUrl destPath = viewTab.isPrimaryViewActive ? viewTab.primaryView->url() : viewTab.secondaryView->url();
- DragAndDropHelper::instance().dropUrls(KFileItem(), destPath, event, m_tabBar);
+ Q_UNUSED(destPath);
+ //DragAndDropHelper::instance().dropUrls(KFileItem(), destPath, event, m_tabBar);
}
}
const int newWidth = (m_viewTab[tabIndex].primaryView->width() - splitter->handleWidth()) / 2;
const DolphinView* view = m_viewTab[tabIndex].primaryView->view();
- m_viewTab[tabIndex].secondaryView = createViewContainer(view->rootUrl(), 0);
+ m_viewTab[tabIndex].secondaryView = createViewContainer(view->url(), 0);
splitter->addWidget(m_viewTab[tabIndex].secondaryView);
splitter->setSizes(QList<int>() << newWidth << newWidth);
connectViewSignals(m_viewTab[tabIndex].secondaryView);
#include "settings/dolphinsettings.h"
#include "views/dolphinview.h"
#include "views/dolphinviewactionhandler.h"
-#include "views/dolphinsortfilterproxymodel.h"
-#include "views/dolphinmodel.h"
#include "views/dolphinnewfilemenuobserver.h"
#include "views/dolphinremoteencoding.h"
#include "views/dolphindirlister.h"
this, SLOT(slotSelectionChanged(KFileItemList)));
connect(m_view, SIGNAL(requestItemInfo(KFileItem)),
this, SLOT(slotRequestItemInfo(KFileItem)));
- connect(m_view, SIGNAL(modeChanged()),
+ connect(m_view, SIGNAL(modeChanged(DolphinView::Mode,DolphinView::Mode)),
this, SIGNAL(viewModeChanged())); // relay signal
connect(m_view, SIGNAL(redirection(KUrl, KUrl)),
this, SLOT(slotRedirection(KUrl, KUrl)));
{
// As requested by KNewFileMenu :
m_newFileMenu->checkUpToDate();
- m_newFileMenu->setViewShowsHiddenFiles(m_view->showHiddenFiles());
+ m_newFileMenu->setViewShowsHiddenFiles(m_view->hiddenFilesShown());
// And set the files that the menu apply on :
m_newFileMenu->setPopupFiles(url());
}
void DolphinPart::createDirectory()
{
- m_newFileMenu->setViewShowsHiddenFiles(m_view->showHiddenFiles());
+ m_newFileMenu->setViewShowsHiddenFiles(m_view->hiddenFilesShown());
m_newFileMenu->setPopupFiles(url());
m_newFileMenu->createDirectory();
}
Name[tg]=Тафсилотҳо
Name[th]=รายละเอียด
Name[tr]=Ayrıntılar
-Name[ug]=تÛ\95پسÙ\89Ù\84اتÙ\89
+Name[ug]=تÛ\95پسÙ\89Ù\84اتÙ\84ار
Name[uk]=Подробиці
Name[uz]=Tafsilotlar
Name[uz@cyrillic]=Тафсилотлар
<Action name="go_forward" />
<Separator name="separator_1" />
<Action name="icons" />
+ <Action name="compact" />
<Action name="details" />
- <Action name="columns" />
<Separator name="separator_0" />
<Action name="edit_find"/>
<Action name="show_preview" />
<Action priority="0" name="go_home"/>
<Action priority="0" name="stop"/>
<Action priority="0" name="icons"/>
+ <Action priority="0" name="compact"/>
<Action priority="0" name="details"/>
- <Action priority="0" name="columns"/>
<Action priority="0" name="view_zoom_in"/>
<Action priority="0" name="view_zoom_out"/>
<Action priority="0" name="edit_cut"/>
#include "search/dolphinsearchbox.h"
#include "settings/dolphinsettings.h"
#include "statusbar/dolphinstatusbar.h"
-#include "views/dolphincolumnview.h"
-#include "views/dolphindetailsview.h"
-#include "views/draganddrophelper.h"
-#include "views/dolphiniconsview.h"
-#include "views/dolphinmodel.h"
-#include "views/dolphinviewcontroller.h"
#include "views/viewmodecontroller.h"
#include "views/viewproperties.h"
connect(m_view, SIGNAL(urlIsFileError(const KUrl&)), this, SLOT(openFile(const KUrl&)));
connect(m_view, SIGNAL(selectionChanged(const KFileItemList&)), this, SLOT(delayedStatusBarUpdate()));
connect(m_view, SIGNAL(operationCompletedMessage(const QString&)), this, SLOT(showOperationCompletedMessage(const QString&)));
+ connect(m_view, SIGNAL(urlAboutToBeChanged(const KUrl&)), this, SLOT(slotViewUrlAboutToBeChanged(const KUrl&)));
+ connect(m_urlNavigator, SIGNAL(urlAboutToBeChanged(const KUrl&)),
+ this, SLOT(slotUrlNavigatorLocationAboutToBeChanged(const KUrl&)));
connect(m_urlNavigator, SIGNAL(urlChanged(const KUrl&)),
this, SLOT(slotUrlNavigatorLocationChanged(const KUrl&)));
- connect(m_urlNavigator, SIGNAL(urlAboutToBeChanged(const KUrl&)),
- this, SLOT(saveViewState()));
connect(m_urlNavigator, SIGNAL(historyChanged()),
this, SLOT(slotHistoryChanged()));
}
}
+void DolphinViewContainer::slotItemTriggered(const KFileItem& item)
+{
+ KUrl url = item.targetUrl();
+
+ if (item.isDir()) {
+ m_view->setUrl(url);
+ return;
+ }
+
+ const GeneralSettings* settings = DolphinSettings::instance().generalSettings();
+ const bool browseThroughArchives = settings->browseThroughArchives();
+ if (browseThroughArchives && item.isFile() && url.isLocalFile()) {
+ // Generic mechanism for redirecting to tar:/<path>/ when clicking on a tar file,
+ // zip:/<path>/ when clicking on a zip file, etc.
+ // The .protocol file specifies the mimetype that the kioslave handles.
+ // Note that we don't use mimetype inheritance since we don't want to
+ // open OpenDocument files as zip folders...
+ const QString protocol = KProtocolManager::protocolForArchiveMimetype(item.mimetype());
+ if (!protocol.isEmpty()) {
+ url.setProtocol(protocol);
+ m_view->setUrl(url);
+ return;
+ }
+ }
+
+ if (item.mimetype() == QLatin1String("application/x-desktop")) {
+ // Redirect to the URL in Type=Link desktop files
+ KDesktopFile desktopFile(url.toLocalFile());
+ if (desktopFile.hasLinkType()) {
+ url = desktopFile.readUrl();
+ m_view->setUrl(url);
+ return;
+ }
+ }
+
+ item.run();
+}
+
+void DolphinViewContainer::openFile(const KUrl& url)
+{
+ const KFileItem item(KFileItem::Unknown, KFileItem::Unknown, url);
+ slotItemTriggered(item);
+}
+
void DolphinViewContainer::showItemInfo(const KFileItem& item)
{
if (item.isNull()) {
setActive(true);
}
-void DolphinViewContainer::saveViewState()
+void DolphinViewContainer::slotViewUrlAboutToBeChanged(const KUrl& url)
{
- QByteArray locationState;
- QDataStream stream(&locationState, QIODevice::WriteOnly);
- m_view->saveState(stream);
- m_urlNavigator->saveLocationState(locationState);
+ // URL changes of the view can happen in two ways:
+ // 1. The URL navigator gets changed and will trigger the view to update its URL
+ // 2. The URL of the view gets changed and will trigger the URL navigator to update
+ // its URL (e.g. by clicking on an item)
+ // In this scope the view-state may only get saved in case 2:
+ if (url != m_urlNavigator->locationUrl()) {
+ saveViewState();
+ }
+}
+
+void DolphinViewContainer::slotUrlNavigatorLocationAboutToBeChanged(const KUrl& url)
+{
+ // URL changes of the view can happen in two ways:
+ // 1. The URL navigator gets changed and will trigger the view to update its URL
+ // 2. The URL of the view gets changed and will trigger the URL navigator to update
+ // its URL (e.g. by clicking on an item)
+ // In this scope the view-state may only get saved in case 1:
+ if (url != m_view->url()) {
+ saveViewState();
+ }
}
void DolphinViewContainer::slotUrlNavigatorLocationChanged(const KUrl& url)
{
if (KProtocolManager::supportsListing(url)) {
setSearchModeEnabled(isSearchUrl(url));
-
m_view->setUrl(url);
+
if (isActive() && !isSearchUrl(url)) {
// When an URL has been entered, the view should get the focus.
// The focus must be requested asynchronously, as changing the URL might create
void DolphinViewContainer::dropUrls(const KUrl& destination, QDropEvent* event)
{
- DragAndDropHelper::instance().dropUrls(KFileItem(), destination, event, this);
+ Q_UNUSED(destination);
+ Q_UNUSED(event);
+ //DragAndDropHelper::instance().dropUrls(KFileItem(), destination, event, this);
}
void DolphinViewContainer::redirect(const KUrl& oldUrl, const KUrl& newUrl)
void DolphinViewContainer::slotHistoryChanged()
{
QByteArray locationState = m_urlNavigator->locationState();
-
if (!locationState.isEmpty()) {
QDataStream stream(&locationState, QIODevice::ReadOnly);
m_view->restoreState(stream);
return protocol.contains("search") || (protocol == QLatin1String("nepomuk"));
}
-void DolphinViewContainer::slotItemTriggered(const KFileItem& item)
-{
- KUrl url = item.targetUrl();
-
- if (item.isDir()) {
- m_view->setUrl(url);
- return;
- }
-
- const GeneralSettings* settings = DolphinSettings::instance().generalSettings();
- const bool browseThroughArchives = settings->browseThroughArchives();
- if (browseThroughArchives && item.isFile() && url.isLocalFile()) {
- // Generic mechanism for redirecting to tar:/<path>/ when clicking on a tar file,
- // zip:/<path>/ when clicking on a zip file, etc.
- // The .protocol file specifies the mimetype that the kioslave handles.
- // Note that we don't use mimetype inheritance since we don't want to
- // open OpenDocument files as zip folders...
- const QString protocol = KProtocolManager::protocolForArchiveMimetype(item.mimetype());
- if (!protocol.isEmpty()) {
- url.setProtocol(protocol);
- m_view->setUrl(url);
- return;
- }
- }
-
- if (item.mimetype() == "application/x-desktop") {
- // redirect to the url in Type=Link desktop files
- KDesktopFile desktopFile(url.toLocalFile());
- if (desktopFile.hasLinkType()) {
- url = desktopFile.readUrl();
- m_view->setUrl(url);
- return;
- }
- }
-
- item.run();
-}
-
-void DolphinViewContainer::openFile(const KUrl& url)
+void DolphinViewContainer::saveViewState()
{
- const KFileItem item(KFileItem::Unknown, KFileItem::Unknown, url);
- slotItemTriggered(item);
+ QByteArray locationState;
+ QDataStream stream(&locationState, QIODevice::WriteOnly);
+ m_view->saveState(stream);
+ m_urlNavigator->saveLocationState(locationState);
}
#include "dolphinviewcontainer.moc"
* @short Represents a view for the directory content
* including the navigation bar, filter bar and status bar.
*
- * View modes for icons, details and columns are supported. Currently
+ * View modes for icons, compact and details are supported. Currently
* Dolphin allows to have up to two views inside the main window.
*
* @see DolphinView
void activate();
/**
- * Saves the state of the current view: contents position,
- * root URL, ...
+ * Is invoked if the signal urlAboutToBeChanged() from the DolphinView
+ * is emitted. Tries to save the view-state.
*/
- void saveViewState();
+ void slotViewUrlAboutToBeChanged(const KUrl& url);
+
+ /**
+ * Is invoked if the signal urlAboutToBeChanged() from the URL navigator
+ * is emitted. Tries to save the view-state.
+ */
+ void slotUrlNavigatorLocationAboutToBeChanged(const KUrl& url);
/**
* Restores the current view to show \a url and assures
*/
bool isSearchUrl(const KUrl& url) const;
+ /**
+ * Saves the state of the current view: contents position,
+ * root URL, ...
+ */
+ void saveViewState();
+
private:
QVBoxLayout* m_topLayout;
KUrlNavigator* m_urlNavigator;
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 "kfileitemlistview.h"
+
+#include "kitemlistgroupheader.h"
+#include "kfileitemmodelrolesupdater.h"
+#include "kfileitemlistwidget.h"
+#include "kfileitemmodel.h"
+#include <KLocale>
+#include <KStringHandler>
+
+#include <KDebug>
+
+#include <QTextLine>
+#include <QTimer>
+
+#define KFILEITEMLISTVIEW_DEBUG
+
+namespace {
+ const int ShortInterval = 50;
+ const int LongInterval = 300;
+}
+
+KFileItemListView::KFileItemListView(QGraphicsWidget* parent) :
+ KItemListView(parent),
+ m_itemLayout(IconsLayout),
+ m_modelRolesUpdater(0),
+ m_updateVisibleIndexRangeTimer(0),
+ m_updateIconSizeTimer(0),
+ m_minimumRolesWidths()
+{
+ setScrollOrientation(Qt::Vertical);
+ setWidgetCreator(new KItemListWidgetCreator<KFileItemListWidget>());
+ setGroupHeaderCreator(new KItemListGroupHeaderCreator<KItemListGroupHeader>());
+
+ m_updateVisibleIndexRangeTimer = new QTimer(this);
+ m_updateVisibleIndexRangeTimer->setSingleShot(true);
+ m_updateVisibleIndexRangeTimer->setInterval(ShortInterval);
+ connect(m_updateVisibleIndexRangeTimer, SIGNAL(timeout()), this, SLOT(updateVisibleIndexRange()));
+
+ m_updateIconSizeTimer = new QTimer(this);
+ m_updateIconSizeTimer->setSingleShot(true);
+ m_updateIconSizeTimer->setInterval(ShortInterval);
+ connect(m_updateIconSizeTimer, SIGNAL(timeout()), this, SLOT(updateIconSize()));
+
+ updateMinimumRolesWidths();
+}
+
+KFileItemListView::~KFileItemListView()
+{
+ delete widgetCreator();
+ delete groupHeaderCreator();
+
+ delete m_modelRolesUpdater;
+ m_modelRolesUpdater = 0;
+}
+
+void KFileItemListView::setPreviewsShown(bool show)
+{
+ if (m_modelRolesUpdater) {
+ m_modelRolesUpdater->setPreviewShown(show);
+ }
+}
+
+bool KFileItemListView::previewsShown() const
+{
+ return m_modelRolesUpdater->isPreviewShown();
+}
+
+void KFileItemListView::setItemLayout(Layout layout)
+{
+ if (m_itemLayout != layout) {
+ m_itemLayout = layout;
+ updateLayoutOfVisibleItems();
+ }
+}
+
+KFileItemListView::Layout KFileItemListView::itemLayout() const
+{
+ return m_itemLayout;
+}
+
+QSizeF KFileItemListView::itemSizeHint(int index) const
+{
+ const QHash<QByteArray, QVariant> values = model()->data(index);
+ const KItemListStyleOption& option = styleOption();
+ const int additionalRolesCount = qMax(visibleRoles().count() - 1, 0);
+
+ switch (m_itemLayout) {
+ case IconsLayout: {
+ const QString text = KStringHandler::preProcessWrap(values["name"].toString());
+
+ const qreal maxWidth = itemSize().width() - 2 * option.margin;
+ int textLinesCount = 0;
+ QTextLine line;
+
+ // Calculate the number of lines required for wrapping the name
+ QTextOption textOption(Qt::AlignHCenter);
+ textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
+
+ QTextLayout layout(text, option.font);
+ layout.setTextOption(textOption);
+ layout.beginLayout();
+ while ((line = layout.createLine()).isValid()) {
+ line.setLineWidth(maxWidth);
+ line.naturalTextWidth();
+ ++textLinesCount;
+ }
+ layout.endLayout();
+
+ // Add one line for each additional information
+ textLinesCount += additionalRolesCount;
+
+ const qreal height = textLinesCount * option.fontMetrics.height() +
+ option.iconSize +
+ option.margin * 4;
+ return QSizeF(itemSize().width(), height);
+ }
+
+ case CompactLayout: {
+ // For each row exactly one role is shown. Calculate the maximum required width that is necessary
+ // to show all roles without horizontal clipping.
+ qreal maximumRequiredWidth = 0.0;
+ QHashIterator<QByteArray, int> it(visibleRoles());
+ while (it.hasNext()) {
+ it.next();
+ const QByteArray& role = it.key();
+ const QString text = values[role].toString();
+ const qreal requiredWidth = option.fontMetrics.width(text);
+ maximumRequiredWidth = qMax(maximumRequiredWidth, requiredWidth);
+ }
+
+ const qreal width = option.margin * 4 + option.iconSize + maximumRequiredWidth;
+ const qreal height = option.margin * 2 + qMax(option.iconSize, (1 + additionalRolesCount) * option.fontMetrics.height());
+ return QSizeF(width, height);
+ }
+
+ case DetailsLayout: {
+ // The width will be determined dynamically by KFileItemListView::visibleRoleSizes()
+ const qreal height = option.margin * 2 + qMax(option.iconSize, option.fontMetrics.height());
+ return QSizeF(-1, height);
+ }
+
+ default:
+ Q_ASSERT(false);
+ break;
+ }
+
+ return QSize();
+}
+
+QHash<QByteArray, QSizeF> KFileItemListView::visibleRoleSizes() const
+{
+ QElapsedTimer timer;
+ timer.start();
+
+ QHash<QByteArray, QSizeF> sizes;
+
+ const int itemCount = model()->count();
+ for (int i = 0; i < itemCount; ++i) {
+ QHashIterator<QByteArray, int> it(visibleRoles());
+ while (it.hasNext()) {
+ it.next();
+ const QByteArray& visibleRole = it.key();
+
+ QSizeF maxSize = sizes.value(visibleRole, QSizeF(0, 0));
+
+ const QSizeF itemSize = visibleRoleSizeHint(i, visibleRole);
+ maxSize = maxSize.expandedTo(itemSize);
+ sizes.insert(visibleRole, maxSize);
+ }
+
+ if (i > 100 && timer.elapsed() > 200) {
+ // When having several thousands of items calculating the sizes can get
+ // very expensive. We accept a possibly too small role-size in favour
+ // of having no blocking user interface.
+ #ifdef KFILEITEMLISTVIEW_DEBUG
+ kDebug() << "Timer exceeded, stopped after" << i << "items";
+ #endif
+ break;
+ }
+ }
+
+#ifdef KFILEITEMLISTVIEW_DEBUG
+ kDebug() << "[TIME] Calculated dynamic item size for " << itemCount << "items:" << timer.elapsed();
+#endif
+ return sizes;
+}
+
+void KFileItemListView::initializeItemListWidget(KItemListWidget* item)
+{
+ KFileItemListWidget* fileItemListWidget = static_cast<KFileItemListWidget*>(item);
+
+ switch (m_itemLayout) {
+ case IconsLayout: fileItemListWidget->setLayout(KFileItemListWidget::IconsLayout); break;
+ case CompactLayout: fileItemListWidget->setLayout(KFileItemListWidget::CompactLayout); break;
+ case DetailsLayout: fileItemListWidget->setLayout(KFileItemListWidget::DetailsLayout); break;
+ default: Q_ASSERT(false); break;
+ }
+}
+
+void KFileItemListView::onModelChanged(KItemModelBase* current, KItemModelBase* previous)
+{
+ Q_UNUSED(previous);
+ Q_ASSERT(qobject_cast<KFileItemModel*>(current));
+
+ if (m_modelRolesUpdater) {
+ delete m_modelRolesUpdater;
+ }
+
+ m_modelRolesUpdater = new KFileItemModelRolesUpdater(static_cast<KFileItemModel*>(current), this);
+ const int size = styleOption().iconSize;
+ m_modelRolesUpdater->setIconSize(QSize(size, size));
+}
+
+void KFileItemListView::onScrollOrientationChanged(Qt::Orientation current, Qt::Orientation previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+ updateLayoutOfVisibleItems();
+}
+
+void KFileItemListView::onItemSizeChanged(const QSizeF& current, const QSizeF& previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+ triggerVisibleIndexRangeUpdate();
+}
+
+void KFileItemListView::onOffsetChanged(qreal current, qreal previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+ triggerVisibleIndexRangeUpdate();
+}
+
+void KFileItemListView::onVisibleRolesChanged(const QHash<QByteArray, int>& current, const QHash<QByteArray, int>& previous)
+{
+ Q_UNUSED(previous);
+
+ Q_ASSERT(qobject_cast<KFileItemModel*>(model()));
+ KFileItemModel* fileItemModel = static_cast<KFileItemModel*>(model());
+
+ // KFileItemModel does not distinct between "visible" and "invisible" roles.
+ // Add all roles that are mandatory for having a working KFileItemListView:
+ QSet<QByteArray> keys = current.keys().toSet();
+ QSet<QByteArray> roles = keys;
+ roles.insert("iconPixmap");
+ roles.insert("iconName");
+ roles.insert("name"); // TODO: just don't allow to disable it
+ roles.insert("isDir");
+ if (m_itemLayout == DetailsLayout) {
+ roles.insert("isExpanded");
+ roles.insert("expansionLevel");
+ }
+
+ fileItemModel->setRoles(roles);
+
+ m_modelRolesUpdater->setRoles(keys);
+}
+
+void KFileItemListView::onStyleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+ triggerIconSizeUpdate();
+}
+
+void KFileItemListView::onTransactionBegin()
+{
+ m_modelRolesUpdater->setPaused(true);
+}
+
+void KFileItemListView::onTransactionEnd()
+{
+ // Only unpause the model-roles-updater if no timer is active. If one
+ // timer is still active the model-roles-updater will be unpaused later as
+ // soon as the timer has been exceeded.
+ const bool timerActive = m_updateVisibleIndexRangeTimer->isActive() ||
+ m_updateIconSizeTimer->isActive();
+ if (!timerActive) {
+ m_modelRolesUpdater->setPaused(false);
+ }
+}
+
+void KFileItemListView::resizeEvent(QGraphicsSceneResizeEvent* event)
+{
+ KItemListView::resizeEvent(event);
+ triggerVisibleIndexRangeUpdate();
+}
+
+void KFileItemListView::slotItemsRemoved(const KItemRangeList& itemRanges)
+{
+ KItemListView::slotItemsRemoved(itemRanges);
+ updateTimersInterval();
+}
+
+void KFileItemListView::triggerVisibleIndexRangeUpdate()
+{
+ m_modelRolesUpdater->setPaused(true);
+ m_updateVisibleIndexRangeTimer->start();
+}
+
+void KFileItemListView::updateVisibleIndexRange()
+{
+ if (!m_modelRolesUpdater) {
+ return;
+ }
+
+ const int index = firstVisibleIndex();
+ const int count = lastVisibleIndex() - index + 1;
+ m_modelRolesUpdater->setVisibleIndexRange(index, count);
+
+ if (m_updateIconSizeTimer->isActive()) {
+ // If the icon-size update is pending do an immediate update
+ // of the icon-size before unpausing m_modelRolesUpdater. This prevents
+ // an unnecessary expensive recreation of all previews afterwards.
+ m_updateIconSizeTimer->stop();
+ const KItemListStyleOption& option = styleOption();
+ m_modelRolesUpdater->setIconSize(QSize(option.iconSize, option.iconSize));
+ }
+
+ m_modelRolesUpdater->setPaused(isTransactionActive());
+ updateTimersInterval();
+}
+
+void KFileItemListView::triggerIconSizeUpdate()
+{
+ m_modelRolesUpdater->setPaused(true);
+ m_updateIconSizeTimer->start();
+}
+
+void KFileItemListView::updateIconSize()
+{
+ if (!m_modelRolesUpdater) {
+ return;
+ }
+
+ const KItemListStyleOption& option = styleOption();
+ m_modelRolesUpdater->setIconSize(QSize(option.iconSize, option.iconSize));
+
+ if (m_updateVisibleIndexRangeTimer->isActive()) {
+ // If the visibility-index-range update is pending do an immediate update
+ // of the range before unpausing m_modelRolesUpdater. This prevents
+ // an unnecessary expensive recreation of all previews afterwards.
+ m_updateVisibleIndexRangeTimer->stop();
+ const int index = firstVisibleIndex();
+ const int count = lastVisibleIndex() - index + 1;
+ m_modelRolesUpdater->setVisibleIndexRange(index, count);
+ }
+
+ m_modelRolesUpdater->setPaused(isTransactionActive());
+ updateTimersInterval();
+}
+
+QSizeF KFileItemListView::visibleRoleSizeHint(int index, const QByteArray& role) const
+{
+ const KItemListStyleOption& option = styleOption();
+
+ qreal width = m_minimumRolesWidths.value(role, 0);
+ const qreal height = option.margin * 2 + option.fontMetrics.height();
+
+ const QVariant value = model()->data(index).value(role);
+ const QString text = value.toString();
+ if (!text.isEmpty()) {
+ width = qMax(width, qreal(option.margin * 2 + option.fontMetrics.width(text)));
+ }
+
+ return QSizeF(width, height);
+}
+
+void KFileItemListView::updateLayoutOfVisibleItems()
+{
+ foreach (KItemListWidget* widget, visibleItemListWidgets()) {
+ initializeItemListWidget(widget);
+ }
+ triggerVisibleIndexRangeUpdate();
+}
+
+void KFileItemListView::updateTimersInterval()
+{
+ if (!model()) {
+ return;
+ }
+
+ // The ShortInterval is used for cases like switching the directory: If the
+ // model is empty and filled later the creation of the previews should be done
+ // as soon as possible. The LongInterval is used when the model already contains
+ // items and assures that operations like zooming don't result in too many temporary
+ // recreations of the previews.
+
+ const int interval = (model()->count() <= 0) ? ShortInterval : LongInterval;
+ m_updateVisibleIndexRangeTimer->setInterval(interval);
+ m_updateIconSizeTimer->setInterval(interval);
+}
+
+void KFileItemListView::updateMinimumRolesWidths()
+{
+ m_minimumRolesWidths.clear();
+
+ const KItemListStyleOption& option = styleOption();
+ const QString sizeText = QLatin1String("888888") + i18nc("@item:intable", "items");
+ m_minimumRolesWidths.insert("size", option.fontMetrics.width(sizeText));
+}
+
+#include "kfileitemlistview.moc"
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 KFILEITEMLISTVIEW_H
+#define KFILEITEMLISTVIEW_H
+
+#include <libdolphin_export.h>
+
+#include <kitemviews/kitemlistview.h>
+
+class KFileItemModelRolesUpdater;
+class QTimer;
+
+class LIBDOLPHINPRIVATE_EXPORT KFileItemListView : public KItemListView
+{
+ Q_OBJECT
+
+public:
+ enum Layout
+ {
+ IconsLayout,
+ CompactLayout,
+ DetailsLayout
+ };
+
+ KFileItemListView(QGraphicsWidget* parent = 0);
+ virtual ~KFileItemListView();
+
+ void setPreviewsShown(bool show);
+ bool previewsShown() const;
+
+ void setItemLayout(Layout layout);
+ Layout itemLayout() const;
+
+ virtual QSizeF itemSizeHint(int index) const;
+ virtual QHash<QByteArray, QSizeF> visibleRoleSizes() const;
+
+protected:
+ virtual void initializeItemListWidget(KItemListWidget* item);
+ virtual void onModelChanged(KItemModelBase* current, KItemModelBase* previous);
+ virtual void onScrollOrientationChanged(Qt::Orientation current, Qt::Orientation previous);
+ virtual void onItemSizeChanged(const QSizeF& current, const QSizeF& previous);
+ virtual void onOffsetChanged(qreal current, qreal previous);
+ virtual void onVisibleRolesChanged(const QHash<QByteArray, int>& current, const QHash<QByteArray, int>& previous);
+ virtual void onStyleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous);
+ virtual void onTransactionBegin();
+ virtual void onTransactionEnd();
+ virtual void resizeEvent(QGraphicsSceneResizeEvent* event);
+
+protected slots:
+ virtual void slotItemsRemoved(const KItemRangeList& itemRanges);
+
+private slots:
+ void triggerVisibleIndexRangeUpdate();
+ void updateVisibleIndexRange();
+
+ void triggerIconSizeUpdate();
+ void updateIconSize();
+
+private:
+ QSizeF visibleRoleSizeHint(int index, const QByteArray& role) const;
+ void updateLayoutOfVisibleItems();
+ void updateTimersInterval();
+ void updateMinimumRolesWidths();
+
+private:
+ Layout m_itemLayout;
+
+ KFileItemModelRolesUpdater* m_modelRolesUpdater;
+ QTimer* m_updateVisibleIndexRangeTimer;
+ QTimer* m_updateIconSizeTimer;
+
+ // Cache for calculating visibleRoleSizes() in a fast way
+ QHash<QByteArray, int> m_minimumRolesWidths;
+
+ friend class KFileItemListViewTest; // For unit testing
+};
+
+#endif
+
+
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 "kfileitemlistwidget.h"
+
+#include "kfileitemmodel.h"
+#include "kitemlistview.h"
+#include "kpixmapmodifier_p.h"
+
+#include <KIcon>
+#include <KIconEffect>
+#include <KIconLoader>
+#include <KLocale>
+#include <KStringHandler>
+#include <KDebug>
+
+#include <QFontMetricsF>
+#include <QGraphicsSceneResizeEvent>
+#include <QPainter>
+#include <QTextLayout>
+#include <QTextLine>
+
+//#define KFILEITEMLISTWIDGET_DEBUG
+
+KFileItemListWidget::KFileItemListWidget(QGraphicsItem* parent) :
+ KItemListWidget(parent),
+ m_isDir(false),
+ m_dirtyLayout(true),
+ m_dirtyContent(true),
+ m_dirtyContentRoles(),
+ m_layout(IconsLayout),
+ m_pixmapPos(),
+ m_pixmap(),
+ m_scaledPixmapSize(),
+ m_hoverPixmapRect(),
+ m_hoverPixmap(),
+ m_textPos(),
+ m_text(),
+ m_textsBoundingRect(),
+ m_sortedVisibleRoles(),
+ m_expansionArea(),
+ m_additionalInfoTextColor()
+{
+ for (int i = 0; i < TextIdCount; ++i) {
+ m_text[i].setTextFormat(Qt::PlainText);
+ m_text[i].setPerformanceHint(QStaticText::AggressiveCaching);
+ }
+}
+
+KFileItemListWidget::~KFileItemListWidget()
+{
+}
+
+void KFileItemListWidget::setLayout(Layout layout)
+{
+ if (m_layout != layout) {
+ m_layout = layout;
+ m_dirtyLayout = true;
+ update();
+ }
+}
+
+KFileItemListWidget::Layout KFileItemListWidget::layout() const
+{
+ return m_layout;
+}
+
+void KFileItemListWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
+{
+ KItemListWidget::paint(painter, option, widget);
+
+ painter->setRenderHint(QPainter::Antialiasing);
+
+ if (m_dirtyContent || m_dirtyLayout) {
+ const_cast<KFileItemListWidget*>(this)->updateCache();
+ }
+
+ if (m_isDir && !m_expansionArea.isEmpty()) {
+ QStyleOption arrowOption;
+ arrowOption.rect = m_expansionArea.toRect();
+ const QStyle::PrimitiveElement arrow = data()["isExpanded"].toBool()
+ ? QStyle::PE_IndicatorArrowDown : QStyle::PE_IndicatorArrowRight;
+ style()->drawPrimitive(arrow, &arrowOption, painter);
+ }
+
+ const bool isHovered = (hoverOpacity() > 0.0);
+
+ const KItemListStyleOption& itemListStyleOption = styleOption();
+ if (isHovered) {
+ // Blend the unhovered and hovered pixmap if the hovering
+ // animation is ongoing
+ if (hoverOpacity() < 1.0) {
+ drawPixmap(painter, m_pixmap);
+ }
+
+ const qreal opacity = painter->opacity();
+ painter->setOpacity(hoverOpacity() * opacity);
+ drawPixmap(painter, m_hoverPixmap);
+
+ // Draw the hover background for the text
+ QRectF textsBoundingRect = m_textsBoundingRect;
+ const qreal marginDiff = itemListStyleOption.margin / 2;
+ textsBoundingRect.adjust(marginDiff, marginDiff, -marginDiff, -marginDiff);
+ painter->setOpacity(hoverOpacity() * opacity * 0.1);
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(itemListStyleOption.palette.text());
+ painter->drawRoundedRect(textsBoundingRect, 4, 4);
+
+ painter->setOpacity(opacity);
+ } else {
+ drawPixmap(painter, m_pixmap);
+ }
+
+ painter->setFont(itemListStyleOption.font);
+ painter->setPen(itemListStyleOption.palette.text().color());
+ painter->drawStaticText(m_textPos[Name], m_text[Name]);
+
+ painter->setPen(m_additionalInfoTextColor);
+ for (int i = Name + 1; i < TextIdCount; ++i) {
+ painter->drawStaticText(m_textPos[i], m_text[i]);
+ }
+
+#ifdef KFILEITEMLISTWIDGET_DEBUG
+ painter->setPen(Qt::red);
+ painter->setBrush(Qt::NoBrush);
+ painter->drawText(QPointF(0, itemListStyleOption.fontMetrics.height()), QString::number(index()));
+ painter->drawRect(rect());
+#endif
+}
+
+bool KFileItemListWidget::contains(const QPointF& point) const
+{
+ return KItemListWidget::contains(point) || m_textsBoundingRect.contains(point);
+}
+
+QRectF KFileItemListWidget::hoverBoundingRect() const
+{
+ QRectF bounds = m_hoverPixmapRect;
+ const qreal margin = styleOption().margin;
+ bounds.adjust(-margin, -margin, margin, margin);
+ return bounds;
+}
+
+QRectF KFileItemListWidget::expansionToggleRect() const
+{
+ return m_isDir ? m_expansionArea : QRectF();
+}
+
+void KFileItemListWidget::dataChanged(const QHash<QByteArray, QVariant>& current,
+ const QSet<QByteArray>& roles)
+{
+ KItemListWidget::dataChanged(current, roles);
+ m_dirtyContent = true;
+
+ QSet<QByteArray> dirtyRoles;
+ if (roles.isEmpty()) {
+ dirtyRoles = visibleRoles().keys().toSet();
+ dirtyRoles.insert("iconPixmap");
+ dirtyRoles.insert("iconName");
+ } else {
+ dirtyRoles = roles;
+ }
+
+ QSetIterator<QByteArray> it(dirtyRoles);
+ while (it.hasNext()) {
+ const QByteArray& role = it.next();
+ m_dirtyContentRoles.insert(role);
+ }
+}
+
+void KFileItemListWidget::visibleRolesChanged(const QHash<QByteArray, int>& current,
+ const QHash<QByteArray, int>& previous)
+{
+ KItemListWidget::visibleRolesChanged(current, previous);
+ m_dirtyLayout = true;
+
+ // Cache the roles sorted into m_sortedVisibleRoles:
+ const int visibleRolesCount = current.count();
+ m_sortedVisibleRoles.clear();
+ m_sortedVisibleRoles.reserve(visibleRolesCount);
+ for (int i = 0; i < visibleRolesCount; ++i) {
+ m_sortedVisibleRoles.append(QByteArray());
+ }
+
+ QHashIterator<QByteArray, int> it(current);
+ while (it.hasNext()) {
+ it.next();
+
+ const int index = it.value();
+ if (index < 0 || index >= visibleRolesCount || !m_sortedVisibleRoles.at(index).isEmpty()) {
+ kWarning() << "The visible roles have an invalid sort order.";
+ break;
+ }
+
+ const QByteArray& role = it.key();
+ m_sortedVisibleRoles[index] = role;
+ }
+}
+
+void KFileItemListWidget::visibleRolesSizesChanged(const QHash<QByteArray, QSizeF>& current,
+ const QHash<QByteArray, QSizeF>& previous)
+{
+ KItemListWidget::visibleRolesSizesChanged(current, previous);
+ m_dirtyLayout = true;
+}
+
+void KFileItemListWidget::styleOptionChanged(const KItemListStyleOption& current,
+ const KItemListStyleOption& previous)
+{
+ KItemListWidget::styleOptionChanged(current, previous);
+
+ // For the color of the additional info the inactive text color
+ // is not used as this might lead to unreadable text for some color schemes. Instead
+ // the text color is slightly mixed with the background color.
+ const QColor c1 = current.palette.text().color();
+ const QColor c2 = current.palette.background().color();
+ const int p1 = 70;
+ const int p2 = 100 - p1;
+ m_additionalInfoTextColor = QColor((c1.red() * p1 + c2.red() * p2) / 100,
+ (c1.green() * p1 + c2.green() * p2) / 100,
+ (c1.blue() * p1 + c2.blue() * p2) / 100);
+
+ m_dirtyLayout = true;
+}
+
+void KFileItemListWidget::resizeEvent(QGraphicsSceneResizeEvent* event)
+{
+ KItemListWidget::resizeEvent(event);
+ m_dirtyLayout = true;
+}
+
+void KFileItemListWidget::updateCache()
+{
+ if (index() < 0) {
+ return;
+ }
+
+ m_isDir = data()["isDir"].toBool();
+
+ updateExpansionArea();
+ updateTextsCache();
+ updatePixmapCache();
+
+ m_dirtyLayout = false;
+ m_dirtyContent = false;
+ m_dirtyContentRoles.clear();
+}
+
+void KFileItemListWidget::updateExpansionArea()
+{
+ if (m_layout == DetailsLayout) {
+ const QHash<QByteArray, QVariant> values = data();
+ Q_ASSERT(values.contains("expansionLevel"));
+ const KItemListStyleOption& option = styleOption();
+ const int expansionLevel = values.value("expansionLevel", 0).toInt();
+
+ const qreal widgetHeight = size().height();
+ const qreal expansionLevelSize = KIconLoader::SizeSmall;
+ const qreal x = option.margin + expansionLevel * widgetHeight;
+ const qreal y = (widgetHeight - expansionLevelSize) / 2;
+ m_expansionArea = QRectF(x, y, expansionLevelSize, expansionLevelSize);
+ } else {
+ m_expansionArea = QRectF();
+ }
+}
+
+void KFileItemListWidget::updatePixmapCache()
+{
+ // Precondition: Requires already updated m_textPos values to calculate
+ // the remaining height when the alignment is vertical.
+
+ const bool iconOnTop = (m_layout == IconsLayout);
+ const KItemListStyleOption& option = styleOption();
+ const int iconHeight = option.iconSize;
+
+ const QHash<QByteArray, QVariant> values = data();
+ const QSizeF widgetSize = size();
+
+ int scaledIconHeight = 0;
+ if (iconOnTop) {
+ scaledIconHeight = static_cast<int>(m_textPos[Name].y() - 3 * option.margin);
+ } else {
+ const int textRowsCount = (m_layout == CompactLayout) ? visibleRoles().count() : 1;
+ const qreal requiredTextHeight = textRowsCount * option.fontMetrics.height();
+ scaledIconHeight = (requiredTextHeight < iconHeight) ? widgetSize.height() - 2 * option.margin : iconHeight;
+ }
+
+ bool updatePixmap = (iconHeight != m_pixmap.height());
+ if (!updatePixmap && m_dirtyContent) {
+ updatePixmap = m_dirtyContentRoles.isEmpty()
+ || m_dirtyContentRoles.contains("iconPixmap")
+ || m_dirtyContentRoles.contains("iconName");
+ }
+
+ if (updatePixmap) {
+ m_pixmap = values["iconPixmap"].value<QPixmap>();
+ if (m_pixmap.isNull()) {
+ // Use the icon that fits to the MIME-type
+ QString iconName = values["iconName"].toString();
+ if (iconName.isEmpty()) {
+ // The icon-name has not been not resolved by KFileItemModelRolesUpdater,
+ // use a generic icon as fallback
+ iconName = QLatin1String("unknown");
+ }
+ m_pixmap = pixmapForIcon(iconName, iconHeight);
+ m_hoverPixmapRect.setSize(m_pixmap.size());
+ } else if (m_pixmap.size() != QSize(iconHeight, iconHeight)) {
+ // A custom pixmap has been applied. Assure that the pixmap
+ // is scaled to the available size.
+ const bool scale = m_pixmap.width() > iconHeight || m_pixmap.height() > iconHeight ||
+ (m_pixmap.width() < iconHeight && m_pixmap.height() < iconHeight);
+ if (scale) {
+ KPixmapModifier::scale(m_pixmap, QSize(iconHeight, iconHeight));
+ }
+ m_hoverPixmapRect.setSize(m_pixmap.size());
+
+ // To simplify the handling of scaling the original pixmap
+ // will be embedded into a square pixmap.
+ QPixmap squarePixmap(iconHeight, iconHeight);
+ squarePixmap.fill(Qt::transparent);
+
+ QPainter painter(&squarePixmap);
+ if (iconOnTop) {
+ const int x = (iconHeight - m_pixmap.width()) / 2; // Center horizontally
+ const int y = iconHeight - m_pixmap.height(); // Align on bottom
+ painter.drawPixmap(x, y, m_pixmap);
+ } else {
+ const int x = iconHeight - m_pixmap.width(); // Align right
+ const int y = (iconHeight - m_pixmap.height()) / 2; // Center vertically
+ painter.drawPixmap(x, y, m_pixmap);
+ }
+
+ m_pixmap = squarePixmap;
+ } else {
+ m_hoverPixmapRect.setSize(m_pixmap.size());
+ }
+
+ Q_ASSERT(m_pixmap.height() == iconHeight);
+ }
+
+ m_scaledPixmapSize = QSize(scaledIconHeight, scaledIconHeight);
+
+ if (iconOnTop) {
+ m_pixmapPos.setX((widgetSize.width() - m_scaledPixmapSize.width()) / 2);
+ } else {
+ m_pixmapPos.setX(m_textPos[Name].x() - 2 * option.margin - scaledIconHeight);
+ }
+ m_pixmapPos.setY(option.margin);
+
+ // Center the hover rectangle horizontally and align it on bottom
+ const qreal x = m_pixmapPos.x() + (m_scaledPixmapSize.width() - m_hoverPixmapRect.width()) / 2.0;
+ const qreal y = m_pixmapPos.y() + m_scaledPixmapSize.height() - m_hoverPixmapRect.height();
+ m_hoverPixmapRect.moveTopLeft(QPointF(x, y));
+
+ // Prepare the pixmap that is used when the item gets hovered
+ if (option.state & QStyle::State_MouseOver) {
+ m_hoverPixmap = m_pixmap;
+ KIconEffect* effect = KIconLoader::global()->iconEffect();
+ // In the KIconLoader terminology, active = hover.
+ if (effect->hasEffect(KIconLoader::Desktop, KIconLoader::ActiveState)) {
+ m_hoverPixmap = effect->apply(m_pixmap, KIconLoader::Desktop, KIconLoader::ActiveState);
+ } else {
+ m_hoverPixmap = m_pixmap;
+ }
+ } else if (hoverOpacity() <= 0.0) {
+ // No hover animation is ongoing. Clear m_hoverPixmap to save memory.
+ m_hoverPixmap = QPixmap();
+ }
+}
+
+void KFileItemListWidget::updateTextsCache()
+{
+ QTextOption textOption;
+ switch (m_layout) {
+ case IconsLayout:
+ textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
+ textOption.setAlignment(Qt::AlignHCenter);
+ break;
+ case CompactLayout:
+ case DetailsLayout:
+ textOption.setAlignment(Qt::AlignLeft);
+ textOption.setWrapMode(QTextOption::NoWrap);
+ break;
+ default:
+ Q_ASSERT(false);
+ break;
+ }
+
+ for (int i = 0; i < TextIdCount; ++i) {
+ m_text[i].setText(QString());
+ m_text[i].setTextOption(textOption);
+ }
+
+ switch (m_layout) {
+ case IconsLayout: updateIconsLayoutTextCache(); break;
+ case CompactLayout: updateCompactLayoutTextCache(); break;
+ case DetailsLayout: updateDetailsLayoutTextCache(); break;
+ default: Q_ASSERT(false); break;
+ }
+}
+
+void KFileItemListWidget::updateIconsLayoutTextCache()
+{
+ // +------+
+ // | Icon |
+ // +------+
+ //
+ // Name role that
+ // might get wrapped above
+ // several lines.
+ // Additional role 1
+ // Additional role 2
+
+ const QHash<QByteArray, QVariant> values = data();
+
+ const KItemListStyleOption& option = styleOption();
+ const qreal maxWidth = size().width() - 2 * option.margin;
+ const qreal widgetHeight = size().height();
+ const qreal fontHeight = option.fontMetrics.height();
+
+ // Initialize properties for the "name" role. It will be used as anchor
+ // for initializing the position of the other roles.
+ m_text[Name].setText(KStringHandler::preProcessWrap(values["name"].toString()));
+
+ // Calculate the number of lines required for the name and the required width
+ int textLinesCountForName = 0;
+ qreal requiredWidthForName = 0;
+ QTextLine line;
+
+ QTextLayout layout(m_text[Name].text(), option.font);
+ layout.setTextOption(m_text[Name].textOption());
+ layout.beginLayout();
+ while ((line = layout.createLine()).isValid()) {
+ line.setLineWidth(maxWidth);
+ requiredWidthForName = qMax(requiredWidthForName, line.naturalTextWidth());
+ ++textLinesCountForName;
+ }
+ layout.endLayout();
+
+ // Use one line for each additional information
+ int textLinesCount = textLinesCountForName;
+ const int additionalRolesCount = qMax(visibleRoles().count() - 1, 0);
+ textLinesCount += additionalRolesCount;
+
+ m_text[Name].setTextWidth(maxWidth);
+ m_textPos[Name] = QPointF(option.margin, widgetHeight - textLinesCount * fontHeight - option.margin);
+ m_textsBoundingRect = QRectF(option.margin + (maxWidth - requiredWidthForName) / 2,
+ m_textPos[Name].y(),
+ requiredWidthForName,
+ m_text[Name].size().height());
+
+ // Calculate the position for each additional information
+ qreal y = m_textPos[Name].y() + textLinesCountForName * fontHeight;
+ foreach (const QByteArray& role, m_sortedVisibleRoles) {
+ const TextId textId = roleTextId(role);
+ if (textId == Name) {
+ continue;
+ }
+
+ const QString text = roleText(textId, values[role]);
+ m_text[textId].setText(text);
+
+ qreal requiredWidth = 0;
+
+ QTextLayout layout(text, option.font);
+ layout.setTextOption(m_text[textId].textOption());
+ layout.beginLayout();
+ QTextLine textLine = layout.createLine();
+ if (textLine.isValid()) {
+ textLine.setLineWidth(maxWidth);
+ requiredWidth = textLine.naturalTextWidth();
+ if (textLine.textLength() < text.length()) {
+ // TODO: QFontMetrics::elidedText() works different regarding the given width
+ // in comparison to QTextLine::setLineWidth(). It might happen that the text does
+ // not get elided although it does not fit into the given width. As workaround
+ // the margin is substracted.
+ const QString elidedText = option.fontMetrics.elidedText(text, Qt::ElideRight, maxWidth - option.margin);
+ m_text[textId].setText(elidedText);
+ }
+ }
+ layout.endLayout();
+
+ m_textPos[textId] = QPointF(option.margin, y);
+ m_text[textId].setTextWidth(maxWidth);
+
+ const QRectF textBoundingRect(option.margin + (maxWidth - requiredWidth) / 2, y, requiredWidth, fontHeight);
+ m_textsBoundingRect |= textBoundingRect;
+
+ y += fontHeight;
+ }
+
+ // Add a margin to the text bounding rectangle
+ const qreal margin = option.margin;
+ m_textsBoundingRect.adjust(-margin, -margin, margin, margin);
+}
+
+void KFileItemListWidget::updateCompactLayoutTextCache()
+{
+ // +------+ Name role
+ // | Icon | Additional role 1
+ // +------+ Additional role 2
+
+ const QHash<QByteArray, QVariant> values = data();
+
+ const KItemListStyleOption& option = styleOption();
+ const qreal widgetHeight = size().height();
+ const qreal fontHeight = option.fontMetrics.height();
+ const qreal textLinesHeight = qMax(visibleRoles().count(), 1) * fontHeight;
+ const int scaledIconSize = (textLinesHeight < option.iconSize) ? widgetHeight - 2 * option.margin : option.iconSize;
+
+ qreal maximumRequiredTextWidth = 0;
+ const qreal x = option.margin * 3 + scaledIconSize;
+ qreal y = (widgetHeight - textLinesHeight) / 2;
+ const qreal maxWidth = size().width() - x - option.margin;
+ foreach (const QByteArray& role, m_sortedVisibleRoles) {
+ const TextId textId = roleTextId(role);
+
+ const QString text = roleText(textId, values[role]);
+ m_text[textId].setText(text);
+
+ qreal requiredWidth = option.fontMetrics.width(text);
+ if (requiredWidth > maxWidth) {
+ requiredWidth = maxWidth;
+ const QString elidedText = option.fontMetrics.elidedText(text, Qt::ElideRight, maxWidth);
+ m_text[textId].setText(elidedText);
+ }
+
+ m_textPos[textId] = QPointF(x, y);
+ m_text[textId].setTextWidth(maxWidth);
+
+ maximumRequiredTextWidth = qMax(maximumRequiredTextWidth, requiredWidth);
+
+ y += fontHeight;
+ }
+
+ m_textsBoundingRect = QRectF(x - option.margin, 0, maximumRequiredTextWidth + 2 * option.margin, widgetHeight);
+}
+
+void KFileItemListWidget::updateDetailsLayoutTextCache()
+{
+ // Precondition: Requires already updated m_expansionArea
+ // to determine the left position.
+
+ // +------+
+ // | Icon | Name role Additional role 1 Additional role 2
+ // +------+
+ m_textsBoundingRect = QRectF();
+
+ const KItemListStyleOption& option = styleOption();
+ const QHash<QByteArray, QVariant> values = data();
+
+ const qreal widgetHeight = size().height();
+ const int scaledIconSize = widgetHeight - 2 * option.margin;
+ const int fontHeight = option.fontMetrics.height();
+
+ qreal x = m_expansionArea.right() + option.margin * 3 + scaledIconSize;
+ const qreal y = qMax(qreal(option.margin), (widgetHeight - fontHeight) / 2);
+
+ foreach (const QByteArray& role, m_sortedVisibleRoles) {
+ const TextId textId = roleTextId(role);
+
+ const QString text = roleText(textId, values[role]);
+ m_text[textId].setText(text);
+
+ const qreal requiredWidth = option.fontMetrics.width(text);
+ m_textPos[textId] = QPointF(x, y);
+
+ const qreal columnWidth = visibleRolesSizes().value(role, QSizeF(0, 0)).width();
+ x += columnWidth;
+
+ switch (textId) {
+ case Name: {
+ m_textsBoundingRect = QRectF(m_textPos[textId].x() - option.margin, 0,
+ requiredWidth + 2 * option.margin, size().height());
+
+ // The column after the name should always be aligned on the same x-position independent
+ // from the expansion-level shown in the name column
+ x -= m_expansionArea.right();
+ break;
+ }
+ case Size:
+ // The values for the size should be right aligned
+ m_textPos[textId].rx() += columnWidth - requiredWidth - 2 * option.margin;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+QString KFileItemListWidget::roleText(TextId textId, const QVariant& roleValue) const
+{
+ QString text;
+
+ switch (textId) {
+ case Name:
+ case Permissions:
+ case Owner:
+ case Group:
+ case Type:
+ case Destination:
+ case Path:
+ text = roleValue.toString();
+ break;
+
+ case Size: {
+ if (data().value("isDir").toBool()) {
+ // The item represents a directory. Show the number of sub directories
+ // instead of the file size of the directory.
+ if (!roleValue.isNull()) {
+ const KIO::filesize_t size = roleValue.value<KIO::filesize_t>();
+ text = i18ncp("@item:intable", "%1 item", "%1 items", size);
+ }
+ } else {
+ const KIO::filesize_t size = roleValue.value<KIO::filesize_t>();
+ text = KIO::convertSize(size);
+ }
+ break;
+ }
+
+ case Date: {
+ const QDateTime dateTime = roleValue.toDateTime();
+ text = KGlobal::locale()->formatDateTime(dateTime);
+ break;
+ }
+
+ default:
+ Q_ASSERT(false);
+ break;
+ }
+
+ return text;
+}
+
+void KFileItemListWidget::drawPixmap(QPainter* painter, const QPixmap& pixmap)
+{
+ const bool isHiddenItem = m_text[Name].text().startsWith(QLatin1Char('.'));
+ qreal opacity;
+ if (isHiddenItem) {
+ opacity = painter->opacity();
+ painter->setOpacity(opacity * 0.3);
+ }
+
+ if (m_scaledPixmapSize != pixmap.size()) {
+ QPixmap scaledPixmap = pixmap;
+ KPixmapModifier::scale(scaledPixmap, m_scaledPixmapSize);
+ painter->drawPixmap(m_pixmapPos, scaledPixmap);
+
+#ifdef KFILEITEMLISTWIDGET_DEBUG
+ painter->setPen(Qt::green);
+ painter->drawRect(QRectF(m_pixmapPos, QSizeF(scaledPixmap.size())));
+#endif
+ } else {
+ painter->drawPixmap(m_pixmapPos, pixmap);
+ }
+
+ if (isHiddenItem) {
+ painter->setOpacity(opacity);
+ }
+}
+
+QPixmap KFileItemListWidget::pixmapForIcon(const QString& name, int size)
+{
+ const KIcon icon(name);
+
+ int requestedSize;
+ if (size <= KIconLoader::SizeSmall) {
+ requestedSize = KIconLoader::SizeSmall;
+ } else if (size <= KIconLoader::SizeSmallMedium) {
+ requestedSize = KIconLoader::SizeSmallMedium;
+ } else if (size <= KIconLoader::SizeMedium) {
+ requestedSize = KIconLoader::SizeMedium;
+ } else if (size <= KIconLoader::SizeLarge) {
+ requestedSize = KIconLoader::SizeLarge;
+ } else if (size <= KIconLoader::SizeHuge) {
+ requestedSize = KIconLoader::SizeHuge;
+ } else if (size <= KIconLoader::SizeEnormous) {
+ requestedSize = KIconLoader::SizeEnormous;
+ } else if (size <= KIconLoader::SizeEnormous * 2) {
+ requestedSize = KIconLoader::SizeEnormous * 2;
+ } else {
+ requestedSize = size;
+ }
+
+ QPixmap pixmap = icon.pixmap(requestedSize, requestedSize);
+ if (requestedSize != size) {
+ KPixmapModifier::scale(pixmap, QSize(size, size));
+ }
+
+ return pixmap;
+}
+
+KFileItemListWidget::TextId KFileItemListWidget::roleTextId(const QByteArray& role)
+{
+ static QHash<QByteArray, TextId> rolesHash;
+ if (rolesHash.isEmpty()) {
+ rolesHash.insert("name", Name);
+ rolesHash.insert("size", Size);
+ rolesHash.insert("date", Date);
+ rolesHash.insert("permissions", Permissions);
+ rolesHash.insert("owner", Owner);
+ rolesHash.insert("group", Group);
+ rolesHash.insert("type", Type);
+ rolesHash.insert("destination", Destination);
+ rolesHash.insert("path", Path);
+ }
+
+ return rolesHash.value(role);
+}
+
+#include "kfileitemlistwidget.moc"
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 KFILEITEMLISTWIDGET_H
+#define KFILEITEMLISTWIDGET_H
+
+#include <libdolphin_export.h>
+
+#include <kitemviews/kitemlistwidget.h>
+
+#include <QPixmap>
+#include <QPointF>
+#include <QStaticText>
+
+class LIBDOLPHINPRIVATE_EXPORT KFileItemListWidget : public KItemListWidget
+{
+ Q_OBJECT
+
+public:
+ enum Layout
+ {
+ IconsLayout,
+ CompactLayout,
+ DetailsLayout
+ };
+
+ KFileItemListWidget(QGraphicsItem* parent);
+ virtual ~KFileItemListWidget();
+
+ void setLayout(Layout layout);
+ Layout layout() const;
+
+ virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0);
+
+ virtual bool contains(const QPointF& point) const;
+ virtual QRectF hoverBoundingRect() const;
+ virtual QRectF expansionToggleRect() const;
+
+protected:
+ virtual void dataChanged(const QHash<QByteArray, QVariant>& current, const QSet<QByteArray>& roles = QSet<QByteArray>());
+ virtual void visibleRolesChanged(const QHash<QByteArray, int>& current, const QHash<QByteArray, int>& previous);
+ virtual void visibleRolesSizesChanged(const QHash<QByteArray, QSizeF>& current, const QHash<QByteArray, QSizeF>& previous);
+ virtual void styleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous);
+ virtual void resizeEvent(QGraphicsSceneResizeEvent* event);
+
+private:
+ enum TextId {
+ Name,
+ Size,
+ Date,
+ Permissions,
+ Owner,
+ Group,
+ Type,
+ Destination,
+ Path,
+ TextIdCount // Mandatory last entry
+ };
+
+ void updateCache();
+ void updateExpansionArea();
+ void updatePixmapCache();
+
+ void updateTextsCache();
+ void updateIconsLayoutTextCache();
+ void updateCompactLayoutTextCache();
+ void updateDetailsLayoutTextCache();
+
+ QString roleText(TextId textId, const QVariant& roleValue) const;
+
+ void drawPixmap(QPainter* painter, const QPixmap& pixmap);
+
+ static QPixmap pixmapForIcon(const QString& name, int size);
+ static TextId roleTextId(const QByteArray& role);
+
+private:
+ bool m_isDir;
+ bool m_dirtyLayout;
+ bool m_dirtyContent;
+ QSet<QByteArray> m_dirtyContentRoles;
+
+ Layout m_layout;
+ QPointF m_pixmapPos;
+ QPixmap m_pixmap;
+ QSize m_scaledPixmapSize;
+
+ QRectF m_hoverPixmapRect;
+ QPixmap m_hoverPixmap;
+
+ QPointF m_textPos[TextIdCount];
+ QStaticText m_text[TextIdCount];
+ QRectF m_textsBoundingRect;
+
+ QList<QByteArray> m_sortedVisibleRoles;
+
+ QRectF m_expansionArea;
+ QColor m_additionalInfoTextColor;
+};
+
+#endif
+
+
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 "kfileitemmodel.h"
+
+#include <KDirLister>
+#include <KLocale>
+#include <KStringHandler>
+#include <KDebug>
+
+#include <QTimer>
+
+#define KFILEITEMMODEL_DEBUG
+
+KFileItemModel::KFileItemModel(KDirLister* dirLister, QObject* parent) :
+ KItemModelBase(QByteArray(), "name", parent),
+ m_dirLister(dirLister),
+ m_naturalSorting(true),
+ m_sortFoldersFirst(true),
+ m_groupRole(NoRole),
+ m_sortRole(NameRole),
+ m_caseSensitivity(Qt::CaseInsensitive),
+ m_sortedItems(),
+ m_items(),
+ m_data(),
+ m_requestRole(),
+ m_minimumUpdateIntervalTimer(0),
+ m_maximumUpdateIntervalTimer(0),
+ m_pendingItemsToInsert(),
+ m_pendingItemsToDelete(),
+ m_rootExpansionLevel(-1)
+{
+ resetRoles();
+ m_requestRole[NameRole] = true;
+ m_requestRole[IsDirRole] = true;
+
+ Q_ASSERT(dirLister);
+
+ connect(dirLister, SIGNAL(canceled()), this, SLOT(slotCanceled()));
+ connect(dirLister, SIGNAL(completed()), this, SLOT(slotCompleted()));
+ connect(dirLister, SIGNAL(newItems(KFileItemList)), this, SLOT(slotNewItems(KFileItemList)));
+ connect(dirLister, SIGNAL(itemsDeleted(KFileItemList)), this, SLOT(slotItemsDeleted(KFileItemList)));
+ connect(dirLister, SIGNAL(clear()), this, SLOT(slotClear()));
+ connect(dirLister, SIGNAL(clear(KUrl)), this, SLOT(slotClear(KUrl)));
+
+ // Although the layout engine of KItemListView is fast it is very inefficient to e.g.
+ // emit 50 itemsInserted()-signals each 100 ms. m_minimumUpdateIntervalTimer assures that updates
+ // are done in 1 second intervals for equal operations.
+ m_minimumUpdateIntervalTimer = new QTimer(this);
+ m_minimumUpdateIntervalTimer->setInterval(1000);
+ m_minimumUpdateIntervalTimer->setSingleShot(true);
+ connect(m_minimumUpdateIntervalTimer, SIGNAL(timeout()), this, SLOT(dispatchPendingItems()));
+
+ // 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);
+ m_maximumUpdateIntervalTimer->setInterval(2000);
+ m_maximumUpdateIntervalTimer->setSingleShot(true);
+ connect(m_maximumUpdateIntervalTimer, SIGNAL(timeout()), this, SLOT(dispatchPendingItems()));
+
+ Q_ASSERT(m_minimumUpdateIntervalTimer->interval() <= m_maximumUpdateIntervalTimer->interval());
+}
+
+KFileItemModel::~KFileItemModel()
+{
+}
+
+int KFileItemModel::count() const
+{
+ return m_data.count();
+}
+
+QHash<QByteArray, QVariant> KFileItemModel::data(int index) const
+{
+ if (index >= 0 && index < count()) {
+ return m_data.at(index);
+ }
+ return QHash<QByteArray, QVariant>();
+}
+
+bool KFileItemModel::setData(int index, const QHash<QByteArray, QVariant>& values)
+{
+ if (index >= 0 && index < count()) {
+ QHash<QByteArray, QVariant> currentValue = m_data.at(index);
+
+ QSet<QByteArray> changedRoles;
+ QHashIterator<QByteArray, QVariant> it(values);
+ while (it.hasNext()) {
+ it.next();
+ const QByteArray role = it.key();
+ const QVariant value = it.value();
+
+ if (currentValue[role] != value) {
+ currentValue[role] = value;
+ changedRoles.insert(role);
+ }
+ }
+
+ if (!changedRoles.isEmpty()) {
+ m_data[index] = currentValue;
+ emit itemsChanged(KItemRangeList() << KItemRange(index, 1), changedRoles);
+ }
+
+ return true;
+ }
+ return false;
+}
+
+bool KFileItemModel::supportsGrouping() const
+{
+ return true;
+}
+
+bool KFileItemModel::supportsSorting() const
+{
+ return true;
+}
+
+KFileItem KFileItemModel::fileItem(int index) const
+{
+ if (index >= 0 && index < count()) {
+ return m_sortedItems.at(index);
+ }
+
+ return KFileItem();
+}
+
+int KFileItemModel::index(const KFileItem& item) const
+{
+ if (item.isNull()) {
+ return -1;
+ }
+
+ return m_items.value(item, -1);
+}
+
+void KFileItemModel::clear()
+{
+ slotClear();
+}
+
+void KFileItemModel::setRoles(const QSet<QByteArray>& roles)
+{
+ if (count() > 0) {
+ const bool supportedExpanding = m_requestRole[IsExpandedRole] && m_requestRole[ExpansionLevelRole];
+ const bool willSupportExpanding = roles.contains("isExpanded") && roles.contains("expansionLevel");
+ if (supportedExpanding && !willSupportExpanding) {
+ // No expanding is supported anymore. Take care to delete all items that have an expansion level
+ // that is not 0 (and hence are part of an expanded item).
+ removeExpandedItems();
+ }
+ }
+
+ resetRoles();
+ QSetIterator<QByteArray> it(roles);
+ while (it.hasNext()) {
+ const QByteArray& role = it.next();
+ m_requestRole[roleIndex(role)] = true;
+ }
+
+ if (count() > 0) {
+ // Update m_data with the changed requested roles
+ const int maxIndex = count() - 1;
+ for (int i = 0; i <= maxIndex; ++i) {
+ m_data[i] = retrieveData(m_sortedItems.at(i));
+ }
+
+ kWarning() << "TODO: Emitting itemsChanged() with no information what has changed!";
+ emit itemsChanged(KItemRangeList() << KItemRange(0, count()), QSet<QByteArray>());
+ }
+}
+
+QSet<QByteArray> KFileItemModel::roles() const
+{
+ QSet<QByteArray> roles;
+ for (int i = 0; i < RolesCount; ++i) {
+ if (m_requestRole[i]) {
+ switch (i) {
+ case NoRole: break;
+ case NameRole: roles.insert("name"); break;
+ case SizeRole: roles.insert("size"); break;
+ case DateRole: roles.insert("date"); break;
+ case PermissionsRole: roles.insert("permissions"); break;
+ case OwnerRole: roles.insert("owner"); break;
+ case GroupRole: roles.insert("group"); break;
+ case TypeRole: roles.insert("type"); break;
+ case DestinationRole: roles.insert("destination"); break;
+ case PathRole: roles.insert("path"); break;
+ case IsDirRole: roles.insert("isDir"); break;
+ case IsExpandedRole: roles.insert("isExpanded"); break;
+ case ExpansionLevelRole: roles.insert("expansionLevel"); break;
+ default: Q_ASSERT(false); break;
+ }
+ }
+ }
+ return roles;
+}
+
+bool KFileItemModel::setExpanded(int index, bool expanded)
+{
+ if (isExpanded(index) == expanded || index < 0 || index >= count()) {
+ return false;
+ }
+
+ QHash<QByteArray, QVariant> values;
+ values.insert("isExpanded", expanded);
+ if (!setData(index, values)) {
+ return false;
+ }
+
+ if (expanded) {
+ const KUrl url = m_sortedItems.at(index).url();
+ KDirLister* dirLister = m_dirLister.data();
+ if (dirLister) {
+ dirLister->openUrl(url, KDirLister::Keep);
+ return true;
+ }
+ } else {
+ KFileItemList itemsToRemove;
+ const int expansionLevel = data(index)["expansionLevel"].toInt();
+ ++index;
+ while (index < count() && data(index)["expansionLevel"].toInt() > expansionLevel) {
+ itemsToRemove.append(m_sortedItems.at(index));
+ ++index;
+ }
+ removeItems(itemsToRemove);
+ return true;
+ }
+
+ return false;
+}
+
+bool KFileItemModel::isExpanded(int index) const
+{
+ if (index >= 0 && index < count()) {
+ return m_data.at(index).value("isExpanded").toBool();
+ }
+ return false;
+}
+
+bool KFileItemModel::isExpandable(int index) const
+{
+ if (index >= 0 && index < count()) {
+ return m_sortedItems.at(index).isDir();
+ }
+ return false;
+}
+
+void KFileItemModel::onGroupRoleChanged(const QByteArray& current, const QByteArray& previous)
+{
+ Q_UNUSED(previous);
+ m_groupRole = roleIndex(current);
+}
+
+void KFileItemModel::onSortRoleChanged(const QByteArray& current, const QByteArray& previous)
+{
+ Q_UNUSED(previous);
+ const int itemCount = count();
+ if (itemCount <= 0) {
+ return;
+ }
+
+ m_sortRole = roleIndex(current);
+
+ KFileItemList sortedItems = m_sortedItems;
+ m_sortedItems.clear();
+ m_items.clear();
+ m_data.clear();
+ emit itemsRemoved(KItemRangeList() << KItemRange(0, itemCount));
+
+ sort(sortedItems.begin(), sortedItems.end());
+ int index = 0;
+ foreach (const KFileItem& item, sortedItems) {
+ m_sortedItems.append(item);
+ m_items.insert(item, index);
+ m_data.append(retrieveData(item));
+
+ ++index;
+ }
+
+ emit itemsInserted(KItemRangeList() << KItemRange(0, itemCount));
+}
+
+void KFileItemModel::slotCompleted()
+{
+ if (m_minimumUpdateIntervalTimer->isActive()) {
+ // dispatchPendingItems() will be called when the timer
+ // has been expired.
+ return;
+ }
+
+ dispatchPendingItems();
+ m_minimumUpdateIntervalTimer->start();
+}
+
+void KFileItemModel::slotCanceled()
+{
+ m_minimumUpdateIntervalTimer->stop();
+ m_maximumUpdateIntervalTimer->stop();
+ dispatchPendingItems();
+}
+
+void KFileItemModel::slotNewItems(const KFileItemList& items)
+{
+ if (!m_pendingItemsToDelete.isEmpty()) {
+ removeItems(m_pendingItemsToDelete);
+ m_pendingItemsToDelete.clear();
+ }
+ m_pendingItemsToInsert.append(items);
+
+ if (useMaximumUpdateInterval() && !m_maximumUpdateIntervalTimer->isActive()) {
+ // Assure that items get dispatched if no completed() or canceled() signal is
+ // emitted during the maximum update interval.
+ m_maximumUpdateIntervalTimer->start();
+ }
+}
+
+void KFileItemModel::slotItemsDeleted(const KFileItemList& items)
+{
+ if (!m_pendingItemsToInsert.isEmpty()) {
+ insertItems(m_pendingItemsToInsert);
+ m_pendingItemsToInsert.clear();
+ }
+ m_pendingItemsToDelete.append(items);
+}
+
+void KFileItemModel::slotClear()
+{
+#ifdef KFILEITEMMODEL_DEBUG
+ kDebug() << "Clearing all items";
+#endif
+
+ m_minimumUpdateIntervalTimer->stop();
+ m_maximumUpdateIntervalTimer->stop();
+ m_pendingItemsToInsert.clear();
+ m_pendingItemsToDelete.clear();
+
+ m_rootExpansionLevel = -1;
+
+ const int removedCount = m_data.count();
+ if (removedCount > 0) {
+ m_sortedItems.clear();
+ m_items.clear();
+ m_data.clear();
+ emit itemsRemoved(KItemRangeList() << KItemRange(0, removedCount));
+ }
+}
+
+void KFileItemModel::slotClear(const KUrl& url)
+{
+ Q_UNUSED(url);
+}
+
+void KFileItemModel::dispatchPendingItems()
+{
+ if (!m_pendingItemsToInsert.isEmpty()) {
+ Q_ASSERT(m_pendingItemsToDelete.isEmpty());
+ insertItems(m_pendingItemsToInsert);
+ m_pendingItemsToInsert.clear();
+ } else if (!m_pendingItemsToDelete.isEmpty()) {
+ Q_ASSERT(m_pendingItemsToInsert.isEmpty());
+ removeItems(m_pendingItemsToDelete);
+ m_pendingItemsToDelete.clear();
+ }
+}
+
+void KFileItemModel::insertItems(const KFileItemList& items)
+{
+ if (items.isEmpty()) {
+ return;
+ }
+
+#ifdef KFILEITEMMODEL_DEBUG
+ QElapsedTimer timer;
+ timer.start();
+ kDebug() << "===========================================================";
+ kDebug() << "Inserting" << items.count() << "items";
+#endif
+
+ KFileItemList sortedItems = items;
+ sort(sortedItems.begin(), sortedItems.end());
+
+#ifdef KFILEITEMMODEL_DEBUG
+ kDebug() << "[TIME] Sorting:" << timer.elapsed();
+#endif
+
+ KItemRangeList itemRanges;
+ int targetIndex = 0;
+ int sourceIndex = 0;
+ int insertedAtIndex = -1;
+ int insertedCount = 0;
+ while (sourceIndex < sortedItems.count()) {
+ // Find target index from m_items to insert the current item
+ // in a sorted order
+ const int previousTargetIndex = targetIndex;
+ while (targetIndex < m_sortedItems.count()) {
+ if (!lessThan(m_sortedItems.at(targetIndex), sortedItems.at(sourceIndex))) {
+ break;
+ }
+ ++targetIndex;
+ }
+
+ if (targetIndex - previousTargetIndex > 0 && insertedAtIndex >= 0) {
+ itemRanges << KItemRange(insertedAtIndex, insertedCount);
+ insertedAtIndex = targetIndex;
+ insertedCount = 0;
+ }
+
+ // Insert item at the position targetIndex
+ const KFileItem item = sortedItems.at(sourceIndex);
+ m_sortedItems.insert(targetIndex, item);
+ m_data.insert(targetIndex, retrieveData(item));
+ // m_items will be inserted after the loop (see comment below)
+ ++insertedCount;
+
+ if (insertedAtIndex < 0) {
+ insertedAtIndex = targetIndex;
+ }
+ ++targetIndex;
+ ++sourceIndex;
+ }
+
+ // The indexes of all m_items must be adjusted, not only the index
+ // of the new items
+ for (int i = 0; i < m_sortedItems.count(); ++i) {
+ m_items.insert(m_sortedItems.at(i), i);
+ }
+
+ itemRanges << KItemRange(insertedAtIndex, insertedCount);
+ emit itemsInserted(itemRanges);
+
+#ifdef KFILEITEMMODEL_DEBUG
+ kDebug() << "[TIME] Inserting of" << items.count() << "items:" << timer.elapsed();
+#endif
+}
+
+void KFileItemModel::removeItems(const KFileItemList& items)
+{
+ if (items.isEmpty()) {
+ return;
+ }
+
+#ifdef KFILEITEMMODEL_DEBUG
+ kDebug() << "Removing " << items.count() << "items";
+#endif
+
+ KFileItemList sortedItems = items;
+ sort(sortedItems.begin(), sortedItems.end());
+
+ QList<int> indexesToRemove;
+ indexesToRemove.reserve(items.count());
+
+ // Calculate the item ranges that will get deleted
+ KItemRangeList itemRanges;
+ int removedAtIndex = -1;
+ int removedCount = 0;
+ int targetIndex = 0;
+ foreach (const KFileItem& itemToRemove, sortedItems) {
+ const int previousTargetIndex = targetIndex;
+ while (targetIndex < m_sortedItems.count()) {
+ if (m_sortedItems.at(targetIndex) == itemToRemove) {
+ break;
+ }
+ ++targetIndex;
+ }
+ if (targetIndex >= m_sortedItems.count()) {
+ kWarning() << "Item that should be deleted has not been found!";
+ return;
+ }
+
+ if (targetIndex - previousTargetIndex > 0 && removedAtIndex >= 0) {
+ itemRanges << KItemRange(removedAtIndex, removedCount);
+ removedAtIndex = targetIndex;
+ removedCount = 0;
+ }
+
+ indexesToRemove.append(targetIndex);
+ if (removedAtIndex < 0) {
+ removedAtIndex = targetIndex;
+ }
+ ++removedCount;
+ ++targetIndex;
+ }
+
+ // Delete the items
+ for (int i = indexesToRemove.count() - 1; i >= 0; --i) {
+ const int indexToRemove = indexesToRemove.at(i);
+ m_items.remove(m_sortedItems.at(indexToRemove));
+ m_sortedItems.removeAt(indexToRemove);
+ m_data.removeAt(indexToRemove);
+ }
+
+ // The indexes of all m_items must be adjusted, not only the index
+ // of the removed items
+ for (int i = 0; i < m_sortedItems.count(); ++i) {
+ m_items.insert(m_sortedItems.at(i), i);
+ }
+
+ if (count() <= 0) {
+ m_rootExpansionLevel = -1;
+ }
+
+ itemRanges << KItemRange(removedAtIndex, removedCount);
+ emit itemsRemoved(itemRanges);
+}
+
+void KFileItemModel::removeExpandedItems()
+{
+
+ KFileItemList expandedItems;
+
+ const int maxIndex = m_data.count() - 1;
+ for (int i = 0; i <= maxIndex; ++i) {
+ if (m_data.at(i).value("expansionLevel").toInt() > 0) {
+ const KFileItem fileItem = m_sortedItems.at(i);
+ expandedItems.append(fileItem);
+ }
+ }
+
+ // The m_rootExpansionLevel may not get reset before all items with
+ // a bigger expansionLevel have been removed.
+ Q_ASSERT(m_rootExpansionLevel >= 0);
+ removeItems(expandedItems);
+
+ m_rootExpansionLevel = -1;
+}
+
+void KFileItemModel::resetRoles()
+{
+ for (int i = 0; i < RolesCount; ++i) {
+ m_requestRole[i] = false;
+ }
+}
+
+KFileItemModel::Role KFileItemModel::roleIndex(const QByteArray& role) const
+{
+ static QHash<QByteArray, Role> rolesHash;
+ if (rolesHash.isEmpty()) {
+ rolesHash.insert("name", NameRole);
+ rolesHash.insert("size", SizeRole);
+ rolesHash.insert("date", DateRole);
+ rolesHash.insert("permissions", PermissionsRole);
+ rolesHash.insert("owner", OwnerRole);
+ rolesHash.insert("group", GroupRole);
+ rolesHash.insert("type", TypeRole);
+ rolesHash.insert("destination", DestinationRole);
+ rolesHash.insert("path", PathRole);
+ rolesHash.insert("isDir", IsDirRole);
+ rolesHash.insert("isExpanded", IsExpandedRole);
+ rolesHash.insert("expansionLevel", ExpansionLevelRole);
+ }
+ return rolesHash.value(role, NoRole);
+}
+
+QHash<QByteArray, QVariant> KFileItemModel::retrieveData(const KFileItem& item) const
+{
+ // It is important to insert only roles that are fast to retrieve. E.g.
+ // KFileItem::iconName() can be very expensive if the MIME-type is unknown
+ // and hence will be retrieved asynchronously by KFileItemModelRolesUpdater.
+ QHash<QByteArray, QVariant> data;
+ data.insert("iconPixmap", QPixmap());
+
+ const bool isDir = item.isDir();
+ if (m_requestRole[IsDirRole]) {
+ data.insert("isDir", isDir);
+ }
+
+ if (m_requestRole[NameRole]) {
+ data.insert("name", item.name());
+ }
+
+ if (m_requestRole[SizeRole]) {
+ if (isDir) {
+ data.insert("size", QVariant());
+ } else {
+ data.insert("size", item.size());
+ }
+ }
+
+ if (m_requestRole[DateRole]) {
+ // Don't use KFileItem::timeString() as this is too expensive when
+ // having several thousands of items. Instead the formatting of the
+ // date-time will be done on-demand by the view when the date will be shown.
+ const KDateTime dateTime = item.time(KFileItem::ModificationTime);
+ data.insert("date", dateTime.dateTime());
+ }
+
+ if (m_requestRole[PermissionsRole]) {
+ data.insert("permissions", item.permissionsString());
+ }
+
+ if (m_requestRole[OwnerRole]) {
+ data.insert("owner", item.user());
+ }
+
+ if (m_requestRole[GroupRole]) {
+ data.insert("group", item.group());
+ }
+
+ if (m_requestRole[DestinationRole]) {
+ QString destination = item.linkDest();
+ if (destination.isEmpty()) {
+ destination = i18nc("@item:intable", "No destination");
+ }
+ data.insert("destination", destination);
+ }
+
+ if (m_requestRole[PathRole]) {
+ data.insert("path", item.localPath());
+ }
+
+ if (m_requestRole[IsExpandedRole]) {
+ data.insert("isExpanded", false);
+ }
+
+ if (m_requestRole[ExpansionLevelRole]) {
+ if (m_rootExpansionLevel < 0) {
+ KDirLister* dirLister = m_dirLister.data();
+ if (dirLister) {
+ const QString rootDir = dirLister->url().directory(KUrl::AppendTrailingSlash);
+ m_rootExpansionLevel = rootDir.count('/');
+ }
+ }
+ const QString dir = item.url().directory(KUrl::AppendTrailingSlash);
+ const int level = dir.count('/') - m_rootExpansionLevel - 1;
+ data.insert("expansionLevel", level);
+ }
+
+ if (item.isMimeTypeKnown()) {
+ data.insert("iconName", item.iconName());
+
+ if (m_requestRole[TypeRole]) {
+ data.insert("type", item.mimeComment());
+ }
+ }
+
+ return data;
+}
+
+bool KFileItemModel::lessThan(const KFileItem& a, const KFileItem& b) const
+{
+ int result = 0;
+
+ if (m_rootExpansionLevel >= 0) {
+ result = expansionLevelsCompare(a, b);
+ if (result != 0) {
+ // The items have parents with different expansion levels
+ return result < 0;
+ }
+ }
+
+ if (m_sortFoldersFirst) {
+ const bool isDirA = a.isDir();
+ const bool isDirB = b.isDir();
+ if (isDirA && !isDirB) {
+ return true;
+ } else if (!isDirA && isDirB) {
+ return false;
+ }
+ }
+
+ switch (m_sortRole) {
+ case NameRole: {
+ result = stringCompare(a.text(), b.text());
+ if (result == 0) {
+ // KFileItem::text() may not be unique in case UDS_DISPLAY_NAME is used
+ result = stringCompare(a.name(m_caseSensitivity == Qt::CaseInsensitive),
+ b.name(m_caseSensitivity == Qt::CaseInsensitive));
+ }
+ break;
+ }
+
+ case DateRole: {
+ const KDateTime dateTimeA = a.time(KFileItem::ModificationTime);
+ const KDateTime dateTimeB = b.time(KFileItem::ModificationTime);
+ if (dateTimeA < dateTimeB) {
+ result = -1;
+ } else if (dateTimeA > dateTimeB) {
+ result = +1;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ if (result == 0) {
+ // It must be assured that the sort order is always unique even if two values have been
+ // equal. In this case a comparison of the URL is done which is unique in all cases
+ // within KDirLister.
+ result = QString::compare(a.url().url(), b.url().url(), Qt::CaseSensitive);
+ }
+
+ return result < 0;
+}
+
+void KFileItemModel::sort(const KFileItemList::iterator& startIterator, const KFileItemList::iterator& endIterator)
+{
+ KFileItemList::iterator start = startIterator;
+ KFileItemList::iterator end = endIterator;
+
+ // The implementation is based on qSortHelper() from qalgorithms.h
+ // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ // In opposite to qSort() it allows to use a member-function for the comparison of elements.
+ while (1) {
+ int span = int(end - start);
+ if (span < 2) {
+ return;
+ }
+
+ --end;
+ KFileItemList::iterator low = start, high = end - 1;
+ KFileItemList::iterator pivot = start + span / 2;
+
+ if (lessThan(*end, *start)) {
+ qSwap(*end, *start);
+ }
+ if (span == 2) {
+ return;
+ }
+
+ if (lessThan(*pivot, *start)) {
+ qSwap(*pivot, *start);
+ }
+ if (lessThan(*end, *pivot)) {
+ qSwap(*end, *pivot);
+ }
+ if (span == 3) {
+ return;
+ }
+
+ qSwap(*pivot, *end);
+
+ while (low < high) {
+ while (low < high && lessThan(*low, *end)) {
+ ++low;
+ }
+
+ while (high > low && lessThan(*end, *high)) {
+ --high;
+ }
+ if (low < high) {
+ qSwap(*low, *high);
+ ++low;
+ --high;
+ } else {
+ break;
+ }
+ }
+
+ if (lessThan(*low, *end)) {
+ ++low;
+ }
+
+ qSwap(*end, *low);
+ sort(start, low);
+
+ start = low + 1;
+ ++end;
+ }
+}
+
+int KFileItemModel::stringCompare(const QString& a, const QString& b) const
+{
+ // Taken from KDirSortFilterProxyModel (kdelibs/kfile/kdirsortfilterproxymodel.*)
+ // Copyright (C) 2006 by Peter Penz <peter.penz@gmx.at>
+ // Copyright (C) 2006 by Dominic Battre <dominic@battre.de>
+ // Copyright (C) 2006 by Martin Pool <mbp@canonical.com>
+
+ if (m_caseSensitivity == Qt::CaseInsensitive) {
+ const int result = m_naturalSorting ? KStringHandler::naturalCompare(a, b, Qt::CaseInsensitive)
+ : QString::compare(a, b, Qt::CaseInsensitive);
+ if (result != 0) {
+ // Only return the result, if the strings are not equal. If they are equal by a case insensitive
+ // comparison, still a deterministic sort order is required. A case sensitive
+ // comparison is done as fallback.
+ return result;
+ }
+ }
+
+ return m_naturalSorting ? KStringHandler::naturalCompare(a, b, Qt::CaseSensitive)
+ : QString::compare(a, b, Qt::CaseSensitive);
+}
+
+int KFileItemModel::expansionLevelsCompare(const KFileItem& a, const KFileItem& b) const
+{
+ const KUrl urlA = a.url();
+ const KUrl urlB = b.url();
+ if (urlA.directory() == urlB.directory()) {
+ // Both items have the same directory as parent
+ return 0;
+ }
+
+ // Check whether one item is the parent of the other item
+ if (urlA.isParentOf(urlB)) {
+ return -1;
+ } else if (urlB.isParentOf(urlA)) {
+ return +1;
+ }
+
+ // Determine the maximum common path of both items and
+ // remember the index in 'index'
+ const QString pathA = urlA.path();
+ const QString pathB = urlB.path();
+
+ const int maxIndex = qMin(pathA.length(), pathB.length()) - 1;
+ int index = 0;
+ while (index <= maxIndex && pathA.at(index) == pathB.at(index)) {
+ ++index;
+ }
+ if (index > maxIndex) {
+ index = maxIndex;
+ }
+ while (pathA.at(index) != QLatin1Char('/') && index > 0) {
+ --index;
+ }
+
+ // Determine the first sub-path after the common path and
+ // check whether it represents a directory or already a file
+ bool isDirA = true;
+ const QString subPathA = subPath(a, pathA, index, &isDirA);
+ bool isDirB = true;
+ const QString subPathB = subPath(b, pathB, index, &isDirB);
+
+ if (isDirA && !isDirB) {
+ return -1;
+ } else if (!isDirA && isDirB) {
+ return +1;
+ }
+
+ return stringCompare(subPathA, subPathB);
+}
+
+QString KFileItemModel::subPath(const KFileItem& item,
+ const QString& itemPath,
+ int start,
+ bool* isDir) const
+{
+ Q_ASSERT(isDir);
+ const int pathIndex = itemPath.indexOf('/', start + 1);
+ *isDir = (pathIndex > 0) || item.isDir();
+ return itemPath.mid(start, pathIndex - start);
+}
+
+bool KFileItemModel::useMaximumUpdateInterval() const
+{
+ const KDirLister* dirLister = m_dirLister.data();
+ return dirLister && !dirLister->url().isLocalFile();
+}
+
+#include "kfileitemmodel.moc"
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 KFILEITEMMODEL_H
+#define KFILEITEMMODEL_H
+
+#include <libdolphin_export.h>
+#include <KFileItemList>
+#include <KUrl>
+#include <kitemviews/kitemmodelbase.h>
+
+#include <QHash>
+
+class KDirLister;
+class QTimer;
+
+/**
+ * @brief KItemModelBase implementation for KFileItems.
+ *
+ * KFileItemModel is connected with one KDirLister. Each time the KDirLister
+ * emits new items, removes items or changes items the model gets synchronized.
+ *
+ * KFileItemModel supports sorting and grouping of items. Additional roles that
+ * are not part of KFileItem can be added with KFileItemModel::setData().
+ *
+ * Also the recursive expansion of sub-directories is supported by
+ * KFileItemModel::setExpanded().
+ */
+class LIBDOLPHINPRIVATE_EXPORT KFileItemModel : public KItemModelBase
+{
+ Q_OBJECT
+
+public:
+ explicit KFileItemModel(KDirLister* dirLister, QObject* parent = 0);
+ virtual ~KFileItemModel();
+
+ virtual int count() const;
+ virtual QHash<QByteArray, QVariant> data(int index) const;
+ virtual bool setData(int index, const QHash<QByteArray, QVariant> &values);
+
+ /**
+ * @return True
+ * @reimp
+ */
+ virtual bool supportsGrouping() const;
+
+ /**
+ * @return True
+ * @reimp
+ */
+ virtual bool supportsSorting() const;
+
+ /**
+ * @return The file-item for the index \a index. If the index is in a valid
+ * range it is assured that the file-item is not null. The runtime
+ * complexity of this call is O(1).
+ */
+ KFileItem fileItem(int index) const;
+
+ /**
+ * @return The index for the file-item \a item. -1 is returned if no file-item
+ * is found or if the file-item is null. The runtime
+ * complexity of this call is O(1).
+ */
+ int index(const KFileItem& item) const;
+
+ /**
+ * Clears all items of the model.
+ */
+ void clear();
+
+ // TODO: "name" + "isDir" is default in ctor
+ void setRoles(const QSet<QByteArray>& roles);
+ QSet<QByteArray> roles() const;
+
+ bool setExpanded(int index, bool expanded);
+ bool isExpanded(int index) const;
+ bool isExpandable(int index) const;
+
+protected:
+ virtual void onGroupRoleChanged(const QByteArray& current, const QByteArray& previous);
+ virtual void onSortRoleChanged(const QByteArray& current, const QByteArray& previous);
+
+private slots:
+ void slotCompleted();
+ void slotCanceled();
+ void slotNewItems(const KFileItemList& items);
+ void slotItemsDeleted(const KFileItemList& items);
+ void slotClear();
+ void slotClear(const KUrl& url);
+
+ void dispatchPendingItems();
+
+private:
+ void insertItems(const KFileItemList& items);
+ void removeItems(const KFileItemList& items);
+
+ void removeExpandedItems();
+
+ enum Role {
+ NoRole,
+ NameRole,
+ SizeRole,
+ DateRole,
+ PermissionsRole,
+ OwnerRole,
+ GroupRole,
+ TypeRole,
+ DestinationRole,
+ PathRole,
+ IsDirRole,
+ IsExpandedRole,
+ ExpansionLevelRole,
+ RolesCount // Mandatory last entry
+ };
+
+ void resetRoles();
+
+ Role roleIndex(const QByteArray& role) const;
+
+ QHash<QByteArray, QVariant> retrieveData(const KFileItem& item) const;
+
+ bool lessThan(const KFileItem& a, const KFileItem& b) const;
+ void sort(const KFileItemList::iterator& start, const KFileItemList::iterator& end);
+ int stringCompare(const QString& a, const QString& b) const;
+
+ /**
+ * Compares the expansion level of both items. The "expansion level" is defined
+ * by the number of parent directories. However simply comparing just the numbers
+ * is not sufficient, it is also important to check the hierarchy for having
+ * a correct order like shown in a tree.
+ */
+ int expansionLevelsCompare(const KFileItem& a, const KFileItem& b) const;
+
+ /**
+ * Helper method for expansionLevelCompare().
+ */
+ QString subPath(const KFileItem& item,
+ const QString& itemPath,
+ int start,
+ bool* isDir) const;
+
+ bool useMaximumUpdateInterval() const;
+
+private:
+ QWeakPointer<KDirLister> m_dirLister;
+
+ bool m_naturalSorting;
+ bool m_sortFoldersFirst;
+
+ Role m_groupRole;
+ Role m_sortRole;
+ Qt::CaseSensitivity m_caseSensitivity;
+
+ KFileItemList m_sortedItems; // Allows O(1) access for KFileItemModel::fileItem(int index)
+ QHash<KFileItem, int> m_items; // Allows O(1) access for KFileItemModel::index(const KFileItem& item)
+ QList<QHash<QByteArray, QVariant> > m_data;
+
+ bool m_requestRole[RolesCount];
+
+ QTimer* m_minimumUpdateIntervalTimer;
+ QTimer* m_maximumUpdateIntervalTimer;
+ KFileItemList m_pendingItemsToInsert;
+ KFileItemList m_pendingItemsToDelete;
+
+ // Stores the smallest expansion level of the root-URL. Is required to calculate
+ // the "expansionLevel" role in an efficient way. A value < 0 indicates that
+ // it has not been initialized yet.
+ mutable int m_rootExpansionLevel;
+
+ friend class KFileItemModelTest; // For unit testing
+};
+
+#endif
+
+
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 "kfileitemmodelrolesupdater.h"
+
+#include "kfileitemmodel.h"
+#include "kpixmapmodifier_p.h"
+
+#include <KConfig>
+#include <KConfigGroup>
+#include <KDebug>
+#include <KFileItem>
+#include <KGlobal>
+#include <KIO/PreviewJob>
+#include <QPainter>
+#include <QPixmap>
+#include <QElapsedTimer>
+#include <QTimer>
+
+// Required includes for subDirectoriesCount():
+#ifdef Q_WS_WIN
+ #include <QDir>
+#else
+ #include <dirent.h>
+ #include <QFile>
+#endif
+
+#define KFILEITEMMODELROLESUPDATER_DEBUG
+
+namespace {
+ const int MaxResolveItemsCount = 100;
+}
+
+KFileItemModelRolesUpdater::KFileItemModelRolesUpdater(KFileItemModel* model, QObject* parent) :
+ QObject(parent),
+ m_paused(false),
+ m_previewChangedDuringPausing(false),
+ m_iconSizeChangedDuringPausing(false),
+ m_rolesChangedDuringPausing(false),
+ m_previewShown(false),
+ m_clearPreviews(false),
+ m_model(model),
+ m_iconSize(),
+ m_firstVisibleIndex(0),
+ m_lastVisibleIndex(-1),
+ m_roles(),
+ m_enabledPlugins(),
+ m_pendingVisibleItems(),
+ m_pendingInvisibleItems(),
+ m_previewJobs(),
+ m_resolvePendingRolesTimer(0)
+{
+ Q_ASSERT(model);
+
+ const KConfigGroup globalConfig(KGlobal::config(), "PreviewSettings");
+ m_enabledPlugins = globalConfig.readEntry("Plugins", QStringList()
+ << "directorythumbnail"
+ << "imagethumbnail"
+ << "jpegthumbnail");
+
+ connect(m_model, SIGNAL(itemsInserted(KItemRangeList)),
+ this, SLOT(slotItemsInserted(KItemRangeList)));
+ connect(m_model, SIGNAL(itemsRemoved(KItemRangeList)),
+ this, SLOT(slotItemsRemoved(KItemRangeList)));
+ connect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet<QByteArray>)),
+ this, SLOT(slotItemsChanged(KItemRangeList,QSet<QByteArray>)));
+
+ // A timer with a minimal timeout is used to merge several triggerPendingRolesResolving() calls
+ // to only one call of resolvePendingRoles().
+ m_resolvePendingRolesTimer = new QTimer(this);
+ m_resolvePendingRolesTimer->setInterval(1);
+ m_resolvePendingRolesTimer->setSingleShot(true);
+ connect(m_resolvePendingRolesTimer, SIGNAL(timeout()), this, SLOT(resolvePendingRoles()));
+}
+
+KFileItemModelRolesUpdater::~KFileItemModelRolesUpdater()
+{
+}
+
+void KFileItemModelRolesUpdater::setIconSize(const QSize& size)
+{
+ if (size != m_iconSize) {
+ m_iconSize = size;
+ if (m_paused) {
+ m_iconSizeChangedDuringPausing = true;
+ } else if (m_previewShown) {
+ // An icon size change requires the regenerating of
+ // all previews
+ sortAndResolveAllRoles();
+ } else {
+ sortAndResolvePendingRoles();
+ }
+ }
+}
+
+QSize KFileItemModelRolesUpdater::iconSize() const
+{
+ return m_iconSize;
+}
+
+void KFileItemModelRolesUpdater::setVisibleIndexRange(int index, int count)
+{
+ if (index < 0) {
+ index = 0;
+ }
+ if (count < 0) {
+ count = 0;
+ }
+
+ if (index == m_firstVisibleIndex && count == m_lastVisibleIndex - m_firstVisibleIndex + 1) {
+ // The range has not been changed
+ return;
+ }
+
+ m_firstVisibleIndex = index;
+ m_lastVisibleIndex = qMin(index + count - 1, m_model->count() - 1);
+
+ if (hasPendingRoles() && !m_paused) {
+ sortAndResolvePendingRoles();
+ }
+}
+
+void KFileItemModelRolesUpdater::setPreviewShown(bool show)
+{
+ if (show == m_previewShown) {
+ return;
+ }
+
+ m_previewShown = show;
+ if (!show) {
+ m_clearPreviews = true;
+ }
+
+ if (m_paused) {
+ m_previewChangedDuringPausing = true;
+ } else {
+ sortAndResolveAllRoles();
+ }
+}
+
+bool KFileItemModelRolesUpdater::isPreviewShown() const
+{
+ return m_previewShown;
+}
+
+void KFileItemModelRolesUpdater::setEnabledPlugins(const QStringList& list)
+{
+ m_enabledPlugins = list;
+}
+
+void KFileItemModelRolesUpdater::setPaused(bool paused)
+{
+ if (paused == m_paused) {
+ return;
+ }
+
+ m_paused = paused;
+ if (paused) {
+ if (hasPendingRoles()) {
+ foreach (KJob* job, m_previewJobs) {
+ job->kill();
+ }
+ Q_ASSERT(m_previewJobs.isEmpty());
+ }
+ } else {
+ const bool resolveAll = (m_iconSizeChangedDuringPausing && m_previewShown) ||
+ (m_previewChangedDuringPausing && !m_previewShown) ||
+ m_rolesChangedDuringPausing;
+ if (resolveAll) {
+ sortAndResolveAllRoles();
+ } else {
+ sortAndResolvePendingRoles();
+ }
+
+ m_iconSizeChangedDuringPausing = false;
+ m_previewChangedDuringPausing = false;
+ m_rolesChangedDuringPausing = false;
+ }
+}
+
+void KFileItemModelRolesUpdater::setRoles(const QSet<QByteArray>& roles)
+{
+ if (roles.count() == m_roles.count()) {
+ bool isEqual = true;
+ foreach (const QByteArray& role, roles) {
+ if (!m_roles.contains(role)) {
+ isEqual = false;
+ break;
+ }
+ }
+ if (isEqual) {
+ return;
+ }
+ }
+
+ m_roles = roles;
+
+ if (m_paused) {
+ m_rolesChangedDuringPausing = true;
+ } else {
+ sortAndResolveAllRoles();
+ }
+}
+
+QSet<QByteArray> KFileItemModelRolesUpdater::roles() const
+{
+ return m_roles;
+}
+
+bool KFileItemModelRolesUpdater::isPaused() const
+{
+ return m_paused;
+}
+
+QStringList KFileItemModelRolesUpdater::enabledPlugins() const
+{
+ return m_enabledPlugins;
+}
+
+void KFileItemModelRolesUpdater::slotItemsInserted(const KItemRangeList& itemRanges)
+{
+ // If no valid index range is given assume that all items are visible.
+ // A cleanup will be done later as soon as the index range has been set.
+ const bool hasValidIndexRange = (m_lastVisibleIndex >= 0);
+
+ if (hasValidIndexRange) {
+ // Move all current pending visible items that are not visible anymore
+ // to the pending invisible items.
+ QSetIterator<KFileItem> it(m_pendingVisibleItems);
+ while (it.hasNext()) {
+ const KFileItem item = it.next();
+ const int index = m_model->index(item);
+ if (index < m_firstVisibleIndex || index > m_lastVisibleIndex) {
+ m_pendingVisibleItems.remove(item);
+ m_pendingInvisibleItems.insert(item);
+ }
+ }
+ }
+
+ int rangesCount = 0;
+
+ foreach (const KItemRange& range, itemRanges) {
+ rangesCount += range.count;
+
+ // Add the inserted items to the pending visible and invisible items
+ const int lastIndex = range.index + range.count - 1;
+ for (int i = range.index; i <= lastIndex; ++i) {
+ const KFileItem item = m_model->fileItem(i);
+ if (!hasValidIndexRange || (i >= m_firstVisibleIndex && i <= m_lastVisibleIndex)) {
+ m_pendingVisibleItems.insert(item);
+ } else {
+ m_pendingInvisibleItems.insert(item);
+ }
+ }
+ }
+
+ triggerPendingRolesResolving(rangesCount);
+}
+
+void KFileItemModelRolesUpdater::slotItemsRemoved(const KItemRangeList& itemRanges)
+{
+ Q_UNUSED(itemRanges);
+ m_firstVisibleIndex = 0;
+ m_lastVisibleIndex = -1;
+ if (hasPendingRoles() && m_model->count() <= 0) {
+ resetPendingRoles();
+ }
+}
+
+void KFileItemModelRolesUpdater::slotItemsChanged(const KItemRangeList& itemRanges,
+ const QSet<QByteArray>& roles)
+{
+ Q_UNUSED(itemRanges);
+ Q_UNUSED(roles);
+ // TODO
+}
+
+void KFileItemModelRolesUpdater::slotGotPreview(const KFileItem& item, const QPixmap& pixmap)
+{
+ m_pendingVisibleItems.remove(item);
+ m_pendingInvisibleItems.remove(item);
+
+ const int index = m_model->index(item);
+ if (index < 0) {
+ return;
+ }
+
+ QPixmap scaledPixmap = pixmap;
+
+ const QString mimeType = item.mimetype();
+ const int slashIndex = mimeType.indexOf(QLatin1Char('/'));
+ const QString mimeTypeGroup = mimeType.left(slashIndex);
+ if (mimeTypeGroup == QLatin1String("image")) {
+ KPixmapModifier::applyFrame(scaledPixmap, m_iconSize);
+ } else {
+ KPixmapModifier::scale(scaledPixmap, m_iconSize);
+ }
+
+ QHash<QByteArray, QVariant> data = rolesData(item);
+ data.insert("iconPixmap", scaledPixmap);
+
+ disconnect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet<QByteArray>)),
+ this, SLOT(slotItemsChanged(KItemRangeList,QSet<QByteArray>)));
+ m_model->setData(index, data);
+ connect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet<QByteArray>)),
+ this, SLOT(slotItemsChanged(KItemRangeList,QSet<QByteArray>)));
+}
+
+void KFileItemModelRolesUpdater::slotPreviewFailed(const KFileItem& item)
+{
+ m_pendingVisibleItems.remove(item);
+ m_pendingInvisibleItems.remove(item);
+
+ const bool clearPreviews = m_clearPreviews;
+ m_clearPreviews = true;
+ applyResolvedRoles(item, ResolveAll);
+ m_clearPreviews = clearPreviews;
+}
+
+void KFileItemModelRolesUpdater::slotPreviewJobFinished(KJob* job)
+{
+#ifdef KFILEITEMMODELROLESUPDATER_DEBUG
+ kDebug() << "Preview job finished. Pending visible:" << m_pendingVisibleItems.count() << "invisible:" << m_pendingInvisibleItems.count();
+#endif
+
+ m_previewJobs.removeOne(job);
+ if (!m_previewJobs.isEmpty() || !hasPendingRoles()) {
+ return;
+ }
+
+ const KFileItemList visibleItems = sortedItems(m_pendingVisibleItems);
+ const KFileItemList invisibleItems = itemSubSet(m_pendingInvisibleItems, MaxResolveItemsCount - visibleItems.count());
+ startPreviewJob(visibleItems + invisibleItems);
+}
+
+void KFileItemModelRolesUpdater::resolvePendingRoles()
+{
+ int resolvedCount = 0;
+
+ const bool hasSlowRoles = m_previewShown
+ || m_roles.contains("size")
+ || m_roles.contains("type");
+ const ResolveHint resolveHint = hasSlowRoles ? ResolveFast : ResolveAll;
+
+ // Resolving the MIME type can be expensive. Assure that not more than 200 ms are
+ // spend for resolving them synchronously. Usually this is more than enough to determine
+ // all visible items, but there are corner cases where this limit gets easily exceeded.
+ const int MaxTime = 200;
+ QElapsedTimer timer;
+ timer.start();
+
+ // Resolve the MIME type of all visible items
+ QSetIterator<KFileItem> visibleIt(m_pendingVisibleItems);
+ while (visibleIt.hasNext()) {
+ const KFileItem item = visibleIt.next();
+ applyResolvedRoles(item, resolveHint);
+ if (!hasSlowRoles) {
+ Q_ASSERT(!m_pendingInvisibleItems.contains(item));
+ // All roles have been resolved already by applyResolvedRoles()
+ m_pendingVisibleItems.remove(item);
+ }
+ ++resolvedCount;
+
+ if (timer.elapsed() > MaxTime) {
+ break;
+ }
+ }
+
+ // Resolve the MIME type of the invisible items at least until the timeout
+ // has been exceeded or the maximum number of items has been reached
+ KFileItemList invisibleItems;
+ if (m_lastVisibleIndex >= 0) {
+ // The visible range is valid, don't care about the order how the MIME
+ // type of invisible items get resolved
+ invisibleItems = m_pendingInvisibleItems.toList();
+ } else {
+ // The visible range is temporary invalid (e.g. happens when loading
+ // a directory) so take care to sort the currently invisible items where
+ // a part will get visible later
+ invisibleItems = sortedItems(m_pendingInvisibleItems);
+ }
+
+ int index = 0;
+ while (resolvedCount < MaxResolveItemsCount && index < invisibleItems.count() && timer.elapsed() <= MaxTime) {
+ const KFileItem item = invisibleItems.at(index);
+ applyResolvedRoles(item, resolveHint);
+
+ if (!hasSlowRoles) {
+ // All roles have been resolved already by applyResolvedRoles()
+ m_pendingInvisibleItems.remove(item);
+ }
+ ++index;
+ ++resolvedCount;
+ }
+
+ if (m_previewShown) {
+ KFileItemList items = sortedItems(m_pendingVisibleItems);
+ items += invisibleItems;
+ startPreviewJob(items);
+ } else {
+ QTimer::singleShot(0, this, SLOT(resolveNextPendingRoles()));
+ }
+
+#ifdef KFILEITEMMODELROLESUPDATER_DEBUG
+ if (timer.elapsed() > MaxTime) {
+ kDebug() << "Maximum time exceeded, skipping items... Remaining visible:" << m_pendingVisibleItems.count()
+ << "invisible:" << m_pendingInvisibleItems.count();
+ }
+ kDebug() << "[TIME] Resolved pending roles:" << timer.elapsed();
+#endif
+}
+
+void KFileItemModelRolesUpdater::resolveNextPendingRoles()
+{
+ if (m_paused) {
+ return;
+ }
+
+ if (m_previewShown) {
+ // The preview has been turned on since the last run. Skip
+ // resolving further pending roles as this is done as soon
+ // as a preview has been received.
+ return;
+ }
+
+ int resolvedCount = 0;
+ bool changed = false;
+ for (int i = 0; i <= 1; ++i) {
+ QSet<KFileItem>& pendingItems = (i == 0) ? m_pendingVisibleItems : m_pendingInvisibleItems;
+ QSetIterator<KFileItem> it(pendingItems);
+ while (it.hasNext() && !changed && resolvedCount < MaxResolveItemsCount) {
+ const KFileItem item = it.next();
+ pendingItems.remove(item);
+ changed = applyResolvedRoles(item, ResolveAll);
+ ++resolvedCount;
+ }
+ }
+
+ if (hasPendingRoles()) {
+ QTimer::singleShot(0, this, SLOT(resolveNextPendingRoles()));
+ } else {
+ m_clearPreviews = false;
+ }
+
+#ifdef KFILEITEMMODELROLESUPDATER_DEBUG
+ static int callCount = 0;
+ ++callCount;
+ if (callCount % 100 == 0) {
+ kDebug() << "Remaining visible roles to resolve:" << m_pendingVisibleItems.count()
+ << "invisible:" << m_pendingInvisibleItems.count();
+ }
+#endif
+}
+
+void KFileItemModelRolesUpdater::startPreviewJob(const KFileItemList& items)
+{
+ if (items.count() <= 0 || m_paused) {
+ return;
+ }
+
+ // PreviewJob internally caches items always with the size of
+ // 128 x 128 pixels or 256 x 256 pixels. A (slow) downscaling is done
+ // by PreviewJob if a smaller size is requested. For images KFileItemModelRolesUpdater must
+ // do a downscaling anyhow because of the frame, so in this case only the provided
+ // cache sizes are requested.
+ const QSize cacheSize = (m_iconSize.width() > 128) || (m_iconSize.height() > 128)
+ ? QSize(256, 256) : QSize(128, 128);
+
+ KJob* job;
+ if (items.count() <= MaxResolveItemsCount) {
+ job = KIO::filePreview(items, cacheSize, &m_enabledPlugins);
+ } else {
+ KFileItemList itemsSubSet;
+ for (int i = 0; i <= MaxResolveItemsCount; ++i) {
+ itemsSubSet.append(items.at(i));
+ }
+ job = KIO::filePreview(itemsSubSet, cacheSize, &m_enabledPlugins);
+ }
+
+ connect(job, SIGNAL(gotPreview(const KFileItem&, const QPixmap&)),
+ this, SLOT(slotGotPreview(const KFileItem&, const QPixmap&)));
+ connect(job, SIGNAL(failed(KFileItem)),
+ this, SLOT(slotPreviewFailed(KFileItem)));
+ connect(job, SIGNAL(finished(KJob*)),
+ this, SLOT(slotPreviewJobFinished(KJob*)));
+
+ m_previewJobs.append(job);
+}
+
+
+bool KFileItemModelRolesUpdater::hasPendingRoles() const
+{
+ return !m_pendingVisibleItems.isEmpty() || !m_pendingInvisibleItems.isEmpty();
+}
+
+void KFileItemModelRolesUpdater::resetPendingRoles()
+{
+ m_pendingVisibleItems.clear();
+ m_pendingInvisibleItems.clear();
+
+ foreach (KJob* job, m_previewJobs) {
+ job->kill();
+ }
+ Q_ASSERT(m_previewJobs.isEmpty());
+}
+
+void KFileItemModelRolesUpdater::triggerPendingRolesResolving(int count)
+{
+ Q_ASSERT(count <= m_model->count());
+ if (count == m_model->count()) {
+ // When initially loading a directory a synchronous resolving prevents a minor
+ // flickering when opening directories. This is also fine from a performance point
+ // of view as it is assured in resolvePendingRoles() to never block the event-loop
+ // for more than 200 ms.
+ resolvePendingRoles();
+ } else {
+ // Items have been added. This can be done in several small steps within one loop
+ // because of the sorting and hence may not trigger any expensive operation.
+ m_resolvePendingRolesTimer->start();
+ }
+}
+
+void KFileItemModelRolesUpdater::sortAndResolveAllRoles()
+{
+ if (m_paused) {
+ return;
+ }
+
+ resetPendingRoles();
+ Q_ASSERT(m_pendingVisibleItems.isEmpty());
+ Q_ASSERT(m_pendingInvisibleItems.isEmpty());
+
+ if (m_model->count() <= 0) {
+ return;
+ }
+
+ // Determine all visible items
+ Q_ASSERT(m_firstVisibleIndex >= 0);
+ for (int i = m_firstVisibleIndex; i <= m_lastVisibleIndex; ++i) {
+ const KFileItem item = m_model->fileItem(i);
+ if (!item.isNull()) {
+ m_pendingVisibleItems.insert(item);
+ }
+ }
+
+ // Determine all invisible items
+ for (int i = 0; i < m_firstVisibleIndex; ++i) {
+ const KFileItem item = m_model->fileItem(i);
+ if (!item.isNull()) {
+ m_pendingInvisibleItems.insert(item);
+ }
+ }
+ for (int i = m_lastVisibleIndex + 1; i < m_model->count(); ++i) {
+ const KFileItem item = m_model->fileItem(i);
+ if (!item.isNull()) {
+ m_pendingInvisibleItems.insert(item);
+ }
+ }
+
+ triggerPendingRolesResolving(m_pendingVisibleItems.count() +
+ m_pendingInvisibleItems.count());
+}
+
+void KFileItemModelRolesUpdater::sortAndResolvePendingRoles()
+{
+ Q_ASSERT(!m_paused);
+ if (m_model->count() <= 0) {
+ return;
+ }
+
+ // If no valid index range is given assume that all items are visible.
+ // A cleanup will be done later as soon as the index range has been set.
+ const bool hasValidIndexRange = (m_lastVisibleIndex >= 0);
+
+ // Trigger a preview generation of all pending items. Assure that the visible
+ // pending items get generated first.
+ QSet<KFileItem> pendingItems;
+ pendingItems += m_pendingVisibleItems;
+ pendingItems += m_pendingInvisibleItems;
+
+ resetPendingRoles();
+ Q_ASSERT(m_pendingVisibleItems.isEmpty());
+ Q_ASSERT(m_pendingInvisibleItems.isEmpty());
+
+ QSetIterator<KFileItem> it(pendingItems);
+ while (it.hasNext()) {
+ const KFileItem item = it.next();
+ if (item.isNull()) {
+ continue;
+ }
+
+ const int index = m_model->index(item);
+ if (!hasValidIndexRange || (index >= m_firstVisibleIndex && index <= m_lastVisibleIndex)) {
+ m_pendingVisibleItems.insert(item);
+ } else {
+ m_pendingInvisibleItems.insert(item);
+ }
+ }
+
+ triggerPendingRolesResolving(m_pendingVisibleItems.count() +
+ m_pendingInvisibleItems.count());
+}
+
+bool KFileItemModelRolesUpdater::applyResolvedRoles(const KFileItem& item, ResolveHint hint)
+{
+ const bool resolveAll = (hint == ResolveAll);
+
+ bool mimeTypeChanged = false;
+ if (!item.isMimeTypeKnown()) {
+ item.determineMimeType();
+ mimeTypeChanged = true;
+ }
+
+ if (mimeTypeChanged || resolveAll || m_clearPreviews) {
+ const int index = m_model->index(item);
+ if (index < 0) {
+ return false;
+ }
+
+ QHash<QByteArray, QVariant> data;
+ if (resolveAll) {
+ data = rolesData(item);
+ }
+
+ if (mimeTypeChanged || m_clearPreviews) {
+ data.insert("iconName", item.iconName());
+ }
+ if (m_clearPreviews) {
+ data.insert("iconPixmap", QString());
+ }
+
+ disconnect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet<QByteArray>)),
+ this, SLOT(slotItemsChanged(KItemRangeList,QSet<QByteArray>)));
+ m_model->setData(index, data);
+ connect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet<QByteArray>)),
+ this, SLOT(slotItemsChanged(KItemRangeList,QSet<QByteArray>)));
+ return true;
+ }
+
+ return false;
+}
+
+QHash<QByteArray, QVariant> KFileItemModelRolesUpdater::rolesData(const KFileItem& item) const
+{
+ QHash<QByteArray, QVariant> data;
+
+ if (m_roles.contains("size")) {
+ if (item.isDir() && item.isLocalFile()) {
+ const QString path = item.localPath();
+ const int count = subDirectoriesCount(path);
+ if (count >= 0) {
+ data.insert("size", KIO::filesize_t(count));
+ }
+ }
+ }
+
+ if (m_roles.contains("type")) {
+ data.insert("type", item.mimeComment());
+ }
+
+ return data;
+}
+
+KFileItemList KFileItemModelRolesUpdater::sortedItems(const QSet<KFileItem>& items) const
+{
+ KFileItemList itemList;
+ if (items.isEmpty()) {
+ return itemList;
+ }
+
+#ifdef KFILEITEMMODELROLESUPDATER_DEBUG
+ QElapsedTimer timer;
+ timer.start();
+#endif
+
+ QList<int> indexes;
+ indexes.reserve(items.count());
+
+ QSetIterator<KFileItem> it(items);
+ while (it.hasNext()) {
+ const KFileItem item = it.next();
+ const int index = m_model->index(item);
+ indexes.append(index);
+ }
+ qSort(indexes);
+
+ itemList.reserve(items.count());
+ foreach (int index, indexes) {
+ itemList.append(m_model->fileItem(index));
+ }
+
+#ifdef KFILEITEMMODELROLESUPDATER_DEBUG
+ kDebug() << "[TIME] Sorting of items:" << timer.elapsed();
+#endif
+ return itemList;
+}
+
+KFileItemList KFileItemModelRolesUpdater::itemSubSet(const QSet<KFileItem>& items, int count)
+{
+ KFileItemList itemList;
+
+ int index = 0;
+ QSetIterator<KFileItem> it(items);
+ while (it.hasNext() && index < count) {
+ const KFileItem item = it.next();
+ if (item.isNull()) {
+ continue;
+ }
+ itemList.append(item);
+ ++index;
+ }
+
+ return itemList;
+}
+
+int KFileItemModelRolesUpdater::subDirectoriesCount(const QString& path)
+{
+#ifdef Q_WS_WIN
+ QDir dir(path);
+ return dir.entryList(QDir::AllEntries|QDir::NoDotAndDotDot|QDir::System).count();
+#else
+ // Taken from kdelibs/kio/kio/kdirmodel.cpp
+ // Copyright (C) 2006 David Faure <faure@kde.org>
+
+ int count = -1;
+ DIR* dir = ::opendir(QFile::encodeName(path));
+ if (dir) {
+ count = 0;
+ struct dirent *dirEntry = 0;
+ while ((dirEntry = ::readdir(dir))) {
+ if (dirEntry->d_name[0] == '.') {
+ if (dirEntry->d_name[1] == '\0') {
+ // Skip "."
+ continue;
+ }
+ if (dirEntry->d_name[1] == '.' && dirEntry->d_name[2] == '\0') {
+ // Skip ".."
+ continue;
+ }
+ }
+ ++count;
+ }
+ ::closedir(dir);
+ }
+ return count;
+#endif
+}
+
+#include "kfileitemmodelrolesupdater.moc"
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 KFILEITEMMODELROLESUPDATER_H
+#define KFILEITEMMODELROLESUPDATER_H
+
+#include <libdolphin_export.h>
+
+#include <KFileItem>
+#include <kitemviews/kitemmodelbase.h>
+
+#include <QObject>
+#include <QSet>
+#include <QSize>
+#include <QStringList>
+
+class KFileItemModel;
+class KJob;
+class QPixmap;
+class QTimer;
+
+/**
+ * @brief Resolves expensive roles asynchronously and applies them to the KFileItemModel.
+ *
+ * KFileItemModel only resolves roles that are inexpensive like e.g. the file name or
+ * the permissions. Creating previews or determining the MIME-type can be quite expensive
+ * and KFileItemModelRolesUpdater takes care to update such roles asynchronously.
+ */
+class LIBDOLPHINPRIVATE_EXPORT KFileItemModelRolesUpdater : public QObject
+{
+ Q_OBJECT
+
+public:
+ KFileItemModelRolesUpdater(KFileItemModel* model, QObject* parent = 0);
+ virtual ~KFileItemModelRolesUpdater();
+
+ void setIconSize(const QSize& size);
+ QSize iconSize() const;
+
+ /**
+ * Sets the range of items that are visible currently. The roles
+ * of visible items are resolved first.
+ */
+ void setVisibleIndexRange(int index, int count);
+
+ /**
+ * If \a show is set to true, the "iconPixmap" role will be filled with a preview
+ * of the file. If \a show is false the MIME type icon will be used for the "iconPixmap"
+ * role.
+ */
+ void setPreviewShown(bool show);
+ bool isPreviewShown() const;
+
+ /**
+ * If \a paused is set to true the asynchronous resolving of roles will be paused.
+ * State changes during pauses like changing the icon size or the preview-shown
+ * will be remembered and handled after unpausing.
+ */
+ void setPaused(bool paused);
+ bool isPaused() const;
+
+ /**
+ * Sets the roles that should be resolved asynchronously.
+ */
+ void setRoles(const QSet<QByteArray>& roles);
+ QSet<QByteArray> roles() const;
+
+ /**
+ * Sets the list of enabled thumbnail plugins.
+ * Per default all plugins enabled in the KConfigGroup "PreviewSettings"
+ * are used.
+ *
+ * Note that this method doesn't cause already generated previews
+ * to be regenerated.
+ *
+ * For a list of available plugins, call KServiceTypeTrader::self()->query("ThumbCreator").
+ *
+ * @see enabledPlugins
+ */
+ void setEnabledPlugins(const QStringList& list);
+
+ /**
+ * Returns the list of enabled thumbnail plugins.
+ * @see setEnabledPlugins
+ */
+ QStringList enabledPlugins() const;
+
+private slots:
+ void slotItemsInserted(const KItemRangeList& itemRanges);
+ void slotItemsRemoved(const KItemRangeList& itemRanges);
+ void slotItemsChanged(const KItemRangeList& itemRanges,
+ const QSet<QByteArray>& roles);
+
+ void slotGotPreview(const KFileItem& item, const QPixmap& pixmap);
+ void slotPreviewFailed(const KFileItem& item);
+
+ /**
+ * Is invoked when the preview job has been finished and
+ * removes the job from the m_previewJobs list.
+ */
+ void slotPreviewJobFinished(KJob* job);
+
+ void resolvePendingRoles();
+ void resolveNextPendingRoles();
+
+private:
+ void startPreviewJob(const KFileItemList& items);
+
+ bool hasPendingRoles() const;
+ void resetPendingRoles();
+ void triggerPendingRolesResolving(int count);
+ void sortAndResolveAllRoles();
+ void sortAndResolvePendingRoles();
+
+ enum ResolveHint {
+ ResolveFast,
+ ResolveAll
+ };
+ bool applyResolvedRoles(const KFileItem& item, ResolveHint hint);
+ QHash<QByteArray, QVariant> rolesData(const KFileItem& item) const;
+
+ KFileItemList sortedItems(const QSet<KFileItem>& items) const;
+
+ static KFileItemList itemSubSet(const QSet<KFileItem>& items, int count);
+ static int subDirectoriesCount(const QString& path);
+
+private:
+ // Property for setPaused()/isPaused().
+ bool m_paused;
+
+ // Property changes during pausing must be remembered to be able
+ // to react when unpausing again:
+ bool m_previewChangedDuringPausing;
+ bool m_iconSizeChangedDuringPausing;
+ bool m_rolesChangedDuringPausing;
+
+ // Property for setPreviewShown()/previewShown().
+ bool m_previewShown;
+
+ // True if the role "iconPixmap" should be cleared when resolving the next
+ // role with resolveRole(). Is necessary if the preview gets disabled
+ // during the roles-updater has been paused by setPaused().
+ bool m_clearPreviews;
+
+ KFileItemModel* m_model;
+ QSize m_iconSize;
+ int m_firstVisibleIndex;
+ int m_lastVisibleIndex;
+ QSet<QByteArray> m_roles;
+ QStringList m_enabledPlugins;
+
+ QSet<KFileItem> m_pendingVisibleItems;
+ QSet<KFileItem> m_pendingInvisibleItems;
+ QList<KJob*> m_previewJobs;
+
+ QTimer* m_resolvePendingRolesTimer;
+};
+
+#endif
+
+
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 "kitemlistcontainer.h"
+
+#include "kitemlistcontroller.h"
+#include "kitemlistview.h"
+#include "kitemmodelbase.h"
+
+#include <QGraphicsScene>
+#include <QGraphicsView>
+#include <QScrollBar>
+#include <QStyle>
+
+#include <KDebug>
+
+class KItemListContainerViewport : public QGraphicsView
+{
+public:
+ KItemListContainerViewport(QGraphicsScene* scene, QWidget* parent)
+ : QGraphicsView(scene, parent)
+ {
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setViewportMargins(0, 0, 0, 0);
+ setFrameShape(QFrame::NoFrame);
+ }
+
+ void scrollContentsBy(int dx, int dy)
+ {
+ Q_UNUSED(dx);
+ Q_UNUSED(dy);
+ // Do nothing. This prevents that e.g. the wheel-event
+ // results in a moving of the scene items.
+ }
+};
+
+KItemListContainer::KItemListContainer(KItemListController* controller, QWidget* parent) :
+ QAbstractScrollArea(parent),
+ m_controller(controller)
+{
+ Q_ASSERT(controller);
+ controller->setParent(this);
+ initialize();
+}
+
+KItemListContainer::KItemListContainer(QWidget* parent) :
+ QAbstractScrollArea(parent),
+ m_controller(0)
+{
+ initialize();
+}
+
+KItemListContainer::~KItemListContainer()
+{
+}
+
+KItemListController* KItemListContainer::controller() const
+{
+ return m_controller;
+}
+
+void KItemListContainer::showEvent(QShowEvent* event)
+{
+ QAbstractScrollArea::showEvent(event);
+ updateGeometries();
+}
+
+void KItemListContainer::resizeEvent(QResizeEvent* event)
+{
+ QAbstractScrollArea::resizeEvent(event);
+ updateGeometries();
+}
+
+void KItemListContainer::scrollContentsBy(int dx, int dy)
+{
+ KItemListView* view = m_controller->view();
+ if (!view) {
+ return;
+ }
+
+ const qreal currentOffset = view->offset();
+ const qreal offsetDiff = (view->scrollOrientation() == Qt::Vertical) ? dy : dx;
+ view->setOffset(currentOffset - offsetDiff);
+}
+
+void KItemListContainer::slotModelChanged(KItemModelBase* current, KItemModelBase* previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+}
+
+void KItemListContainer::slotViewChanged(KItemListView* current, KItemListView* previous)
+{
+ QGraphicsScene* scene = static_cast<QGraphicsView*>(viewport())->scene();
+ if (previous) {
+ scene->removeItem(previous);
+ disconnect(previous, SIGNAL(offsetChanged(int,int)), this, SLOT(updateScrollBars()));
+ disconnect(previous, SIGNAL(maximumOffsetChanged(int,int)), this, SLOT(updateScrollBars()));
+ }
+ if (current) {
+ scene->addItem(current);
+ connect(previous, SIGNAL(offsetChanged(int,int)), this, SLOT(updateScrollBars()));
+ connect(current, SIGNAL(maximumOffsetChanged(int,int)), this, SLOT(updateScrollBars()));
+ }
+}
+
+void KItemListContainer::updateScrollBars()
+{
+ const QSizeF size = m_controller->view()->size();
+
+ if (m_controller->view()->scrollOrientation() == Qt::Vertical) {
+ QScrollBar* scrollBar = verticalScrollBar();
+ const int value = m_controller->view()->offset();
+ const int maximum = qMax(0, int(m_controller->view()->maximumOffset() - size.height()));
+ scrollBar->setPageStep(size.height());
+ scrollBar->setMinimum(0);
+ scrollBar->setMaximum(maximum);
+ scrollBar->setValue(value);
+ horizontalScrollBar()->setMaximum(0);
+ } else {
+ QScrollBar* scrollBar = horizontalScrollBar();
+ const int value = m_controller->view()->offset();
+ const int maximum = qMax(0, int(m_controller->view()->maximumOffset() - size.width()));
+ scrollBar->setPageStep(size.width());
+ scrollBar->setMinimum(0);
+ scrollBar->setMaximum(maximum);
+ scrollBar->setValue(value);
+ verticalScrollBar()->setMaximum(0);
+ }
+}
+
+void KItemListContainer::updateGeometries()
+{
+ QRect rect = geometry();
+
+ int widthDec = frameWidth() * 2;
+ if (verticalScrollBar()->isVisible()) {
+ widthDec += style()->pixelMetric(QStyle::PM_ScrollBarExtent);
+ }
+
+ int heightDec = frameWidth() * 2;
+ if (horizontalScrollBar()->isVisible()) {
+ heightDec += style()->pixelMetric(QStyle::PM_ScrollBarExtent);
+ }
+
+ rect.adjust(0, 0, -widthDec, -heightDec);
+
+ m_controller->view()->setGeometry(QRect(0, 0, rect.width(), rect.height()));
+
+ static_cast<KItemListContainerViewport*>(viewport())->scene()->setSceneRect(0, 0, rect.width(), rect.height());
+ static_cast<KItemListContainerViewport*>(viewport())->viewport()->setGeometry(QRect(0, 0, rect.width(), rect.height()));
+
+ updateScrollBars();
+}
+
+void KItemListContainer::initialize()
+{
+ if (!m_controller) {
+ m_controller = new KItemListController(this);
+ }
+
+ connect(m_controller, SIGNAL(modelChanged(KItemModelBase*,KItemModelBase*)),
+ this, SLOT(slotModelChanged(KItemModelBase*,KItemModelBase*)));
+ connect(m_controller, SIGNAL(viewChanged(KItemListView*,KItemListView*)),
+ this, SLOT(slotViewChanged(KItemListView*,KItemListView*)));
+
+ QGraphicsView* graphicsView = new KItemListContainerViewport(new QGraphicsScene(this), this);
+ setViewport(graphicsView);
+}
+
+#include "kitemlistcontainer.moc"
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 KITEMLISTCONTAINER_H
+#define KITEMLISTCONTAINER_H
+
+#include <libdolphin_export.h>
+
+#include <QAbstractScrollArea>
+
+class KItemListController;
+class KItemListView;
+class KItemModelBase;
+
+/**
+ * @brief Provides a QWidget based scrolling view for a KItemListController.
+ *
+ * @see KItemListController
+ */
+class LIBDOLPHINPRIVATE_EXPORT KItemListContainer : public QAbstractScrollArea
+{
+ Q_OBJECT
+
+public:
+ explicit KItemListContainer(KItemListController* controller, QWidget* parent = 0);
+ KItemListContainer(QWidget* parent = 0);
+ virtual ~KItemListContainer();
+
+ KItemListController* controller() const;
+
+protected:
+ virtual void showEvent(QShowEvent* event);
+ virtual void resizeEvent(QResizeEvent* event);
+ virtual void scrollContentsBy(int dx, int dy);
+
+private slots:
+ void slotModelChanged(KItemModelBase* current, KItemModelBase* previous);
+ void slotViewChanged(KItemListView* current, KItemListView* previous);
+ void updateScrollBars();
+
+private:
+ void initialize();
+ void updateGeometries();
+
+private:
+ KItemListController* m_controller;
+};
+
+#endif
+
+
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 "kitemlistcontroller.h"
+
+#include "kitemlistview.h"
+#include "kitemlistselectionmanager.h"
+
+#include <QEvent>
+#include <QGraphicsSceneEvent>
+#include <QTransform>
+
+#include <KDebug>
+
+KItemListController::KItemListController(QObject* parent) :
+ QObject(parent),
+ m_selectionBehavior(NoSelection),
+ m_model(0),
+ m_view(0),
+ m_selectionManager(new KItemListSelectionManager(this))
+{
+}
+
+KItemListController::~KItemListController()
+{
+}
+
+void KItemListController::setModel(KItemModelBase* model)
+{
+ if (m_model == model) {
+ return;
+ }
+
+ KItemModelBase* oldModel = m_model;
+ m_model = model;
+
+ if (m_view) {
+ m_view->setModel(m_model);
+ }
+
+ emit modelChanged(m_model, oldModel);
+}
+
+KItemModelBase* KItemListController::model() const
+{
+ return m_model;
+}
+
+KItemListSelectionManager* KItemListController::selectionManager() const
+{
+ return m_selectionManager;
+}
+
+void KItemListController::setView(KItemListView* view)
+{
+ if (m_view == view) {
+ return;
+ }
+
+ KItemListView* oldView = m_view;
+ m_view = view;
+
+ if (m_view) {
+ m_view->setController(this);
+ m_view->setModel(m_model);
+ }
+
+ emit viewChanged(m_view, oldView);
+}
+
+KItemListView* KItemListController::view() const
+{
+ return m_view;
+}
+
+void KItemListController::setSelectionBehavior(SelectionBehavior behavior)
+{
+ m_selectionBehavior = behavior;
+}
+
+KItemListController::SelectionBehavior KItemListController::selectionBehavior() const
+{
+ return m_selectionBehavior;
+}
+
+bool KItemListController::showEvent(QShowEvent* event)
+{
+ Q_UNUSED(event);
+ return false;
+}
+
+bool KItemListController::hideEvent(QHideEvent* event)
+{
+ Q_UNUSED(event);
+ return false;
+}
+
+bool KItemListController::keyPressEvent(QKeyEvent* event)
+{
+ Q_UNUSED(event);
+ return false;
+}
+
+bool KItemListController::inputMethodEvent(QInputMethodEvent* event)
+{
+ Q_UNUSED(event);
+ return false;
+}
+
+bool KItemListController::mousePressEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform)
+{
+ Q_UNUSED(event);
+ Q_UNUSED(transform);
+ return false;
+}
+
+bool KItemListController::mouseMoveEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform)
+{
+ Q_UNUSED(event);
+ Q_UNUSED(transform);
+ return false;
+}
+
+bool KItemListController::mouseReleaseEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform)
+{
+ if (m_view) {
+ const QPointF pos = transform.map(event->pos());
+ const int index = m_view->itemAt(pos);
+ if (index >= 0) {
+ bool emitItemClicked = true;
+ if (event->button() & Qt::LeftButton) {
+ if (m_view->isAboveExpansionToggle(index, pos)) {
+ emit itemExpansionToggleClicked(index);
+ emitItemClicked = false;
+ }
+ }
+
+ if (emitItemClicked) {
+ emit itemClicked(index, event->button());
+ }
+ }
+ }
+
+ return false;
+}
+
+bool KItemListController::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform)
+{
+ Q_UNUSED(event);
+ Q_UNUSED(transform);
+ return false;
+}
+
+bool KItemListController::dragEnterEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform)
+{
+ Q_UNUSED(event);
+ Q_UNUSED(transform);
+ return false;
+}
+
+bool KItemListController::dragLeaveEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform)
+{
+ Q_UNUSED(event);
+ Q_UNUSED(transform);
+ return false;
+}
+
+bool KItemListController::dragMoveEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform)
+{
+ Q_UNUSED(event);
+ Q_UNUSED(transform);
+ return false;
+}
+
+bool KItemListController::dropEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform)
+{
+ Q_UNUSED(event);
+ Q_UNUSED(transform);
+ return false;
+}
+
+bool KItemListController::hoverEnterEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform)
+{
+ Q_UNUSED(event);
+ Q_UNUSED(transform);
+ return false;
+}
+
+bool KItemListController::hoverMoveEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform)
+{
+ Q_UNUSED(event);
+ Q_UNUSED(transform);
+ return false;
+}
+
+bool KItemListController::hoverLeaveEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform)
+{
+ Q_UNUSED(event);
+ Q_UNUSED(transform);
+ return false;
+}
+
+bool KItemListController::wheelEvent(QGraphicsSceneWheelEvent* event, const QTransform& transform)
+{
+ Q_UNUSED(event);
+ Q_UNUSED(transform);
+ return false;
+}
+
+bool KItemListController::resizeEvent(QGraphicsSceneResizeEvent* event, const QTransform& transform)
+{
+ Q_UNUSED(event);
+ Q_UNUSED(transform);
+ return false;
+}
+
+bool KItemListController::processEvent(QEvent* event, const QTransform& transform)
+{
+ if (!event) {
+ return false;
+ }
+
+ switch (event->type()) {
+// case QEvent::FocusIn:
+// case QEvent::FocusOut:
+// return focusEvent(static_cast<QFocusEvent*>(event));
+ case QEvent::KeyPress:
+ return keyPressEvent(static_cast<QKeyEvent*>(event));
+ case QEvent::InputMethod:
+ return inputMethodEvent(static_cast<QInputMethodEvent*>(event));
+ case QEvent::GraphicsSceneMousePress:
+ return mousePressEvent(static_cast<QGraphicsSceneMouseEvent*>(event), QTransform());
+ case QEvent::GraphicsSceneMouseMove:
+ return mouseMoveEvent(static_cast<QGraphicsSceneMouseEvent*>(event), QTransform());
+ case QEvent::GraphicsSceneMouseRelease:
+ return mouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent*>(event), QTransform());
+ case QEvent::GraphicsSceneWheel:
+ return wheelEvent(static_cast<QGraphicsSceneWheelEvent*>(event), QTransform());
+ case QEvent::GraphicsSceneDragEnter:
+ return dragEnterEvent(static_cast<QGraphicsSceneDragDropEvent*>(event), QTransform());
+ case QEvent::GraphicsSceneDragLeave:
+ return dragLeaveEvent(static_cast<QGraphicsSceneDragDropEvent*>(event), QTransform());
+ case QEvent::GraphicsSceneDragMove:
+ return dragMoveEvent(static_cast<QGraphicsSceneDragDropEvent*>(event), QTransform());
+ case QEvent::GraphicsSceneDrop:
+ return dropEvent(static_cast<QGraphicsSceneDragDropEvent*>(event), QTransform());
+ case QEvent::GraphicsSceneHoverEnter:
+ return hoverEnterEvent(static_cast<QGraphicsSceneHoverEvent*>(event), QTransform());
+ case QEvent::GraphicsSceneHoverMove:
+ return hoverMoveEvent(static_cast<QGraphicsSceneHoverEvent*>(event), QTransform());
+ case QEvent::GraphicsSceneHoverLeave:
+ return hoverLeaveEvent(static_cast<QGraphicsSceneHoverEvent*>(event), QTransform());
+ case QEvent::GraphicsSceneResize:
+ return resizeEvent(static_cast<QGraphicsSceneResizeEvent*>(event), transform);
+ default:
+ break;
+ }
+
+ return false;
+}
+
+#include "kitemlistcontroller.moc"
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 KITEMLISTCONTROLLER_H
+#define KITEMLISTCONTROLLER_H
+
+#include <libdolphin_export.h>
+
+#include <QObject>
+
+class KItemModelBase;
+class KItemListSelectionManager;
+class KItemListView;
+class QGraphicsSceneHoverEvent;
+class QGraphicsSceneDragDropEvent;
+class QGraphicsSceneMouseEvent;
+class QGraphicsSceneResizeEvent;
+class QGraphicsSceneWheelEvent;
+class QHideEvent;
+class QInputMethodEvent;
+class QKeyEvent;
+class QShowEvent;
+class QTransform;
+
+/**
+ * @brief Controls the view, model and selection of an item-list.
+ *
+ * For a working item-list it is mandatory to set a compatible view and model
+ * with KItemListController::setView() and KItemListController::setModel().
+ *
+ * @see KItemListView
+ * @see KItemModelBase
+ * @see KItemListSelectionManager
+ */
+class LIBDOLPHINPRIVATE_EXPORT KItemListController : public QObject
+{
+ Q_OBJECT
+ Q_ENUMS(SelectionBehavior)
+ Q_PROPERTY(KItemModelBase* model READ model WRITE setModel)
+ Q_PROPERTY(KItemListView *view READ view WRITE setView)
+ Q_PROPERTY(SelectionBehavior selectionBehavior READ selectionBehavior WRITE setSelectionBehavior)
+
+public:
+ enum SelectionBehavior {
+ NoSelection,
+ SingleSelection,
+ MultiSelection
+ };
+
+ KItemListController(QObject* parent = 0);
+ virtual ~KItemListController();
+
+ void setModel(KItemModelBase* model);
+ KItemModelBase* model() const;
+
+ void setView(KItemListView* view);
+ KItemListView* view() const;
+
+ KItemListSelectionManager* selectionManager() const;
+
+ void setSelectionBehavior(SelectionBehavior behavior);
+ SelectionBehavior selectionBehavior() const;
+
+ virtual bool showEvent(QShowEvent* event);
+ virtual bool hideEvent(QHideEvent* event);
+ virtual bool keyPressEvent(QKeyEvent* event);
+ virtual bool inputMethodEvent(QInputMethodEvent* event);
+ virtual bool mousePressEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform);
+ virtual bool mouseMoveEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform);
+ virtual bool mouseReleaseEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform);
+ virtual bool mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform);
+ virtual bool dragEnterEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform);
+ virtual bool dragLeaveEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform);
+ virtual bool dragMoveEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform);
+ virtual bool dropEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform);
+ virtual bool hoverEnterEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform);
+ virtual bool hoverMoveEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform);
+ virtual bool hoverLeaveEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform);
+ virtual bool wheelEvent(QGraphicsSceneWheelEvent* event, const QTransform& transform);
+ virtual bool resizeEvent(QGraphicsSceneResizeEvent* event, const QTransform& transform);
+ virtual bool processEvent(QEvent* event, const QTransform& transform);
+
+signals:
+ void itemClicked(int index, Qt::MouseButton button);
+ void itemExpansionToggleClicked(int index);
+
+ void modelChanged(KItemModelBase* current, KItemModelBase* previous);
+ void viewChanged(KItemListView* current, KItemListView* previous);
+
+private:
+ SelectionBehavior m_selectionBehavior;
+ KItemModelBase* m_model;
+ KItemListView* m_view;
+ KItemListSelectionManager* m_selectionManager;
+};
+
+#endif
+
+
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 "kitemlistgroupheader.h"
+
+#include "kitemlistview.h"
+
+#include <QPainter>
+
+#include <KDebug>
+
+KItemListGroupHeader::KItemListGroupHeader(QGraphicsWidget* parent) :
+ QGraphicsWidget(parent, 0)
+{
+}
+
+KItemListGroupHeader::~KItemListGroupHeader()
+{
+}
+
+QSizeF KItemListGroupHeader::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const
+{
+ Q_UNUSED(which);
+ Q_UNUSED(constraint);
+ return QSizeF();
+}
+
+void KItemListGroupHeader::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
+{
+ Q_UNUSED(option);
+ Q_UNUSED(widget);
+ painter->setPen(Qt::darkGreen);
+ painter->setBrush(QColor(0, 255, 0, 50));
+ painter->drawRect(rect());
+
+ //painter->drawText(rect(), QString::number(m_index));
+}
+
+#include "kitemlistgroupheader.moc"
/***************************************************************************
- * Copyright (C) 2006 by Peter Penz <peter.penz19@gmail.com> *
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
* *
* 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 *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
-#ifndef COLUMNVIEWSETTINGSPAGE_H
-#define COLUMNVIEWSETTINGSPAGE_H
+#ifndef KITEMLISTGROUPHEADER_H
+#define KITEMLISTGROUPHEADER_H
-#include "viewsettingspagebase.h"
+#include <libdolphin_export.h>
-class DolphinFontRequester;
-class IconSizeGroupBox;
-class KComboBox;
+#include <QGraphicsWidget>
-/**
- * @brief Represents the page from the Dolphin Settings which allows
- * to modify the settings for the details view.
- */
-class ColumnViewSettingsPage : public ViewSettingsPageBase
+class KItemListView;
+
+class LIBDOLPHINPRIVATE_EXPORT KItemListGroupHeader : public QGraphicsWidget
{
Q_OBJECT
public:
- ColumnViewSettingsPage(QWidget* parent);
- virtual ~ColumnViewSettingsPage();
-
- /**
- * Applies the settings for the details view.
- * The settings are persisted automatically when
- * closing Dolphin.
- */
- virtual void applySettings();
-
- /** Restores the settings to default values. */
- virtual void restoreDefaults();
-
-private:
- void loadSettings();
+ KItemListGroupHeader(QGraphicsWidget* parent = 0);
+ virtual ~KItemListGroupHeader();
-private:
- enum
- {
- BaseTextWidth = 200,
- TextInc = 50
- };
+ void setIndex(int index);
+ int index() const;
- IconSizeGroupBox* m_iconSizeGroupBox;
- DolphinFontRequester* m_fontRequester;
- KComboBox* m_textWidthBox;
+ virtual QSizeF sizeHint(Qt::SizeHint which = Qt::PreferredSize, const QSizeF& constraint = QSizeF()) const;
+ virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0);
};
-
#endif
+
+
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 "kitemlistselectionmanager.h"
+
+#include "kitemmodelbase.h"
+
+KItemListSelectionManager::KItemListSelectionManager(QObject* parent) :
+ QObject(parent),
+ m_currentItem(-1),
+ m_anchorItem(-1),
+ m_model(0)
+{
+}
+
+KItemListSelectionManager::~KItemListSelectionManager()
+{
+}
+
+void KItemListSelectionManager::setCurrentItem(int current)
+{
+ const int previous = m_currentItem;
+ if (m_model && current < m_model->count()) {
+ m_currentItem = current;
+ } else {
+ m_currentItem = -1;
+ }
+
+ if (m_currentItem != previous) {
+ emit currentChanged(m_currentItem, previous);
+ }
+}
+
+int KItemListSelectionManager::currentItem() const
+{
+ return m_currentItem;
+}
+
+void KItemListSelectionManager::setAnchorItem(int anchor)
+{
+ const int previous = m_anchorItem;
+ if (m_model && anchor < m_model->count()) {
+ m_anchorItem = anchor;
+ } else {
+ m_anchorItem = -1;
+ }
+
+ if (m_anchorItem != previous) {
+ emit anchorChanged(m_anchorItem, previous);
+ }
+}
+
+int KItemListSelectionManager::anchorItem() const
+{
+ return m_anchorItem;
+}
+
+KItemModelBase* KItemListSelectionManager::model() const
+{
+ return m_model;
+}
+
+void KItemListSelectionManager::setModel(KItemModelBase* model)
+{
+ m_model = model;
+}
+
+#include "kitemlistselectionmanager.moc"
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 KITEMLISTSELECTIONMANAGER_H
+#define KITEMLISTSELECTIONMANAGER_H
+
+#include <libdolphin_export.h>
+
+#include <QObject>
+
+class KItemModelBase;
+
+class LIBDOLPHINPRIVATE_EXPORT KItemListSelectionManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum SelectionMode {
+ Select,
+ Deselect,
+ Toggle
+ };
+
+ KItemListSelectionManager(QObject* parent = 0);
+ virtual ~KItemListSelectionManager();
+
+ void setCurrentItem(int current);
+ int currentItem() const;
+
+ void setAnchorItem(int anchor);
+ int anchorItem() const;
+
+ KItemModelBase* model() const;
+
+signals:
+ void currentChanged(int current, int previous);
+ void anchorChanged(int anchor, int previous);
+
+protected:
+ void setModel(KItemModelBase* model);
+
+private:
+ int m_currentItem;
+ int m_anchorItem;
+ KItemModelBase* m_model;
+
+ friend class KItemListController;
+};
+
+#endif
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 <kitemviews/kitemlistview.h>
+#include <KDebug>
+
+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<QSizeF>::iterator begin = m_sizeHintCache.begin() + index;
+ const QList<QSizeF>::iterator end = begin + count;
+ m_sizeHintCache.erase(begin, end);
+}
+
+void KItemListSizeHintResolver::itemsMoved(int from, int to, int count)
+{
+ Q_UNUSED(from);
+ Q_UNUSED(to);
+ Q_UNUSED(count);
+}
+
+void KItemListSizeHintResolver::itemsChanged(int index, int count, const QSet<QByteArray>& 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();
+ }
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 <libdolphin_export.h>
+
+#include <QByteArray>
+#include <QList>
+#include <QSizeF>
+
+class 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 from, int to, int count);
+ void itemsChanged(int index, int count, const QSet<QByteArray>& roles);
+
+ void clearCache();
+
+private:
+ const KItemListView* m_itemListView;
+ mutable QList<QSizeF> m_sizeHintCache;
+};
+
+#endif
/***************************************************************************
- * Copyright (C) 2010 by Frank Reininghaus (frank78ac@googlemail.com) *
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
* *
* 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 *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
-#include <qtest_kde.h>
+#include "kitemliststyleoption.h"
-#include "dolphinviewtest_allviewmodes.h"
-
-class DolphinViewTest_Details : public DolphinViewTest_AllViewModes
+KItemListStyleOption::KItemListStyleOption() :
+ QStyleOption(QStyleOption::Version, QStyleOption::SO_CustomBase + 1)
{
- Q_OBJECT
-
-public:
-
- virtual DolphinView::Mode mode() const {
- return DolphinView::DetailsView;
- }
-
- virtual bool verifyCorrectViewMode(const DolphinView* view) const {
- return (view->mode() == DolphinView::DetailsView);
- }
+}
-};
-
-QTEST_KDEMAIN(DolphinViewTest_Details, GUI)
+KItemListStyleOption::KItemListStyleOption(const KItemListStyleOption& other) :
+ QStyleOption(other)
+{
+ margin = other.margin;
+ iconSize = other.iconSize;
+ font = other.font;
+}
-#include "dolphinviewtest_details.moc"
+KItemListStyleOption::~KItemListStyleOption()
+{
+}
/***************************************************************************
- * Copyright (C) 2010 by Frank Reininghaus (frank78ac@googlemail.com) *
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
* *
* 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 *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
-#include <qtest_kde.h>
+#ifndef KITEMLISTSTYLEOPTION_H
+#define KITEMLISTSTYLEOPTION_H
-#include "dolphinviewtest_allviewmodes.h"
+#include <libdolphin_export.h>
-class DolphinViewTest_Columns : public DolphinViewTest_AllViewModes
-{
- Q_OBJECT
+#include <QFont>
+#include <QStyleOption>
+class LIBDOLPHINPRIVATE_EXPORT KItemListStyleOption : public QStyleOption
+{
public:
+ KItemListStyleOption();
+ KItemListStyleOption(const KItemListStyleOption& other);
+ virtual ~KItemListStyleOption();
- virtual DolphinView::Mode mode() const {
- return DolphinView::ColumnView;
- }
-
- virtual bool verifyCorrectViewMode(const DolphinView* view) const {
- return (view->mode() == DolphinView::ColumnView);
- }
-
+ int margin;
+ int iconSize;
+ QFont font;
};
+#endif
-QTEST_KDEMAIN(DolphinViewTest_Columns, GUI)
-#include "dolphinviewtest_columns.moc"
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 "kitemlistview.h"
+
+#include "kitemlistcontroller.h"
+#include "kitemlistgroupheader.h"
+#include "kitemlistselectionmanager.h"
+#include "kitemlistsizehintresolver_p.h"
+#include "kitemlistviewlayouter_p.h"
+#include "kitemlistviewanimation_p.h"
+#include "kitemlistwidget.h"
+
+#include <KDebug>
+
+#include <QGraphicsSceneMouseEvent>
+#include <QPropertyAnimation>
+#include <QStyle>
+#include <QTimer>
+
+KItemListView::KItemListView(QGraphicsWidget* parent) :
+ QGraphicsWidget(parent),
+ m_grouped(false),
+ m_activeTransactions(0),
+ m_itemSize(),
+ m_controller(0),
+ m_model(0),
+ m_visibleRoles(),
+ m_visibleRolesSizes(),
+ m_widgetCreator(0),
+ m_groupHeaderCreator(0),
+ m_styleOption(),
+ m_visibleItems(),
+ m_visibleGroups(),
+ m_sizeHintResolver(0),
+ m_layouter(0),
+ m_animation(0),
+ m_layoutTimer(0),
+ m_oldOffset(0),
+ m_oldMaximumOffset(0)
+{
+ setAcceptHoverEvents(true);
+
+ m_sizeHintResolver = new KItemListSizeHintResolver(this);
+
+ m_layouter = new KItemListViewLayouter(this);
+ m_layouter->setSizeHintResolver(m_sizeHintResolver);
+
+ m_animation = new KItemListViewAnimation(this);
+ connect(m_animation, SIGNAL(finished(QGraphicsWidget*, KItemListViewAnimation::AnimationType)),
+ this, SLOT(slotAnimationFinished(QGraphicsWidget*, KItemListViewAnimation::AnimationType)));
+
+ m_layoutTimer = new QTimer(this);
+ m_layoutTimer->setInterval(300);
+ m_layoutTimer->setSingleShot(true);
+ connect(m_layoutTimer, SIGNAL(timeout()), this, SLOT(slotLayoutTimerFinished()));
+}
+
+KItemListView::~KItemListView()
+{
+ delete m_sizeHintResolver;
+ m_sizeHintResolver = 0;
+}
+
+void KItemListView::setScrollOrientation(Qt::Orientation orientation)
+{
+ const Qt::Orientation previousOrientation = m_layouter->scrollOrientation();
+ if (orientation == previousOrientation) {
+ return;
+ }
+
+ m_layouter->setScrollOrientation(orientation);
+ m_animation->setScrollOrientation(orientation);
+ m_sizeHintResolver->clearCache();
+ updateLayout();
+ onScrollOrientationChanged(orientation, previousOrientation);
+}
+
+Qt::Orientation KItemListView::scrollOrientation() const
+{
+ return m_layouter->scrollOrientation();
+}
+
+void KItemListView::setItemSize(const QSizeF& itemSize)
+{
+ const QSizeF previousSize = m_itemSize;
+ if (itemSize == previousSize) {
+ return;
+ }
+
+ m_itemSize = itemSize;
+
+ if (!markVisibleRolesSizesAsDirty()) {
+ if (itemSize.width() < previousSize.width() || itemSize.height() < previousSize.height()) {
+ prepareLayoutForIncreasedItemCount(itemSize, ItemSize);
+ } else {
+ m_layouter->setItemSize(itemSize);
+ }
+ }
+
+ m_sizeHintResolver->clearCache();
+ updateLayout();
+ onItemSizeChanged(itemSize, previousSize);
+}
+
+QSizeF KItemListView::itemSize() const
+{
+ return m_itemSize;
+}
+
+void KItemListView::setOffset(qreal offset)
+{
+ if (offset < 0) {
+ offset = 0;
+ }
+
+ const qreal previousOffset = m_layouter->offset();
+ if (offset == previousOffset) {
+ return;
+ }
+
+ m_layouter->setOffset(offset);
+ m_animation->setOffset(offset);
+ if (!m_layoutTimer->isActive()) {
+ doLayout(NoAnimation, 0, 0);
+ update();
+ }
+ onOffsetChanged(offset, previousOffset);
+}
+
+qreal KItemListView::offset() const
+{
+ return m_layouter->offset();
+}
+
+qreal KItemListView::maximumOffset() const
+{
+ return m_layouter->maximumOffset();
+}
+
+void KItemListView::setVisibleRoles(const QHash<QByteArray, int>& roles)
+{
+ const QHash<QByteArray, int> previousRoles = m_visibleRoles;
+ m_visibleRoles = roles;
+
+ QHashIterator<int, KItemListWidget*> it(m_visibleItems);
+ while (it.hasNext()) {
+ it.next();
+ KItemListWidget* widget = it.value();
+ widget->setVisibleRoles(roles);
+ widget->setVisibleRolesSizes(m_visibleRolesSizes);
+ }
+
+ m_sizeHintResolver->clearCache();
+ m_layouter->markAsDirty();
+ onVisibleRolesChanged(roles, previousRoles);
+
+ markVisibleRolesSizesAsDirty();
+ updateLayout();
+}
+
+QHash<QByteArray, int> KItemListView::visibleRoles() const
+{
+ return m_visibleRoles;
+}
+
+KItemListController* KItemListView::controller() const
+{
+ return m_controller;
+}
+
+KItemModelBase* KItemListView::model() const
+{
+ return m_model;
+}
+
+void KItemListView::setWidgetCreator(KItemListWidgetCreatorBase* widgetCreator)
+{
+ m_widgetCreator = widgetCreator;
+}
+
+KItemListWidgetCreatorBase* KItemListView::widgetCreator() const
+{
+ return m_widgetCreator;
+}
+
+void KItemListView::setGroupHeaderCreator(KItemListGroupHeaderCreatorBase* groupHeaderCreator)
+{
+ m_groupHeaderCreator = groupHeaderCreator;
+}
+
+KItemListGroupHeaderCreatorBase* KItemListView::groupHeaderCreator() const
+{
+ return m_groupHeaderCreator;
+}
+
+void KItemListView::setStyleOption(const KItemListStyleOption& option)
+{
+ const KItemListStyleOption previousOption = m_styleOption;
+ m_styleOption = option;
+
+ QHashIterator<int, KItemListWidget*> it(m_visibleItems);
+ while (it.hasNext()) {
+ it.next();
+ it.value()->setStyleOption(option);
+ }
+
+ m_sizeHintResolver->clearCache();
+ updateLayout();
+ onStyleOptionChanged(option, previousOption);
+}
+
+const KItemListStyleOption& KItemListView::styleOption() const
+{
+ return m_styleOption;
+}
+
+void KItemListView::setGeometry(const QRectF& rect)
+{
+ QGraphicsWidget::setGeometry(rect);
+ if (!m_model) {
+ return;
+ }
+
+ if (m_itemSize.isEmpty()) {
+ m_layouter->setItemSize(QSizeF());
+ }
+
+ if (m_model->count() > 0) {
+ prepareLayoutForIncreasedItemCount(rect.size(), LayouterSize);
+ } else {
+ m_layouter->setSize(rect.size());
+ }
+
+ m_layoutTimer->start();
+}
+
+int KItemListView::itemAt(const QPointF& pos) const
+{
+ if (!m_model) {
+ return -1;
+ }
+
+ QHashIterator<int, KItemListWidget*> it(m_visibleItems);
+ while (it.hasNext()) {
+ it.next();
+
+ const KItemListWidget* widget = it.value();
+ const QPointF mappedPos = widget->mapFromItem(this, pos);
+ if (widget->contains(mappedPos)) {
+ return it.key();
+ }
+ }
+
+ return -1;
+}
+
+bool KItemListView::isAboveSelectionToggle(int index, const QPointF& pos) const
+{
+ Q_UNUSED(index);
+ Q_UNUSED(pos);
+ return false;
+}
+
+bool KItemListView::isAboveExpansionToggle(int index, const QPointF& pos) const
+{
+ const KItemListWidget* widget = m_visibleItems.value(index);
+ if (widget) {
+ const QRectF expansionToggleRect = widget->expansionToggleRect();
+ if (!expansionToggleRect.isEmpty()) {
+ const QPointF mappedPos = widget->mapFromItem(this, pos);
+ return expansionToggleRect.contains(mappedPos);
+ }
+ }
+ return false;
+}
+
+int KItemListView::firstVisibleIndex() const
+{
+ return m_layouter->firstVisibleIndex();
+}
+
+int KItemListView::lastVisibleIndex() const
+{
+ return m_layouter->lastVisibleIndex();
+}
+
+QSizeF KItemListView::itemSizeHint(int index) const
+{
+ Q_UNUSED(index);
+ return itemSize();
+}
+
+QHash<QByteArray, QSizeF> KItemListView::visibleRoleSizes() const
+{
+ return QHash<QByteArray, QSizeF>();
+}
+
+void KItemListView::beginTransaction()
+{
+ ++m_activeTransactions;
+ if (m_activeTransactions == 1) {
+ onTransactionBegin();
+ }
+}
+
+void KItemListView::endTransaction()
+{
+ --m_activeTransactions;
+ if (m_activeTransactions < 0) {
+ m_activeTransactions = 0;
+ kWarning() << "Mismatch between beginTransaction()/endTransaction()";
+ }
+
+ if (m_activeTransactions == 0) {
+ onTransactionEnd();
+ updateLayout();
+ }
+}
+
+bool KItemListView::isTransactionActive() const
+{
+ return m_activeTransactions > 0;
+}
+
+void KItemListView::initializeItemListWidget(KItemListWidget* item)
+{
+ Q_UNUSED(item);
+}
+
+void KItemListView::onControllerChanged(KItemListController* current, KItemListController* previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+}
+
+void KItemListView::onModelChanged(KItemModelBase* current, KItemModelBase* previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+}
+
+void KItemListView::onScrollOrientationChanged(Qt::Orientation current, Qt::Orientation previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+}
+
+void KItemListView::onItemSizeChanged(const QSizeF& current, const QSizeF& previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+}
+
+void KItemListView::onOffsetChanged(qreal current, qreal previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+}
+
+void KItemListView::onVisibleRolesChanged(const QHash<QByteArray, int>& current, const QHash<QByteArray, int>& previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+}
+
+void KItemListView::onStyleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+}
+
+void KItemListView::onTransactionBegin()
+{
+}
+
+void KItemListView::onTransactionEnd()
+{
+}
+
+bool KItemListView::event(QEvent* event)
+{
+ // Forward all events to the controller and handle them there
+ if (m_controller && m_controller->processEvent(event, transform())) {
+ event->accept();
+ return true;
+ }
+ return QGraphicsWidget::event(event);
+}
+
+void KItemListView::mousePressEvent(QGraphicsSceneMouseEvent* event)
+{
+ event->accept();
+}
+
+void KItemListView::hoverMoveEvent(QGraphicsSceneHoverEvent* event)
+{
+ if (!m_model) {
+ return;
+ }
+
+ QHashIterator<int, KItemListWidget*> it(m_visibleItems);
+ while (it.hasNext()) {
+ it.next();
+
+ KItemListWidget* widget = it.value();
+ KItemListStyleOption styleOption = widget->styleOption();
+ const QPointF mappedPos = widget->mapFromItem(this, event->pos());
+
+ const bool hovered = widget->contains(mappedPos) &&
+ !widget->expansionToggleRect().contains(mappedPos) &&
+ !widget->selectionToggleRect().contains(mappedPos);
+ if (hovered) {
+ if (!(styleOption.state & QStyle::State_MouseOver)) {
+ styleOption.state |= QStyle::State_MouseOver;
+ widget->setStyleOption(styleOption);
+ }
+ } else if (styleOption.state & QStyle::State_MouseOver) {
+ styleOption.state &= ~QStyle::State_MouseOver;
+ widget->setStyleOption(styleOption);
+ }
+ }
+}
+
+void KItemListView::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
+{
+ Q_UNUSED(event);
+
+ if (!m_model) {
+ return;
+ }
+
+ QHashIterator<int, KItemListWidget*> it(m_visibleItems);
+ while (it.hasNext()) {
+ it.next();
+
+ KItemListWidget* widget = it.value();
+ KItemListStyleOption styleOption = widget->styleOption();
+ if (styleOption.state & QStyle::State_MouseOver) {
+ styleOption.state &= ~QStyle::State_MouseOver;
+ widget->setStyleOption(styleOption);
+ }
+ }
+}
+
+QList<KItemListWidget*> KItemListView::visibleItemListWidgets() const
+{
+ return m_visibleItems.values();
+}
+
+void KItemListView::slotItemsInserted(const KItemRangeList& itemRanges)
+{
+ markVisibleRolesSizesAsDirty();
+
+ const bool hasMultipleRanges = (itemRanges.count() > 1);
+ if (hasMultipleRanges) {
+ beginTransaction();
+ }
+
+ foreach (const KItemRange& range, itemRanges) {
+ const int index = range.index;
+ const int count = range.count;
+ if (index < 0 || count <= 0) {
+ kWarning() << "Invalid item range (index:" << index << ", count:" << count << ")";
+ continue;
+ }
+
+ m_sizeHintResolver->itemsInserted(index, count);
+
+ // Determine which visible items must be moved
+ QList<int> itemsToMove;
+ QHashIterator<int, KItemListWidget*> it(m_visibleItems);
+ while (it.hasNext()) {
+ it.next();
+ const int visibleItemIndex = it.key();
+ if (visibleItemIndex >= index) {
+ itemsToMove.append(visibleItemIndex);
+ }
+ }
+
+ // Update the indexes of all KItemListWidget instances that are located
+ // after the inserted items. It is important to adjust the indexes in the order
+ // from the highest index to the lowest index to prevent overlaps when setting the new index.
+ qSort(itemsToMove);
+ for (int i = itemsToMove.count() - 1; i >= 0; --i) {
+ KItemListWidget* widget = m_visibleItems.value(itemsToMove[i]);
+ Q_ASSERT(widget);
+ setWidgetIndex(widget, widget->index() + count);
+ }
+
+ m_layouter->markAsDirty();
+ if (m_model->count() == count && maximumOffset() > size().height()) {
+ kDebug() << "Scrollbar required, skipping layout";
+ const int scrollBarExtent = style()->pixelMetric(QStyle::PM_ScrollBarExtent);
+ QSizeF layouterSize = m_layouter->size();
+ if (scrollOrientation() == Qt::Vertical) {
+ layouterSize.rwidth() -= scrollBarExtent;
+ } else {
+ layouterSize.rheight() -= scrollBarExtent;
+ }
+ m_layouter->setSize(layouterSize);
+ }
+
+ if (!hasMultipleRanges) {
+ doLayout(Animation, index, count);
+ update();
+ }
+
+ if (m_controller) {
+ KItemListSelectionManager* selectionManager = m_controller->selectionManager();
+ const int current = selectionManager->currentItem();
+ if (current < 0) {
+ selectionManager->setCurrentItem(0);
+ } else if (current >= index) {
+ selectionManager->setCurrentItem(current + count);
+ }
+ }
+ }
+
+ if (hasMultipleRanges) {
+ endTransaction();
+ }
+}
+
+void KItemListView::slotItemsRemoved(const KItemRangeList& itemRanges)
+{
+ markVisibleRolesSizesAsDirty();
+
+ const bool hasMultipleRanges = (itemRanges.count() > 1);
+ if (hasMultipleRanges) {
+ beginTransaction();
+ }
+
+ for (int i = itemRanges.count() - 1; i >= 0; --i) {
+ const KItemRange& range = itemRanges.at(i);
+ const int index = range.index;
+ const int count = range.count;
+ if (index < 0 || count <= 0) {
+ kWarning() << "Invalid item range (index:" << index << ", count:" << count << ")";
+ continue;
+ }
+
+ m_sizeHintResolver->itemsRemoved(index, count);
+
+ const int firstRemovedIndex = index;
+ const int lastRemovedIndex = index + count - 1;
+ const int lastIndex = m_model->count() + count - 1;
+
+ // Remove all KItemListWidget instances that got deleted
+ for (int i = firstRemovedIndex; i <= lastRemovedIndex; ++i) {
+ KItemListWidget* widget = m_visibleItems.value(i);
+ if (!widget) {
+ continue;
+ }
+
+ m_animation->stop(widget);
+ // Stopping the animation might lead to recycling the widget if
+ // it is invisible (see slotAnimationFinished()).
+ // Check again whether it is still visible:
+ if (!m_visibleItems.contains(i)) {
+ continue;
+ }
+
+ if (m_model->count() == 0) {
+ // For performance reasons no animation is done when all items have
+ // been removed.
+ recycleWidget(widget);
+ } else {
+ // Animate the removing of the items. Special case: When removing an item there
+ // is no valid model index available anymore. For the
+ // remove-animation the item gets removed from m_visibleItems but the widget
+ // will stay alive until the animation has been finished and will
+ // be recycled (deleted) in KItemListView::slotAnimationFinished().
+ m_visibleItems.remove(i);
+ widget->setIndex(-1);
+ m_animation->start(widget, KItemListViewAnimation::DeleteAnimation);
+ }
+ }
+
+ // Update the indexes of all KItemListWidget instances that are located
+ // after the deleted items
+ for (int i = lastRemovedIndex + 1; i <= lastIndex; ++i) {
+ KItemListWidget* widget = m_visibleItems.value(i);
+ if (widget) {
+ const int newIndex = i - count;
+ setWidgetIndex(widget, newIndex);
+ }
+ }
+
+ m_layouter->markAsDirty();
+ if (!hasMultipleRanges) {
+ doLayout(Animation, index, -count);
+ update();
+ }
+
+ /*KItemListSelectionManager* selectionManager = m_controller->selectionManager();
+ const int current = selectionManager->currentItem();
+ if (count() <= 0) {
+ selectionManager->setCurrentItem(-1);
+ } else if (current >= index) {
+ selectionManager->setCurrentItem(current + count);
+ }*/
+ }
+
+ if (hasMultipleRanges) {
+ endTransaction();
+ }
+}
+
+void KItemListView::slotItemsChanged(const KItemRangeList& itemRanges,
+ const QSet<QByteArray>& roles)
+{
+ foreach (const KItemRange& itemRange, itemRanges) {
+ const int index = itemRange.index;
+ const int count = itemRange.count;
+
+ m_sizeHintResolver->itemsChanged(index, count, roles);
+
+ const int lastIndex = index + count - 1;
+ for (int i = index; i <= lastIndex; ++i) {
+ KItemListWidget* widget = m_visibleItems.value(i);
+ if (widget) {
+ widget->setData(m_model->data(i), roles);
+ }
+ }
+ }
+}
+
+void KItemListView::slotAnimationFinished(QGraphicsWidget* widget,
+ KItemListViewAnimation::AnimationType type)
+{
+ KItemListWidget* itemListWidget = qobject_cast<KItemListWidget*>(widget);
+ Q_ASSERT(itemListWidget);
+
+ switch (type) {
+ case KItemListViewAnimation::DeleteAnimation: {
+ // As we recycle the widget in this case it is important to assure that no
+ // other animation has been started. This is a convention in KItemListView and
+ // not a requirement defined by KItemListViewAnimation.
+ Q_ASSERT(!m_animation->isStarted(itemListWidget));
+
+ // All KItemListWidgets that are animated by the DeleteAnimation are not maintained
+ // by m_visibleWidgets and must be deleted manually after the animation has
+ // been finished.
+ KItemListGroupHeader* header = m_visibleGroups.value(itemListWidget);
+ if (header) {
+ m_groupHeaderCreator->recycle(header);
+ m_visibleGroups.remove(itemListWidget);
+ }
+ m_widgetCreator->recycle(itemListWidget);
+ break;
+ }
+
+ case KItemListViewAnimation::CreateAnimation:
+ case KItemListViewAnimation::MovingAnimation:
+ case KItemListViewAnimation::ResizeAnimation: {
+ const int index = itemListWidget->index();
+ const bool invisible = (index < m_layouter->firstVisibleIndex()) ||
+ (index > m_layouter->lastVisibleIndex());
+ if (invisible && !m_animation->isStarted(itemListWidget)) {
+ recycleWidget(itemListWidget);
+ }
+ break;
+ }
+
+ default: break;
+ }
+}
+
+void KItemListView::slotLayoutTimerFinished()
+{
+ m_layouter->setSize(geometry().size());
+ doLayout(Animation, 0, 0);
+}
+
+void KItemListView::setController(KItemListController* controller)
+{
+ if (m_controller != controller) {
+ KItemListController* previous = m_controller;
+ m_controller = controller;
+ onControllerChanged(controller, previous);
+ }
+}
+
+void KItemListView::setModel(KItemModelBase* model)
+{
+ if (m_model == model) {
+ return;
+ }
+
+ KItemModelBase* previous = m_model;
+
+ if (m_model) {
+ disconnect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet<QByteArray>)),
+ this, SLOT(slotItemsChanged(KItemRangeList,QSet<QByteArray>)));
+ disconnect(m_model, SIGNAL(itemsInserted(KItemRangeList)),
+ this, SLOT(slotItemsInserted(KItemRangeList)));
+ disconnect(m_model, SIGNAL(itemsRemoved(KItemRangeList)),
+ this, SLOT(slotItemsRemoved(KItemRangeList)));
+ }
+
+ m_model = model;
+ m_layouter->setModel(model);
+ m_grouped = !model->groupRole().isEmpty();
+
+ if (m_model) {
+ connect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet<QByteArray>)),
+ this, SLOT(slotItemsChanged(KItemRangeList,QSet<QByteArray>)));
+ connect(m_model, SIGNAL(itemsInserted(KItemRangeList)),
+ this, SLOT(slotItemsInserted(KItemRangeList)));
+ connect(m_model, SIGNAL(itemsRemoved(KItemRangeList)),
+ this, SLOT(slotItemsRemoved(KItemRangeList)));
+ }
+
+ onModelChanged(model, previous);
+}
+
+void KItemListView::updateLayout()
+{
+ doLayout(Animation, 0, 0);
+ update();
+}
+
+void KItemListView::doLayout(LayoutAnimationHint hint, int changedIndex, int changedCount)
+{
+ if (m_layoutTimer->isActive()) {
+ kDebug() << "Stopping layout timer, synchronous layout requested";
+ m_layoutTimer->stop();
+ }
+
+ if (m_model->count() < 0 || m_activeTransactions > 0) {
+ return;
+ }
+
+ applyDynamicItemSize();
+
+ const int firstVisibleIndex = m_layouter->firstVisibleIndex();
+ const int lastVisibleIndex = m_layouter->lastVisibleIndex();
+ if (firstVisibleIndex < 0) {
+ emitOffsetChanges();
+ return;
+ }
+
+ // Do a sanity check of the offset-property: When properties of the itemlist-view have been changed
+ // it might be possible that the maximum offset got changed too. Assure that the full visible range
+ // is still shown if the maximum offset got decreased.
+ const qreal visibleOffsetRange = (scrollOrientation() == Qt::Horizontal) ? size().width() : size().height();
+ const qreal maxOffsetToShowFullRange = maximumOffset() - visibleOffsetRange;
+ if (offset() > maxOffsetToShowFullRange) {
+ m_layouter->setOffset(qMax(qreal(0), maxOffsetToShowFullRange));
+ }
+
+ // Determine all items that are completely invisible and might be
+ // reused for items that just got (at least partly) visible.
+ // Items that do e.g. an animated moving of their position are not
+ // marked as invisible: This assures that a scrolling inside the view
+ // can be done without breaking an animation.
+ QList<int> reusableItems;
+ QHashIterator<int, KItemListWidget*> it(m_visibleItems);
+ while (it.hasNext()) {
+ it.next();
+ KItemListWidget* widget = it.value();
+ const int index = widget->index();
+ const bool invisible = (index < firstVisibleIndex) || (index > lastVisibleIndex);
+ if (invisible && !m_animation->isStarted(widget)) {
+ widget->setVisible(false);
+ reusableItems.append(index);
+ }
+ }
+
+ // Assure that for each visible item a KItemListWidget is available. KItemListWidget
+ // instances from invisible items are reused. If no reusable items are
+ // found then new KItemListWidget instances get created.
+ const bool animate = (hint == Animation);
+ for (int i = firstVisibleIndex; i <= lastVisibleIndex; ++i) {
+ bool applyNewPos = true;
+ bool wasHidden = false;
+
+ const QRectF itemBounds = m_layouter->itemBoundingRect(i);
+ const QPointF newPos = itemBounds.topLeft();
+ KItemListWidget* widget = m_visibleItems.value(i);
+ if (!widget) {
+ wasHidden = true;
+ if (!reusableItems.isEmpty()) {
+ // Reuse a KItemListWidget instance from an invisible item
+ const int oldIndex = reusableItems.takeLast();
+ widget = m_visibleItems.value(oldIndex);
+ setWidgetIndex(widget, i);
+ } else {
+ // No reusable KItemListWidget instance is available, create a new one
+ widget = createWidget(i);
+ }
+ widget->resize(itemBounds.size());
+
+ if (animate && changedCount < 0) {
+ // Items have been deleted, move the created item to the
+ // imaginary old position.
+ const QRectF itemBoundingRect = m_layouter->itemBoundingRect(i - changedCount);
+ if (itemBoundingRect.isEmpty()) {
+ const QPointF invisibleOldPos = (scrollOrientation() == Qt::Vertical)
+ ? QPointF(0, size().height()) : QPointF(size().width(), 0);
+ widget->setPos(invisibleOldPos);
+ } else {
+ widget->setPos(itemBoundingRect.topLeft());
+ }
+ applyNewPos = false;
+ }
+ } else if (m_animation->isStarted(widget, KItemListViewAnimation::MovingAnimation)) {
+ applyNewPos = false;
+ }
+
+ if (animate) {
+ const bool itemsRemoved = (changedCount < 0);
+ const bool itemsInserted = (changedCount > 0);
+
+ if (itemsRemoved && (i >= changedIndex + changedCount + 1)) {
+ // The item is located after the removed items. Animate the moving of the position.
+ m_animation->start(widget, KItemListViewAnimation::MovingAnimation, newPos);
+ applyNewPos = false;
+ } else if (itemsInserted && i >= changedIndex) {
+ // The item is located after the first inserted item
+ if (i <= changedIndex + changedCount - 1) {
+ // The item is an inserted item. Animate the appearing of the item.
+ // For performance reasons no animation is done when changedCount is equal
+ // to all available items.
+ if (changedCount < m_model->count()) {
+ m_animation->start(widget, KItemListViewAnimation::CreateAnimation);
+ }
+ } else if (!m_animation->isStarted(widget, KItemListViewAnimation::CreateAnimation)) {
+ // The item was already there before, so animate the moving of the position.
+ // No moving animation is done if the item is animated by a create animation: This
+ // prevents a "move animation mess" when inserting several ranges in parallel.
+ m_animation->start(widget, KItemListViewAnimation::MovingAnimation, newPos);
+ applyNewPos = false;
+ }
+ } else if (!itemsRemoved && !itemsInserted && !wasHidden) {
+ // The size of the view might have been changed. Animate the moving of the position.
+ m_animation->start(widget, KItemListViewAnimation::MovingAnimation, newPos);
+ applyNewPos = false;
+ }
+ }
+
+ if (applyNewPos) {
+ widget->setPos(newPos);
+ }
+
+ Q_ASSERT(widget->index() == i);
+ widget->setVisible(true);
+
+ if (widget->size() != itemBounds.size()) {
+ m_animation->start(widget, KItemListViewAnimation::ResizeAnimation, itemBounds.size());
+ }
+ }
+
+ // Delete invisible KItemListWidget instances that have not been reused
+ foreach (int index, reusableItems) {
+ recycleWidget(m_visibleItems.value(index));
+ }
+
+ emitOffsetChanges();
+}
+
+void KItemListView::emitOffsetChanges()
+{
+ const int newOffset = m_layouter->offset();
+ if (m_oldOffset != newOffset) {
+ emit offsetChanged(newOffset, m_oldOffset);
+ m_oldOffset = newOffset;
+ }
+
+ const int newMaximumOffset = m_layouter->maximumOffset();
+ if (m_oldMaximumOffset != newMaximumOffset) {
+ emit maximumOffsetChanged(newMaximumOffset, m_oldMaximumOffset);
+ m_oldMaximumOffset = newMaximumOffset;
+ }
+}
+
+KItemListWidget* KItemListView::createWidget(int index)
+{
+ KItemListWidget* widget = m_widgetCreator->create(this);
+ widget->setVisibleRoles(m_visibleRoles);
+ widget->setVisibleRolesSizes(m_visibleRolesSizes);
+ widget->setStyleOption(m_styleOption);
+ widget->setIndex(index);
+ widget->setData(m_model->data(index));
+ m_visibleItems.insert(index, widget);
+
+ if (m_grouped) {
+ if (m_layouter->isFirstGroupItem(index)) {
+ KItemListGroupHeader* header = m_groupHeaderCreator->create(widget);
+ header->setPos(0, -50);
+ header->resize(50, 50);
+ m_visibleGroups.insert(widget, header);
+ }
+ }
+
+ initializeItemListWidget(widget);
+ return widget;
+}
+
+void KItemListView::recycleWidget(KItemListWidget* widget)
+{
+ if (m_grouped) {
+ KItemListGroupHeader* header = m_visibleGroups.value(widget);
+ if (header) {
+ m_groupHeaderCreator->recycle(header);
+ m_visibleGroups.remove(widget);
+ }
+ }
+
+ m_visibleItems.remove(widget->index());
+ m_widgetCreator->recycle(widget);
+}
+
+void KItemListView::setWidgetIndex(KItemListWidget* widget, int index)
+{
+ if (m_grouped) {
+ bool createHeader = m_layouter->isFirstGroupItem(index);
+ KItemListGroupHeader* header = m_visibleGroups.value(widget);
+ if (header) {
+ if (createHeader) {
+ createHeader = false;
+ } else {
+ m_groupHeaderCreator->recycle(header);
+ m_visibleGroups.remove(widget);
+ }
+ }
+
+ if (createHeader) {
+ KItemListGroupHeader* header = m_groupHeaderCreator->create(widget);
+ header->setPos(0, -50);
+ header->resize(50, 50);
+ m_visibleGroups.insert(widget, header);
+ }
+ }
+
+ const int oldIndex = widget->index();
+ m_visibleItems.remove(oldIndex);
+ widget->setVisibleRoles(m_visibleRoles);
+ widget->setVisibleRolesSizes(m_visibleRolesSizes);
+ widget->setStyleOption(m_styleOption);
+ widget->setIndex(index);
+ widget->setData(m_model->data(index));
+ m_visibleItems.insert(index, widget);
+
+ initializeItemListWidget(widget);
+}
+
+void KItemListView::prepareLayoutForIncreasedItemCount(const QSizeF& size, SizeType sizeType)
+{
+ // Calculate the first visible index and last visible index for the current size
+ const int currentFirst = m_layouter->firstVisibleIndex();
+ const int currentLast = m_layouter->lastVisibleIndex();
+
+ const QSizeF currentSize = (sizeType == LayouterSize) ? m_layouter->size() : m_layouter->itemSize();
+
+ // Calculate the first visible index and last visible index for the new size
+ setLayouterSize(size, sizeType);
+ const int newFirst = m_layouter->firstVisibleIndex();
+ const int newLast = m_layouter->lastVisibleIndex();
+
+ if ((currentFirst != newFirst) || (currentLast != newLast)) {
+ // At least one index has been changed. Assure that widgets for all possible
+ // visible items get created so that a move-animation can be started later.
+ const int maxVisibleItems = m_layouter->maximumVisibleItems();
+ int minFirst = qMin(newFirst, currentFirst);
+ const int maxLast = qMax(newLast, currentLast);
+
+ if (maxLast - minFirst + 1 < maxVisibleItems) {
+ // Increasing the size might result in a smaller KItemListView::offset().
+ // Decrease the first visible index in a way that at least the maximum
+ // visible items are shown.
+ minFirst = qMax(0, maxLast - maxVisibleItems + 1);
+ }
+
+ if (maxLast - minFirst > maxVisibleItems + maxVisibleItems / 2) {
+ // The creating of widgets is quite expensive. Assure that never more
+ // than 50 % of the maximum visible items get created for the animations.
+ return;
+ }
+
+ setLayouterSize(currentSize, sizeType);
+ for (int i = minFirst; i <= maxLast; ++i) {
+ if (!m_visibleItems.contains(i)) {
+ KItemListWidget* widget = createWidget(i);
+ const QPointF pos = m_layouter->itemBoundingRect(i).topLeft();
+ widget->setPos(pos);
+ }
+ }
+ setLayouterSize(size, sizeType);
+ }
+}
+
+void KItemListView::setLayouterSize(const QSizeF& size, SizeType sizeType)
+{
+ switch (sizeType) {
+ case LayouterSize: m_layouter->setSize(size); break;
+ case ItemSize: m_layouter->setItemSize(size); break;
+ default: break;
+ }
+}
+
+bool KItemListView::markVisibleRolesSizesAsDirty()
+{
+ const bool dirty = m_itemSize.isEmpty();
+ if (dirty) {
+ m_visibleRolesSizes.clear();
+ m_layouter->setItemSize(QSizeF());
+ }
+ return dirty;
+}
+
+void KItemListView::applyDynamicItemSize()
+{
+ if (!m_itemSize.isEmpty()) {
+ return;
+ }
+
+ if (m_visibleRolesSizes.isEmpty()) {
+ m_visibleRolesSizes = visibleRoleSizes();
+ foreach (KItemListWidget* widget, visibleItemListWidgets()) {
+ widget->setVisibleRolesSizes(m_visibleRolesSizes);
+ }
+ }
+
+ if (m_layouter->itemSize().isEmpty()) {
+ qreal requiredWidth = 0;
+ qreal requiredHeight = 0;
+
+ QHashIterator<QByteArray, QSizeF> it(m_visibleRolesSizes);
+ while (it.hasNext()) {
+ it.next();
+ const QSizeF& visibleRoleSize = it.value();
+ requiredWidth += visibleRoleSize.width();
+ requiredHeight += visibleRoleSize.height();
+ }
+
+ QSizeF dynamicItemSize = m_itemSize;
+ if (dynamicItemSize.width() <= 0) {
+ dynamicItemSize.setWidth(qMax(requiredWidth, size().width()));
+ }
+ if (dynamicItemSize.height() <= 0) {
+ dynamicItemSize.setHeight(qMax(requiredHeight, size().height()));
+ }
+
+ m_layouter->setItemSize(dynamicItemSize);
+ }
+}
+
+KItemListCreatorBase::~KItemListCreatorBase()
+{
+ qDeleteAll(m_recycleableWidgets);
+ qDeleteAll(m_createdWidgets);
+}
+
+void KItemListCreatorBase::addCreatedWidget(QGraphicsWidget* widget)
+{
+ m_createdWidgets.insert(widget);
+}
+
+void KItemListCreatorBase::pushRecycleableWidget(QGraphicsWidget* widget)
+{
+ Q_ASSERT(m_createdWidgets.contains(widget));
+ m_createdWidgets.remove(widget);
+
+ if (m_recycleableWidgets.count() < 100) {
+ m_recycleableWidgets.append(widget);
+ widget->setVisible(false);
+ } else {
+ delete widget;
+ }
+}
+
+QGraphicsWidget* KItemListCreatorBase::popRecycleableWidget()
+{
+ if (m_recycleableWidgets.isEmpty()) {
+ return 0;
+ }
+
+ QGraphicsWidget* widget = m_recycleableWidgets.takeLast();
+ m_createdWidgets.insert(widget);
+ return widget;
+}
+
+KItemListWidgetCreatorBase::~KItemListWidgetCreatorBase()
+{
+}
+
+void KItemListWidgetCreatorBase::recycle(KItemListWidget* widget)
+{
+ widget->setOpacity(1.0);
+ pushRecycleableWidget(widget);
+}
+
+KItemListGroupHeaderCreatorBase::~KItemListGroupHeaderCreatorBase()
+{
+}
+
+void KItemListGroupHeaderCreatorBase::recycle(KItemListGroupHeader* header)
+{
+ header->setOpacity(1.0);
+ pushRecycleableWidget(header);
+}
+
+#include "kitemlistview.moc"
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 KITEMLISTVIEW_H
+#define KITEMLISTVIEW_H
+
+#include <libdolphin_export.h>
+
+#include <kitemviews/kitemliststyleoption.h>
+#include <kitemviews/kitemlistviewanimation_p.h>
+#include <kitemviews/kitemlistwidget.h>
+#include <kitemviews/kitemmodelbase.h>
+#include <QGraphicsWidget>
+
+class KItemListController;
+class KItemListWidgetCreatorBase;
+class KItemListGroupHeader;
+class KItemListGroupHeaderCreatorBase;
+class KItemListSizeHintResolver;
+class KItemListViewAnimation;
+class KItemListViewLayouter;
+class KItemListWidget;
+class KItemListViewCreatorBase;
+class QTimer;
+
+/**
+ * @brief Represents the view of an item-list.
+ *
+ * The view is responsible for showing the items of the model within
+ * a GraphicsItem. Each visible item is represented by a KItemListWidget.
+ *
+ * The created view must be applied to the KItemListController with
+ * KItemListController::setView(). For showing a custom model it is not
+ * mandatory to derive from KItemListView, all that is necessary is
+ * to set a widget-creator that is capable to create KItemListWidgets
+ * showing the model items. A widget-creator can be set with
+ * KItemListView::setWidgetCreator().
+ *
+ * @see KItemListWidget
+ * @see KItemModelBase
+ */
+class LIBDOLPHINPRIVATE_EXPORT KItemListView : public QGraphicsWidget
+{
+ Q_OBJECT
+
+public:
+ KItemListView(QGraphicsWidget* parent = 0);
+ virtual ~KItemListView();
+
+ void setScrollOrientation(Qt::Orientation orientation);
+ Qt::Orientation scrollOrientation() const;
+
+ void setItemSize(const QSizeF& size);
+ QSizeF itemSize() const;
+
+ // TODO: add note that offset is not checked against maximumOffset, only against 0.
+ void setOffset(qreal offset);
+ qreal offset() const;
+
+ qreal maximumOffset() const;
+
+ /**
+ * Sets the visible roles to \p roles. The integer-value defines
+ * the order of the visible role: Smaller values are ordered first.
+ */
+ void setVisibleRoles(const QHash<QByteArray, int>& roles);
+ QHash<QByteArray, int> visibleRoles() const;
+
+ /**
+ * @return Controller of the item-list. The controller gets
+ * initialized by KItemListController::setView() and will
+ * result in calling KItemListController::onControllerChanged().
+ */
+ KItemListController* controller() const;
+
+ /**
+ * @return Model of the item-list. The model gets
+ * initialized by KItemListController::setView() and will
+ * result in calling KItemListController::onModelChanged().
+ */
+ KItemModelBase* model() const;
+
+ /**
+ * Sets the creator that creates a widget showing the
+ * content of one model-item. Usually it is sufficient
+ * to implement a custom widget X derived from KItemListWidget and
+ * set the creator by:
+ * <code>
+ * itemListView->setWidgetCreator(new KItemListWidgetCreator<X>());
+ * </code>
+ * Note that the ownership of the widget creator is not transferred to
+ * the item-list view: One instance of a widget creator might get shared
+ * by several item-list view instances.
+ **/
+ void setWidgetCreator(KItemListWidgetCreatorBase* widgetCreator);
+ KItemListWidgetCreatorBase* widgetCreator() const;
+
+ void setGroupHeaderCreator(KItemListGroupHeaderCreatorBase* groupHeaderCreator);
+ KItemListGroupHeaderCreatorBase* groupHeaderCreator() const;
+
+ void setStyleOption(const KItemListStyleOption& option);
+ const KItemListStyleOption& styleOption() const;
+
+ virtual void setGeometry(const QRectF& rect);
+
+ int itemAt(const QPointF& pos) const;
+ bool isAboveSelectionToggle(int index, const QPointF& pos) const;
+ bool isAboveExpansionToggle(int index, const QPointF& pos) const;
+
+ int firstVisibleIndex() const;
+ int lastVisibleIndex() const;
+
+ virtual QSizeF itemSizeHint(int index) const;
+ virtual QHash<QByteArray, QSizeF> visibleRoleSizes() const;
+
+ void beginTransaction();
+ void endTransaction();
+ bool isTransactionActive() const;
+
+signals:
+ void offsetChanged(int current, int previous);
+ void maximumOffsetChanged(int current, int previous);
+
+protected:
+ virtual void initializeItemListWidget(KItemListWidget* item);
+
+ virtual void onControllerChanged(KItemListController* current, KItemListController* previous);
+ virtual void onModelChanged(KItemModelBase* current, KItemModelBase* previous);
+
+ virtual void onScrollOrientationChanged(Qt::Orientation current, Qt::Orientation previous);
+ virtual void onItemSizeChanged(const QSizeF& current, const QSizeF& previous);
+ virtual void onOffsetChanged(qreal current, qreal previous);
+ virtual void onVisibleRolesChanged(const QHash<QByteArray, int>& current, const QHash<QByteArray, int>& previous);
+ virtual void onStyleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous);
+
+ virtual void onTransactionBegin();
+ virtual void onTransactionEnd();
+
+ virtual bool event(QEvent* event);
+ virtual void mousePressEvent(QGraphicsSceneMouseEvent* event);
+ virtual void hoverMoveEvent(QGraphicsSceneHoverEvent* event);
+ virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent* event);
+
+ QList<KItemListWidget*> visibleItemListWidgets() const;
+
+protected slots:
+ virtual void slotItemsInserted(const KItemRangeList& itemRanges);
+ virtual void slotItemsRemoved(const KItemRangeList& itemRanges);
+ virtual void slotItemsChanged(const KItemRangeList& itemRanges,
+ const QSet<QByteArray>& roles);
+
+private slots:
+ void slotAnimationFinished(QGraphicsWidget* widget,
+ KItemListViewAnimation::AnimationType type);
+ void slotLayoutTimerFinished();
+
+private:
+ enum LayoutAnimationHint
+ {
+ NoAnimation,
+ Animation
+ };
+
+ enum SizeType
+ {
+ LayouterSize,
+ ItemSize
+ };
+
+ void setController(KItemListController* controller);
+ void setModel(KItemModelBase* model);
+
+ void updateLayout();
+ void doLayout(LayoutAnimationHint hint, int changedIndex, int changedCount);
+ void doGroupHeadersLayout(LayoutAnimationHint hint, int changedIndex, int changedCount);
+ void emitOffsetChanges();
+
+ KItemListWidget* createWidget(int index);
+ void recycleWidget(KItemListWidget* widget);
+ void setWidgetIndex(KItemListWidget* widget, int index);
+
+ /**
+ * Helper method for setGeometry() and setItemSize(): Calling both methods might result
+ * in a changed number of visible items. To assure that currently invisible items can
+ * get animated from the old position to the new position prepareLayoutForIncreasedItemCount()
+ * takes care to create all item widgets that are visible with the old or the new size.
+ * @param size Size of the layouter or the item dependent on \p sizeType.
+ * @param sizeType LayouterSize: KItemListLayouter::setSize() is used.
+ * ItemSize: KItemListLayouter::setItemSize() is used.
+ */
+ void prepareLayoutForIncreasedItemCount(const QSizeF& size, SizeType sizeType);
+
+ /**
+ * Helper method for prepareLayoutForIncreasedItemCount().
+ */
+ void setLayouterSize(const QSizeF& size, SizeType sizeType);
+
+ /**
+ * Marks the visible roles as dirty so that they will get updated when doing the next
+ * layout. The visible roles will only get marked as dirty if an empty item-size is
+ * given.
+ * @return True if the visible roles have been marked as dirty.
+ */
+ bool markVisibleRolesSizesAsDirty();
+
+ /**
+ * Updates the m_visibleRoleSizes property and applies the dynamic
+ * size to the layouter.
+ */
+ void applyDynamicItemSize();
+
+private:
+ bool m_grouped;
+ int m_activeTransactions; // Counter for beginTransaction()/endTransaction()
+
+ QSizeF m_itemSize;
+ KItemListController* m_controller;
+ KItemModelBase* m_model;
+ QHash<QByteArray, int> m_visibleRoles;
+ QHash<QByteArray, QSizeF> m_visibleRolesSizes;
+ KItemListWidgetCreatorBase* m_widgetCreator;
+ KItemListGroupHeaderCreatorBase* m_groupHeaderCreator;
+ KItemListStyleOption m_styleOption;
+
+ QHash<int, KItemListWidget*> m_visibleItems;
+ QHash<KItemListWidget*, KItemListGroupHeader*> m_visibleGroups;
+
+ int m_scrollBarExtent;
+ KItemListSizeHintResolver* m_sizeHintResolver;
+ KItemListViewLayouter* m_layouter;
+ KItemListViewAnimation* m_animation;
+
+ QTimer* m_layoutTimer; // Triggers an asynchronous doLayout() call.
+ int m_oldOffset;
+ int m_oldMaximumOffset;
+
+ friend class KItemListController;
+};
+
+/**
+ * Allows to do a fast logical creation and deletion of QGraphicsWidgets
+ * by recycling existing QGraphicsWidgets instances. Is used by
+ * KItemListWidgetCreatorBase and KItemListGroupHeaderCreatorBase.
+ * @internal
+ */
+class LIBDOLPHINPRIVATE_EXPORT KItemListCreatorBase
+{
+public:
+ virtual ~KItemListCreatorBase();
+
+protected:
+ void addCreatedWidget(QGraphicsWidget* widget);
+ void pushRecycleableWidget(QGraphicsWidget* widget);
+ QGraphicsWidget* popRecycleableWidget();
+
+private:
+ QSet<QGraphicsWidget*> m_createdWidgets;
+ QList<QGraphicsWidget*> m_recycleableWidgets;
+};
+
+/**
+ * @brief Base class for creating KItemListWidgets.
+ *
+ * It is recommended that applications simply use the KItemListWidgetCreator-template class.
+ * For a custom implementation the methods create() and recyle() must be reimplemented.
+ * The intention of the widget creator is to prevent repetitive and expensive instantiations and
+ * deletions of KItemListWidgets by recycling existing widget instances.
+ */
+class LIBDOLPHINPRIVATE_EXPORT KItemListWidgetCreatorBase : public KItemListCreatorBase
+{
+public:
+ virtual ~KItemListWidgetCreatorBase();
+ virtual KItemListWidget* create(KItemListView* view) = 0;
+ virtual void recycle(KItemListWidget* widget);
+};
+
+template <class T>
+class LIBDOLPHINPRIVATE_EXPORT KItemListWidgetCreator : public KItemListWidgetCreatorBase
+{
+public:
+ virtual ~KItemListWidgetCreator();
+ virtual KItemListWidget* create(KItemListView* view);
+};
+
+template <class T>
+KItemListWidgetCreator<T>::~KItemListWidgetCreator()
+{
+}
+
+template <class T>
+KItemListWidget* KItemListWidgetCreator<T>::create(KItemListView* view)
+{
+ KItemListWidget* widget = static_cast<KItemListWidget*>(popRecycleableWidget());
+ if (!widget) {
+ widget = new T(view);
+ addCreatedWidget(widget);
+ }
+ return widget;
+}
+
+/**
+ * @brief Base class for creating KItemListGroupHeaders.
+ *
+ * It is recommended that applications simply use the KItemListGroupHeaderCreator-template class.
+ * For a custom implementation the methods create() and recyle() must be reimplemented.
+ * The intention of the group-header creator is to prevent repetitive and expensive instantiations and
+ * deletions of KItemListGroupHeaders by recycling existing header instances.
+ */
+class LIBDOLPHINPRIVATE_EXPORT KItemListGroupHeaderCreatorBase : public KItemListCreatorBase
+{
+public:
+ virtual ~KItemListGroupHeaderCreatorBase();
+ virtual KItemListGroupHeader* create(QGraphicsWidget* parent) = 0;
+ virtual void recycle(KItemListGroupHeader* header);
+};
+
+template <class T>
+class LIBDOLPHINPRIVATE_EXPORT KItemListGroupHeaderCreator : public KItemListGroupHeaderCreatorBase
+{
+public:
+ virtual ~KItemListGroupHeaderCreator();
+ virtual KItemListGroupHeader* create(QGraphicsWidget* parent);
+};
+
+template <class T>
+KItemListGroupHeaderCreator<T>::~KItemListGroupHeaderCreator()
+{
+}
+
+template <class T>
+KItemListGroupHeader* KItemListGroupHeaderCreator<T>::create(QGraphicsWidget* parent)
+{
+ KItemListGroupHeader* widget = static_cast<KItemListGroupHeader*>(popRecycleableWidget());
+ if (!widget) {
+ widget = new T(parent);
+ addCreatedWidget(widget);
+ }
+ return widget;
+}
+
+#endif
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 <KDebug>
+
+#include <QGraphicsWidget>
+#include <QPropertyAnimation>
+
+KItemListViewAnimation::KItemListViewAnimation(QObject* parent) :
+ QObject(parent),
+ m_scrollOrientation(Qt::Vertical),
+ m_offset(0),
+ m_animation()
+{
+}
+
+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::setOffset(qreal offset)
+{
+ const qreal diff = m_offset - offset;
+ m_offset = 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<QGraphicsWidget*, QPropertyAnimation*> 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::offset() const
+{
+ return m_offset;
+}
+
+void KItemListViewAnimation::start(QGraphicsWidget* widget, AnimationType type, const QVariant& endValue)
+{
+ stop(widget, type);
+
+ const int duration = 200;
+ QPropertyAnimation* propertyAnim = 0;
+
+ switch (type) {
+ case MovingAnimation: {
+ const QPointF newPos = endValue.toPointF();
+ if (newPos == widget->pos()) {
+ return;
+ }
+
+ propertyAnim = new QPropertyAnimation(widget, "pos");
+ propertyAnim->setDuration(duration);
+ propertyAnim->setEndValue(newPos);
+ break;
+ }
+
+ case CreateAnimation: {
+ propertyAnim = new QPropertyAnimation(widget, "opacity");
+ propertyAnim->setEasingCurve(QEasingCurve::InQuart);
+ propertyAnim->setDuration(duration);
+ propertyAnim->setStartValue(0.0);
+ propertyAnim->setEndValue(1.0);
+ break;
+ }
+
+ case DeleteAnimation: {
+ propertyAnim = new QPropertyAnimation(widget, "opacity");
+ propertyAnim->setEasingCurve(QEasingCurve::OutQuart);
+ propertyAnim->setDuration(duration);
+ 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(duration);
+ 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<AnimationType>(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<AnimationType>(type))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void KItemListViewAnimation::slotFinished()
+{
+ QPropertyAnimation* finishedAnim = qobject_cast<QPropertyAnimation*>(sender());
+ for (int type = 0; type < AnimationTypeCount; ++type) {
+ QHashIterator<QGraphicsWidget*, QPropertyAnimation*> 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<AnimationType>(type));
+ return;
+ }
+ }
+ }
+ Q_ASSERT(false);
+}
+
+#include "kitemlistviewanimation_p.moc"
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 <libdolphin_export.h>
+
+#include <QHash>
+#include <QObject>
+#include <QVariant>
+
+class KItemListView;
+class QGraphicsWidget;
+class QPointF;
+class QPropertyAnimation;
+
+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 setOffset(qreal offset);
+ qreal offset() const;
+
+ void start(QGraphicsWidget* widget, AnimationType type, const QVariant& endValue = QVariant());
+
+ void stop(QGraphicsWidget* widget, AnimationType type);
+ void stop(QGraphicsWidget* widget);
+
+ bool isStarted(QGraphicsWidget *widget, AnimationType type) const;
+ bool isStarted(QGraphicsWidget* widget) const;
+
+signals:
+ void finished(QGraphicsWidget* widget, KItemListViewAnimation::AnimationType type);
+
+private slots:
+ void slotFinished();
+
+private:
+ enum { AnimationTypeCount = 4 };
+
+ Qt::Orientation m_scrollOrientation;
+ qreal m_offset;
+ QHash<QGraphicsWidget*, QPropertyAnimation*> m_animation[AnimationTypeCount];
+};
+
+#endif
+
+
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 <KDebug>
+
+#define KITEMLISTVIEWLAYOUTER_DEBUG
+
+namespace {
+ // TODO
+ const int HeaderHeight = 50;
+};
+
+KItemListViewLayouter::KItemListViewLayouter(QObject* parent) :
+ QObject(parent),
+ m_dirty(true),
+ m_visibleIndexesDirty(true),
+ m_grouped(false),
+ m_scrollOrientation(Qt::Vertical),
+ m_size(),
+ m_itemSize(128, 128),
+ m_model(0),
+ m_sizeHintResolver(0),
+ m_offset(0),
+ m_maximumOffset(0),
+ m_firstVisibleIndex(-1),
+ m_lastVisibleIndex(-1),
+ m_firstVisibleGroupIndex(-1),
+ m_columnWidth(0),
+ m_xPosInc(0),
+ m_columnCount(0),
+ m_groups(),
+ m_groupIndexes(),
+ m_itemBoundingRects()
+{
+}
+
+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::setOffset(qreal offset)
+{
+ if (m_offset != offset) {
+ m_offset = offset;
+ m_visibleIndexesDirty = true;
+ }
+}
+
+qreal KItemListViewLayouter::offset() const
+{
+ return m_offset;
+}
+
+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;
+}
+
+qreal KItemListViewLayouter::maximumOffset() const
+{
+ const_cast<KItemListViewLayouter*>(this)->doLayout();
+ return m_maximumOffset;
+}
+
+int KItemListViewLayouter::firstVisibleIndex() const
+{
+ const_cast<KItemListViewLayouter*>(this)->doLayout();
+ return m_firstVisibleIndex;
+}
+
+int KItemListViewLayouter::lastVisibleIndex() const
+{
+ const_cast<KItemListViewLayouter*>(this)->doLayout();
+ return m_lastVisibleIndex;
+}
+
+QRectF KItemListViewLayouter::itemBoundingRect(int index) const
+{
+ const_cast<KItemListViewLayouter*>(this)->doLayout();
+ if (index < 0 || index >= m_itemBoundingRects.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_itemBoundingRects[index];
+ QRectF bounds(b.y(), b.x(), b.height(), b.width());
+ QPointF pos = bounds.topLeft();
+ pos.rx() -= m_offset;
+ bounds.moveTo(pos);
+ return bounds;
+ }
+
+ QRectF bounds = m_itemBoundingRects[index];
+ QPointF pos = bounds.topLeft();
+ pos.ry() -= m_offset;
+ bounds.moveTo(pos);
+ return bounds;
+}
+
+int KItemListViewLayouter::maximumVisibleItems() const
+{
+ const_cast<KItemListViewLayouter*>(this)->doLayout();
+
+ const int height = static_cast<int>(m_size.height());
+ const int rowHeight = static_cast<int>(m_itemSize.height());
+ int rows = height / rowHeight;
+ if (height % rowHeight != 0) {
+ ++rows;
+ }
+
+ return rows * m_columnCount;
+}
+
+bool KItemListViewLayouter::isFirstGroupItem(int itemIndex) const
+{
+ return m_groupIndexes.contains(itemIndex);
+}
+
+void KItemListViewLayouter::markAsDirty()
+{
+ m_dirty = true;
+}
+
+void KItemListViewLayouter::doLayout()
+{
+ if (m_dirty) {
+#ifdef KITEMLISTVIEWLAYOUTER_DEBUG
+ QElapsedTimer timer;
+ timer.start();
+#endif
+
+ m_visibleIndexesDirty = true;
+
+ QSizeF itemSize = m_itemSize;
+ QSizeF size = m_size;
+
+ const bool horizontalScrolling = (m_scrollOrientation == Qt::Horizontal);
+ if (horizontalScrolling) {
+ itemSize.setWidth(m_itemSize.height());
+ itemSize.setHeight(m_itemSize.width());
+ size.setWidth(m_size.height());
+ size.setHeight(m_size.width());
+ }
+
+ m_columnWidth = itemSize.width();
+ m_columnCount = qMax(1, int(size.width() / m_columnWidth));
+ m_xPosInc = 0;
+
+ const int itemCount = m_model->count();
+ if (itemCount > m_columnCount) {
+ // Apply the unused width equally to each column
+ const qreal unusedWidth = size.width() - m_columnCount * m_columnWidth;
+ 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_itemBoundingRects.reserve(itemCount);
+
+ qreal y = 0;
+ int rowIndex = 0;
+
+ int index = 0;
+ while (index < itemCount) {
+ qreal x = m_xPosInc;
+ qreal maxItemHeight = itemSize.height();
+
+ 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_itemBoundingRects.count()) {
+ m_itemBoundingRects[index] = bounds;
+ } else {
+ m_itemBoundingRects.append(bounds);
+ }
+
+ maxItemHeight = qMax(maxItemHeight, requiredItemHeight);
+ x += m_columnWidth;
+ ++index;
+ ++column;
+ }
+
+ y += maxItemHeight;
+ ++rowIndex;
+ }
+ if (m_itemBoundingRects.count() > itemCount) {
+ m_itemBoundingRects.erase(m_itemBoundingRects.begin() + itemCount,
+ m_itemBoundingRects.end());
+ }
+
+ m_maximumOffset = (itemCount > 0) ? m_itemBoundingRects.last().bottom() : 0;
+
+ m_grouped = !m_model->groupRole().isEmpty();
+ /*if (m_grouped) {
+ createGroupHeaders();
+
+ const int lastGroupItemCount = m_model->count() - m_groups.last().firstItemIndex;
+ m_maximumOffset = m_groups.last().y + (lastGroupItemCount / m_columnCount) * m_rowHeight;
+ if (lastGroupItemCount % m_columnCount != 0) {
+ m_maximumOffset += m_rowHeight;
+ }
+ } else {*/
+ // m_maximumOffset = m_minimumRowHeight * rowCount;
+ //}
+
+#ifdef KITEMLISTVIEWLAYOUTER_DEBUG
+ kDebug() << "[TIME] doLayout() for " << m_model->count() << "items:" << timer.elapsed();
+#endif
+ m_dirty = false;
+ }
+
+ if (m_grouped) {
+ updateGroupedVisibleIndexes();
+ } else {
+ updateVisibleIndexes();
+ }
+}
+
+void KItemListViewLayouter::updateVisibleIndexes()
+{
+ if (!m_visibleIndexesDirty) {
+ return;
+ }
+
+ Q_ASSERT(!m_grouped);
+ Q_ASSERT(!m_dirty);
+
+ if (m_model->count() <= 0) {
+ m_firstVisibleIndex = -1;
+ m_lastVisibleIndex = -1;
+ m_visibleIndexesDirty = false;
+ return;
+ }
+
+ const bool horizontalScrolling = (m_scrollOrientation == Qt::Horizontal);
+ const int minimumHeight = horizontalScrolling ? m_itemSize.width()
+ : m_itemSize.height();
+
+ // Calculate the first visible index:
+ // 1. Guess the index by using the minimum row height
+ const int maxIndex = m_model->count() - 1;
+ m_firstVisibleIndex = int(m_offset / minimumHeight) * m_columnCount;
+
+ // 2. Decrease the index by checking the real row heights
+ int prevRowIndex = m_firstVisibleIndex - m_columnCount;
+ while (prevRowIndex > maxIndex) {
+ prevRowIndex -= m_columnCount;
+ }
+
+ while (prevRowIndex >= 0 && m_itemBoundingRects[prevRowIndex].bottom() >= m_offset) {
+ m_firstVisibleIndex = prevRowIndex;
+ prevRowIndex -= m_columnCount;
+ }
+ m_firstVisibleIndex = qBound(0, m_firstVisibleIndex, maxIndex);
+
+ // Calculate the last visible index
+ const int visibleHeight = horizontalScrolling ? m_size.width() : m_size.height();
+ const qreal bottom = m_offset + visibleHeight;
+ m_lastVisibleIndex = m_firstVisibleIndex; // first visible row, first column
+ int nextRowIndex = m_lastVisibleIndex + m_columnCount;
+ while (nextRowIndex <= maxIndex && m_itemBoundingRects[nextRowIndex].y() <= bottom) {
+ m_lastVisibleIndex = nextRowIndex;
+ nextRowIndex += m_columnCount;
+ }
+ m_lastVisibleIndex += m_columnCount - 1; // move it to the last column
+ m_lastVisibleIndex = qBound(0, m_lastVisibleIndex, maxIndex);
+
+ m_visibleIndexesDirty = false;
+}
+
+void KItemListViewLayouter::updateGroupedVisibleIndexes()
+{
+ if (!m_visibleIndexesDirty) {
+ return;
+ }
+
+ Q_ASSERT(m_grouped);
+ Q_ASSERT(!m_dirty);
+
+ if (m_model->count() <= 0) {
+ m_firstVisibleIndex = -1;
+ m_lastVisibleIndex = -1;
+ m_visibleIndexesDirty = false;
+ return;
+ }
+
+ // Find the first visible group
+ const int lastGroupIndex = m_groups.count() - 1;
+ int groupIndex = lastGroupIndex;
+ for (int i = 1; i < m_groups.count(); ++i) {
+ if (m_groups[i].y >= m_offset) {
+ groupIndex = i - 1;
+ break;
+ }
+ }
+
+ // Calculate the first visible index
+ qreal groupY = m_groups[groupIndex].y;
+ m_firstVisibleIndex = m_groups[groupIndex].firstItemIndex;
+ const int invisibleRowCount = int(m_offset - groupY) / int(m_itemSize.height());
+ m_firstVisibleIndex += invisibleRowCount * m_columnCount;
+ if (groupIndex + 1 <= lastGroupIndex) {
+ // Check whether the calculated first visible index remains inside the current
+ // group. If this is not the case let the first element of the next group be the first
+ // visible index.
+ const int nextGroupIndex = m_groups[groupIndex + 1].firstItemIndex;
+ if (m_firstVisibleIndex > nextGroupIndex) {
+ m_firstVisibleIndex = nextGroupIndex;
+ }
+ }
+
+ m_firstVisibleGroupIndex = groupIndex;
+
+ const int maxIndex = m_model->count() - 1;
+ m_firstVisibleIndex = qBound(0, m_firstVisibleIndex, maxIndex);
+
+ // Calculate the last visible index: Find group where the last visible item is shown.
+ const qreal visibleBottom = m_offset + m_size.height(); // TODO: respect Qt::Horizontal alignment
+ while ((groupIndex < lastGroupIndex) && (m_groups[groupIndex + 1].y < visibleBottom)) {
+ ++groupIndex;
+ }
+
+ groupY = m_groups[groupIndex].y;
+ m_lastVisibleIndex = m_groups[groupIndex].firstItemIndex;
+ const int availableHeight = static_cast<int>(visibleBottom - groupY);
+ int visibleRowCount = availableHeight / int(m_itemSize.height());
+ if (availableHeight % int(m_itemSize.height()) != 0) {
+ ++visibleRowCount;
+ }
+ m_lastVisibleIndex += visibleRowCount * m_columnCount - 1;
+
+ if (groupIndex + 1 <= lastGroupIndex) {
+ // Check whether the calculate last visible index remains inside the current group.
+ // If this is not the case let the last element of this group be the last visible index.
+ const int nextGroupIndex = m_groups[groupIndex + 1].firstItemIndex;
+ if (m_lastVisibleIndex >= nextGroupIndex) {
+ m_lastVisibleIndex = nextGroupIndex - 1;
+ }
+ }
+ //Q_ASSERT(m_lastVisibleIndex < m_model->count());
+ m_lastVisibleIndex = qBound(0, m_lastVisibleIndex, maxIndex);
+
+ m_visibleIndexesDirty = false;
+}
+
+void KItemListViewLayouter::createGroupHeaders()
+{
+ m_groups.clear();
+ m_groupIndexes.clear();
+
+ // TODO:
+ QList<int> numbers;
+ numbers << 0 << 5 << 6 << 13 << 20 << 25 << 30 << 35 << 50;
+
+ qreal y = 0;
+ for (int i = 0; i < numbers.count(); ++i) {
+ if (i > 0) {
+ const int previousGroupItemCount = numbers[i] - m_groups.last().firstItemIndex;
+ int previousGroupRowCount = previousGroupItemCount / m_columnCount;
+ if (previousGroupItemCount % m_columnCount != 0) {
+ ++previousGroupRowCount;
+ }
+ const qreal previousGroupHeight = previousGroupRowCount * m_itemSize.height();
+ y += previousGroupHeight;
+ }
+ y += HeaderHeight;
+
+ ItemGroup itemGroup;
+ itemGroup.firstItemIndex = numbers[i];
+ itemGroup.y = y;
+
+ m_groups.append(itemGroup);
+ m_groupIndexes.insert(itemGroup.firstItemIndex);
+ }
+}
+
+#include "kitemlistviewlayouter_p.moc"
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 <libdolphin_export.h>
+
+#include <QObject>
+#include <QRectF>
+#include <QSet>
+#include <QSizeF>
+
+class KItemModelBase;
+class KItemListSizeHintResolver;
+
+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;
+
+ // TODO: add note that offset can be < 0 or > maximumOffset!
+ void setOffset(qreal offset);
+ qreal offset() const;
+
+ void setModel(const KItemModelBase* model);
+ const KItemModelBase* model() const;
+
+ void setSizeHintResolver(const KItemListSizeHintResolver* sizeHintResolver);
+ const KItemListSizeHintResolver* sizeHintResolver() const;
+
+ qreal maximumOffset() const;
+
+ // TODO: mention that return value is -1 if count == 0
+ int firstVisibleIndex() const;
+
+ // TODO: mention that return value is -1 if count == 0
+ int lastVisibleIndex() const;
+
+ QRectF itemBoundingRect(int index) const;
+
+ 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;
+
+ void markAsDirty();
+
+private:
+ void doLayout();
+
+ void updateVisibleIndexes();
+ void updateGroupedVisibleIndexes();
+ void createGroupHeaders();
+
+private:
+ bool m_dirty;
+ bool m_visibleIndexesDirty;
+ bool m_grouped;
+
+ Qt::Orientation m_scrollOrientation;
+ QSizeF m_size;
+
+ QSizeF m_itemSize;
+ const KItemModelBase* m_model;
+ const KItemListSizeHintResolver* m_sizeHintResolver;
+
+ qreal m_offset;
+ qreal m_maximumOffset;
+
+ int m_firstVisibleIndex;
+ int m_lastVisibleIndex;
+
+ int m_firstVisibleGroupIndex;
+
+ qreal m_columnWidth;
+ qreal m_xPosInc;
+ int m_columnCount;
+
+ struct ItemGroup {
+ int firstItemIndex;
+ qreal y;
+ };
+ QList<ItemGroup> m_groups;
+
+ // Stores all item indexes that are the first item of a group.
+ // Assures fast access for KItemListViewLayouter::isFirstGroupItem().
+ QSet<int> m_groupIndexes;
+
+ QList<QRectF> m_itemBoundingRects;
+};
+
+#endif
+
+
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 "kitemlistwidget.h"
+
+#include "kitemlistview.h"
+#include "kitemmodelbase.h"
+
+#include <KDebug>
+
+#include <QPainter>
+#include <QPropertyAnimation>
+#include <QStyle>
+
+KItemListWidget::KItemListWidget(QGraphicsItem* parent) :
+ QGraphicsWidget(parent, 0),
+ m_index(-1),
+ m_data(),
+ m_visibleRoles(),
+ m_visibleRolesSizes(),
+ m_styleOption(),
+ m_hoverOpacity(0),
+ m_hoverCache(0),
+ m_hoverAnimation(0)
+{
+}
+
+KItemListWidget::~KItemListWidget()
+{
+ clearCache();
+}
+
+void KItemListWidget::setIndex(int index)
+{
+ if (m_index != index) {
+ if (m_hoverAnimation) {
+ m_hoverAnimation->stop();
+ m_hoverOpacity = 0;
+ }
+ clearCache();
+
+ m_index = index;
+ }
+}
+
+int KItemListWidget::index() const
+{
+ return m_index;
+}
+
+void KItemListWidget::setData(const QHash<QByteArray, QVariant>& data,
+ const QSet<QByteArray>& roles)
+{
+ clearCache();
+ if (roles.isEmpty()) {
+ m_data = data;
+ dataChanged(m_data);
+ } else {
+ foreach (const QByteArray& role, roles) {
+ m_data[role] = data[role];
+ }
+ dataChanged(m_data, roles);
+ }
+}
+
+QHash<QByteArray, QVariant> KItemListWidget::data() const
+{
+ return m_data;
+}
+
+void KItemListWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
+{
+ Q_UNUSED(option);
+ if (m_hoverOpacity <= 0.0) {
+ return;
+ }
+
+ const QRect hoverBounds = hoverBoundingRect().toRect();
+ if (!m_hoverCache) {
+ m_hoverCache = new QPixmap(hoverBounds.size());
+ m_hoverCache->fill(Qt::transparent);
+
+ QPainter pixmapPainter(m_hoverCache);
+
+ QStyleOptionViewItemV4 viewItemOption;
+ viewItemOption.initFrom(widget);
+ viewItemOption.rect = QRect(0, 0, hoverBounds.width(), hoverBounds.height());
+ viewItemOption.state = QStyle::State_Enabled | QStyle::State_MouseOver;
+ viewItemOption.viewItemPosition = QStyleOptionViewItemV4::OnlyOne;
+
+ widget->style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &viewItemOption, &pixmapPainter, widget);
+ }
+
+ const qreal opacity = painter->opacity();
+ painter->setOpacity(m_hoverOpacity * opacity);
+ painter->drawPixmap(hoverBounds.topLeft(), *m_hoverCache);
+ painter->setOpacity(opacity);
+}
+
+void KItemListWidget::setVisibleRoles(const QHash<QByteArray, int>& roles)
+{
+ const QHash<QByteArray, int> previousRoles = m_visibleRoles;
+ m_visibleRoles = roles;
+ visibleRolesChanged(roles, previousRoles);
+}
+
+QHash<QByteArray, int> KItemListWidget::visibleRoles() const
+{
+ return m_visibleRoles;
+}
+
+void KItemListWidget::setVisibleRolesSizes(const QHash<QByteArray, QSizeF> rolesSizes)
+{
+ const QHash<QByteArray, QSizeF> previousRolesSizes = m_visibleRolesSizes;
+ m_visibleRolesSizes = rolesSizes;
+ visibleRolesSizesChanged(rolesSizes, previousRolesSizes);
+}
+
+QHash<QByteArray, QSizeF> KItemListWidget::visibleRolesSizes() const
+{
+ return m_visibleRolesSizes;
+}
+
+void KItemListWidget::setStyleOption(const KItemListStyleOption& option)
+{
+ const KItemListStyleOption previous = m_styleOption;
+ if (m_index >= 0) {
+ clearCache();
+
+ const bool wasHovered = (previous.state & QStyle::State_MouseOver);
+ m_styleOption = option;
+ const bool isHovered = (m_styleOption.state & QStyle::State_MouseOver);
+
+ if (wasHovered != isHovered) {
+ // The hovering state has been changed. Assure that a fade-animation
+ // is done to the new state.
+ if (!m_hoverAnimation) {
+ m_hoverAnimation = new QPropertyAnimation(this, "hoverOpacity", this);
+ m_hoverAnimation->setDuration(200);
+ }
+ m_hoverAnimation->stop();
+
+ if (!wasHovered && isHovered) {
+ m_hoverAnimation->setEndValue(1.0);
+ } else {
+ Q_ASSERT(wasHovered && !isHovered);
+ m_hoverAnimation->setEndValue(0.0);
+ }
+
+ m_hoverAnimation->start();
+ }
+ } else {
+ m_styleOption = option;
+ }
+
+ styleOptionChanged(option, previous);
+}
+
+const KItemListStyleOption& KItemListWidget::styleOption() const
+{
+ return m_styleOption;
+}
+
+bool KItemListWidget::contains(const QPointF& point) const
+{
+ return hoverBoundingRect().contains(point) ||
+ expansionToggleRect().contains(point) ||
+ selectionToggleRect().contains(point);
+}
+
+QRectF KItemListWidget::hoverBoundingRect() const
+{
+ return QRectF(QPointF(0, 0), size());
+}
+
+QRectF KItemListWidget::selectionToggleRect() const
+{
+ return QRectF();
+}
+
+QRectF KItemListWidget::expansionToggleRect() const
+{
+ return QRectF();
+}
+
+void KItemListWidget::dataChanged(const QHash<QByteArray, QVariant>& current,
+ const QSet<QByteArray>& roles)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(roles);
+ update();
+}
+
+void KItemListWidget::visibleRolesChanged(const QHash<QByteArray, int>& current,
+ const QHash<QByteArray, int>& previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+ update();
+}
+
+void KItemListWidget::visibleRolesSizesChanged(const QHash<QByteArray, QSizeF>& current,
+ const QHash<QByteArray, QSizeF>& previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+ update();
+}
+
+void KItemListWidget::styleOptionChanged(const KItemListStyleOption& current,
+ const KItemListStyleOption& previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+ update();
+}
+
+void KItemListWidget::resizeEvent(QGraphicsSceneResizeEvent* event)
+{
+ QGraphicsWidget::resizeEvent(event);
+ clearCache();
+}
+
+qreal KItemListWidget::hoverOpacity() const
+{
+ return m_hoverOpacity;
+}
+
+void KItemListWidget::setHoverOpacity(qreal opacity)
+{
+ m_hoverOpacity = opacity;
+ update();
+}
+
+void KItemListWidget::clearCache()
+{
+ delete m_hoverCache;
+ m_hoverCache = 0;
+}
+
+#include "kitemlistwidget.moc"
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 KITEMLISTWIDGET_H
+#define KITEMLISTWIDGET_H
+
+#include <libdolphin_export.h>
+
+#include <kitemviews/kitemliststyleoption.h>
+
+#include <QGraphicsWidget>
+
+class QPropertyAnimation;
+
+/**
+ * @brief Widget that shows a visible item from the model.
+ *
+ * For showing an item from a custom model it is required to at least overwrite KItemListWidget::paint().
+ * All properties are set by KItemListView, for each property there is a corresponding
+ * virtual protected method that allows to react on property changes.
+ */
+class LIBDOLPHINPRIVATE_EXPORT KItemListWidget : public QGraphicsWidget
+{
+ Q_OBJECT
+
+public:
+ KItemListWidget(QGraphicsItem* parent);
+ virtual ~KItemListWidget();
+
+ void setIndex(int index);
+ int index() const;
+
+ void setData(const QHash<QByteArray, QVariant>& data, const QSet<QByteArray>& roles = QSet<QByteArray>());
+ QHash<QByteArray, QVariant> data() const;
+
+ /**
+ * Draws the hover-bounding-rectangle if the item is hovered. Overwrite this method
+ * to show the data of the custom model provided by KItemListWidget::data().
+ * @reimp
+ */
+ virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0);
+
+ /**
+ * Sets the visible roles to \p roles. The integer-value defines
+ * the order of the visible role: Smaller values are ordered first.
+ */
+ void setVisibleRoles(const QHash<QByteArray, int>& roles);
+ QHash<QByteArray, int> visibleRoles() const;
+
+ void setVisibleRolesSizes(const QHash<QByteArray, QSizeF> rolesSizes);
+ QHash<QByteArray, QSizeF> visibleRolesSizes() const;
+
+ void setStyleOption(const KItemListStyleOption& option);
+ const KItemListStyleOption& styleOption() const;
+
+ /**
+ * @return True if \a point is inside KItemListWidget::hoverBoundingRect(),
+ * KItemListWidget::selectionToggleRect() or KItemListWidget::expansionToggleRect().
+ * @reimp
+ */
+ virtual bool contains(const QPointF& point) const;
+
+ /**
+ * @return Bounding rectangle for the area that acts as hovering-area. Per default
+ * the bounding rectangle of the KItemListWidget is returned.
+ */
+ virtual QRectF hoverBoundingRect() const;
+
+ /**
+ * @return Rectangle for the selection-toggle that is used to select or deselect an item.
+ * Per default an empty rectangle is returned which means that no selection-toggle
+ * is available.
+ */
+ virtual QRectF selectionToggleRect() const;
+
+ /**
+ * @return Rectangle for the expansion-toggle that is used to open a sub-tree of the model.
+ * Per default an empty rectangle is returned which means that no opening of sub-trees
+ * is supported.
+ */
+ virtual QRectF expansionToggleRect() const;
+
+protected:
+ virtual void dataChanged(const QHash<QByteArray, QVariant>& current, const QSet<QByteArray>& roles = QSet<QByteArray>());
+ virtual void visibleRolesChanged(const QHash<QByteArray, int>& current, const QHash<QByteArray, int>& previous);
+ virtual void visibleRolesSizesChanged(const QHash<QByteArray, QSizeF>& current, const QHash<QByteArray, QSizeF>& previous);
+ virtual void styleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous);
+ virtual void resizeEvent(QGraphicsSceneResizeEvent* event);
+
+ /**
+ * @return The current opacity of the hover-animation. When implementing a custom painting-code for a hover-state
+ * this opacity value should be respected.
+ */
+ qreal hoverOpacity() const;
+
+private:
+ void setHoverOpacity(qreal opacity);
+ void clearCache();
+
+private:
+ Q_PROPERTY(qreal hoverOpacity READ hoverOpacity WRITE setHoverOpacity)
+
+ int m_index;
+ QHash<QByteArray, QVariant> m_data;
+ QHash<QByteArray, int> m_visibleRoles;
+ QHash<QByteArray, QSizeF> m_visibleRolesSizes;
+ KItemListStyleOption m_styleOption;
+
+ qreal m_hoverOpacity;
+ mutable QPixmap* m_hoverCache;
+ QPropertyAnimation* m_hoverAnimation;
+};
+#endif
+
+
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 "kitemmodelbase.h"
+
+KItemRange::KItemRange(int index, int count) :
+ index(index),
+ count(count)
+{
+}
+
+KItemModelBase::KItemModelBase(QObject* parent) :
+ QObject(parent),
+ m_groupRole(),
+ m_sortRole()
+{
+}
+
+KItemModelBase::KItemModelBase(const QByteArray& groupRole, const QByteArray& sortRole, QObject* parent) :
+ QObject(parent),
+ m_groupRole(groupRole),
+ m_sortRole(sortRole)
+{
+}
+
+KItemModelBase::~KItemModelBase()
+{
+}
+
+bool KItemModelBase::setData(int index, const QHash<QByteArray, QVariant> &values)
+{
+ Q_UNUSED(index);
+ Q_UNUSED(values);
+ return false;
+}
+
+bool KItemModelBase::supportsGrouping() const
+{
+ return false;
+}
+
+void KItemModelBase::setGroupRole(const QByteArray& role)
+{
+ if (supportsGrouping() && role != m_groupRole) {
+ const QByteArray previous = m_groupRole;
+ m_groupRole = role;
+ onGroupRoleChanged(role, previous);
+ emit groupRoleChanged(role, previous);
+ }
+}
+
+QByteArray KItemModelBase::groupRole() const
+{
+ return m_groupRole;
+}
+
+bool KItemModelBase::supportsSorting() const
+{
+ return false;
+}
+
+void KItemModelBase::setSortRole(const QByteArray& role)
+{
+ if (supportsSorting() && role != m_sortRole) {
+ const QByteArray previous = m_sortRole;
+ m_sortRole = role;
+ onSortRoleChanged(role, previous);
+ emit sortRoleChanged(role, previous);
+ }
+}
+
+QByteArray KItemModelBase::sortRole() const
+{
+ return m_sortRole;
+}
+
+QString KItemModelBase::roleDescription(const QByteArray& role) const
+{
+ return role;
+}
+
+void KItemModelBase::onGroupRoleChanged(const QByteArray& current, const QByteArray& previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+}
+
+void KItemModelBase::onSortRoleChanged(const QByteArray& current, const QByteArray& previous)
+{
+ Q_UNUSED(current);
+ Q_UNUSED(previous);
+}
+
+#include "kitemmodelbase.moc"
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 KITEMMODELBASE_H
+#define KITEMMODELBASE_H
+
+#include <libdolphin_export.h>
+
+#include <QHash>
+#include <QObject>
+#include <QSet>
+#include <QVariant>
+
+struct KItemRange
+{
+ KItemRange(int index, int count);
+ int index;
+ int count;
+};
+typedef QList<KItemRange> KItemRangeList;
+
+/**
+ * @brief Base class for model implementations used by KItemListView and KItemListController.
+ *
+ * A item-model consists of a variable number of items. The number of items
+ * is given by KItemModelBase::count(). The data of an item is accessed by a unique index
+ * with KItemModelBase::data(). The indexes are integer-values counting from 0 to the
+ * KItemModelBase::count() - 1.
+ *
+ * One item consists of a variable number of role/value-pairs.
+ *
+ * A model can optionally provide sorting- and/or grouping-capabilities.
+ */
+class LIBDOLPHINPRIVATE_EXPORT KItemModelBase : public QObject
+{
+ Q_OBJECT
+
+public:
+ KItemModelBase(QObject* parent = 0);
+ KItemModelBase(const QByteArray& groupRole, const QByteArray& sortRole, QObject* parent = 0);
+ virtual ~KItemModelBase();
+
+ /** @return The number of items. */
+ virtual int count() const = 0;
+
+ virtual QHash<QByteArray, QVariant> data(int index) const = 0;
+
+ /**
+ * Sets the data for the item at \a index to the given \a values. Returns true
+ * if the data was set on the item; returns false otherwise.
+ *
+ * The default implementation does not set the data, and will always return
+ * false.
+ */
+ virtual bool setData(int index, const QHash<QByteArray, QVariant>& values);
+
+ /**
+ * @return True if the model supports grouping of data. Per default false is returned.
+ * If the model should support grouping it is necessary to overwrite
+ * this method to return true and to implement KItemModelBase::onGroupRoleChanged().
+ */
+ virtual bool supportsGrouping() const;
+
+ /**
+ * Sets the group-role to \a role. The method KItemModelBase::onGroupRoleChanged() will be
+ * called so that model-implementations can react on the group-role change. Afterwards the
+ * signal groupRoleChanged() will be emitted.
+ */
+ void setGroupRole(const QByteArray& role);
+ QByteArray groupRole() const;
+
+ /**
+ * @return True if the model supports sorting of data. Per default false is returned.
+ * If the model should support sorting it is necessary to overwrite
+ * this method to return true and to implement KItemModelBase::onSortRoleChanged().
+ */
+ virtual bool supportsSorting() const;
+
+ /**
+ * Sets the sor-role to \a role. The method KItemModelBase::onSortRoleChanged() will be
+ * called so that model-implementations can react on the sort-role change. Afterwards the
+ * signal sortRoleChanged() will be emitted.
+ */
+ void setSortRole(const QByteArray& role);
+ QByteArray sortRole() const;
+
+ virtual QString roleDescription(const QByteArray& role) const;
+
+signals:
+ void itemsInserted(const KItemRangeList& itemRanges);
+ void itemsRemoved(const KItemRangeList& itemRanges);
+ void itemsMoved(const KItemRangeList& itemRanges);
+ void itemsChanged(const KItemRangeList& itemRanges, const QSet<QByteArray>& roles);
+
+ void groupRoleChanged(const QByteArray& current, const QByteArray& previous);
+ void sortRoleChanged(const QByteArray& current, const QByteArray& previous);
+
+protected:
+ /**
+ * Is invoked if the group role has been changed by KItemModelBase::setGroupRole(). Allows
+ * to react on the changed group role before the signal groupRoleChanged() will be emitted.
+ * The implementation must assure that the items are sorted in a way that they are grouped
+ * by the role given by \a current. Usually the most efficient way is to emit a
+ * itemsRemoved() signal for all items, reorder the items internally and to emit a
+ * itemsInserted() signal afterwards.
+ */
+ virtual void onGroupRoleChanged(const QByteArray& current, const QByteArray& previous);
+
+ /**
+ * Is invoked if the sort role has been changed by KItemModelBase::setSortRole(). Allows
+ * to react on the changed sort role before the signal sortRoleChanged() will be emitted.
+ * The implementation must assure that the items are sorted by the role given by \a current.
+ * Usually the most efficient way is to emit a
+ * itemsRemoved() signal for all items, reorder the items internally and to emit a
+ * itemsInserted() signal afterwards.
+ */
+ virtual void onSortRoleChanged(const QByteArray& current, const QByteArray& previous);
+
+private:
+ QByteArray m_groupRole;
+ QByteArray m_sortRole;
+};
+
+#endif
+
+
--- /dev/null
+//krazy:exclude=copyright (email of Maxim is missing)
+/*
+ This file is a part of the KDE project
+
+ Copyright © 2006 Zack Rusin <zack@kde.org>
+ Copyright © 2006-2007, 2008 Fredrik Höglund <fredrik@kde.org>
+
+ The stack blur algorithm was invented by Mario Klingemann <mario@quasimondo.com>
+
+ 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 <QImage>
+#include <QPainter>
+#include <QPixmap>
+#include <QSize>
+
+#include <KDebug>
+
+#include <config-X11.h> // for HAVE_XRENDER
+#if defined(Q_WS_X11) && defined(HAVE_XRENDER)
+# include <QX11Info>
+# include <X11/Xlib.h>
+# include <X11/extensions/Xrender.h>
+#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<quint32 *>(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<quint32 *>(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 defined(Q_WS_X11) && defined(HAVE_XRENDER)
+ // Assume that the texture size limit is 2048x2048
+ if ((pixmap.width() <= 2048) && (pixmap.height() <= 2048) && pixmap.x11PictureHandle()) {
+ QSize scaledPixmapSize = pixmap.size();
+ scaledPixmapSize.scale(scaledSize, Qt::KeepAspectRatio);
+
+ const qreal factor = scaledPixmapSize.width() / qreal(pixmap.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, pixmap.x11PictureHandle(), CPRepeat, &attr);
+
+ XRenderSetPictureFilter(dpy, pixmap.x11PictureHandle(), FilterBilinear, 0, 0);
+ XRenderSetPictureTransform(dpy, pixmap.x11PictureHandle(), &xform);
+ XRenderComposite(dpy, PictOpOver, pixmap.x11PictureHandle(), None, scaledPixmap.x11PictureHandle(),
+ 0, 0, 0, 0, 0, 0, scaledPixmap.width(), scaledPixmap.height());
+ pixmap = scaledPixmap;
+ } else {
+ pixmap = pixmap.scaled(scaledSize, Qt::KeepAspectRatio, Qt::FastTransformation);
+ }
+#else
+ pixmap = pixmap.scaled(scaledSize, Qt::KeepAspectRatio, Qt::FastTransformation);
+#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;
+}
+
/***************************************************************************
- * Copyright (C) 2010 by Frank Reininghaus (frank78ac@googlemail.com) *
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
* *
* 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 *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
-#include <qtest_kde.h>
+#ifndef KPIXMAPMODIFIER_H
+#define KPIXMAPMODIFIER_H
-#include "dolphinviewtest_allviewmodes.h"
+#include <libdolphin_export.h>
-class DolphinViewTest_Icons : public DolphinViewTest_AllViewModes
-{
- Q_OBJECT
+class QPixmap;
+class QSize;
+class LIBDOLPHINPRIVATE_EXPORT KPixmapModifier
+{
public:
-
- virtual DolphinView::Mode mode() const {
- return DolphinView::IconsView;
- }
-
- virtual bool verifyCorrectViewMode(const DolphinView* view) const {
- return (view->mode() == DolphinView::IconsView);
- }
-
+ static void scale(QPixmap& pixmap, const QSize& scaledSize);
+ static void applyFrame(QPixmap& icon, const QSize& scaledSize);
};
-QTEST_KDEMAIN(DolphinViewTest_Icons, GUI)
+#endif
+
-#include "dolphinviewtest_icons.moc"
{
KAboutData about("dolphin", 0,
ki18nc("@title", "Dolphin"),
- "1.6.9",
+ "1.99",
ki18nc("@title", "File Manager"),
KAboutData::License_GPL,
ki18nc("@info:credit", "(C) 2006-2011 Peter Penz"));
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
<kcfgfile name="dolphinrc"/>
<group name="FoldersPanel">
- <entry name="ShowHiddenFiles" type="Bool">
- <label>Show hidden files</label>
+ <entry name="HiddenFilesShown" type="Bool">
+ <label>Hidden files shown</label>
<default>false</default>
</entry>
<entry name="AutoScrolling" type="Bool">
#include <QScrollBar>
#include <QTimer>
-#include <views/draganddrophelper.h>
-#include <views/dolphinmodel.h>
-#include <views/dolphinsortfilterproxymodel.h>
#include <views/dolphinview.h>
#include <views/folderexpander.h>
#include <views/renamedialog.h>
m_setLeafVisible(false),
m_mouseButtons(Qt::NoButton),
m_dirLister(0),
- m_dolphinModel(0),
- m_proxyModel(0),
+ //m_dolphinModel(0),
+ //m_proxyModel(0),
m_treeView(0),
m_leafDir()
{
{
FoldersPanelSettings::self()->writeConfig();
- delete m_proxyModel;
- m_proxyModel = 0;
- delete m_dolphinModel;
- m_dolphinModel = 0;
- m_dirLister = 0; // deleted by m_dolphinModel
+ //delete m_proxyModel;
+ //m_proxyModel = 0;
+ //delete m_dolphinModel;
+ //m_dolphinModel = 0;
+ delete m_dirLister;
+ m_dirLister = 0;
}
-void FoldersPanel::setShowHiddenFiles(bool show)
+void FoldersPanel::setHiddenFilesShown(bool show)
{
- FoldersPanelSettings::setShowHiddenFiles(show);
+ FoldersPanelSettings::setHiddenFilesShown(show);
if (m_dirLister) {
m_dirLister->setShowingDotFiles(show);
m_dirLister->openUrl(m_dirLister->url(), KDirLister::Reload);
}
}
-bool FoldersPanel::showHiddenFiles() const
+bool FoldersPanel::hiddenFilesShown() const
{
- return FoldersPanelSettings::showHiddenFiles();
+ return FoldersPanelSettings::hiddenFilesShown();
}
void FoldersPanel::setAutoScrolling(bool enable)
void FoldersPanel::rename(const KFileItem& item)
{
if (DolphinSettings::instance().generalSettings()->renameInline()) {
- const QModelIndex dirIndex = m_dolphinModel->indexForItem(item);
- const QModelIndex proxyIndex = m_proxyModel->mapFromSource(dirIndex);
- m_treeView->edit(proxyIndex);
+ //const QModelIndex dirIndex = m_dolphinModel->indexForItem(item);
+ //const QModelIndex proxyIndex = m_proxyModel->mapFromSource(dirIndex);
+ //m_treeView->edit(proxyIndex);
} else {
RenameDialog* dialog = new RenameDialog(this, KFileItemList() << item);
dialog->setAttribute(Qt::WA_DeleteOnClose);
m_dirLister->setMainWindow(window());
m_dirLister->setDelayedMimeTypes(true);
m_dirLister->setAutoErrorHandlingEnabled(false, this);
- m_dirLister->setShowingDotFiles(FoldersPanelSettings::showHiddenFiles());
+ m_dirLister->setShowingDotFiles(FoldersPanelSettings::hiddenFilesShown());
connect(m_dirLister, SIGNAL(completed()), this, SLOT(slotDirListerCompleted()));
- Q_ASSERT(!m_dolphinModel);
+ /*Q_ASSERT(!m_dolphinModel);
m_dolphinModel = new DolphinModel(this);
m_dolphinModel->setDirLister(m_dirLister);
m_dolphinModel->setDropsAllowed(DolphinModel::DropOnDirectory);
QVBoxLayout* layout = new QVBoxLayout(this);
layout->setMargin(0);
- layout->addWidget(m_treeView);
+ layout->addWidget(m_treeView);*/
}
loadTree(url());
Panel::contextMenuEvent(event);
KFileItem item;
- const QModelIndex index = m_treeView->indexAt(event->pos());
+ /*const QModelIndex index = m_treeView->indexAt(event->pos());
if (index.isValid()) {
const QModelIndex dolphinModelIndex = m_proxyModel->mapToSource(index);
item = m_dolphinModel->itemForIndex(dolphinModelIndex);
- }
+ }*/
QPointer<TreeViewContextMenu> contextMenu = new TreeViewContextMenu(this, item);
contextMenu->open();
void FoldersPanel::updateActiveView(const QModelIndex& index)
{
- const QModelIndex dirIndex = m_proxyModel->mapToSource(index);
+ Q_UNUSED(index);
+ /*const QModelIndex dirIndex = m_proxyModel->mapToSource(index);
const KFileItem item = m_dolphinModel->itemForIndex(dirIndex);
if (!item.isNull()) {
emit changeUrl(item.url(), m_mouseButtons);
- }
+ }*/
}
void FoldersPanel::dropUrls(const QModelIndex& index, QDropEvent* event)
{
+ Q_UNUSED(event);
if (index.isValid()) {
- const QModelIndex dirIndex = m_proxyModel->mapToSource(index);
+ /*const QModelIndex dirIndex = m_proxyModel->mapToSource(index);
KFileItem item = m_dolphinModel->itemForIndex(dirIndex);
Q_ASSERT(!item.isNull());
if (item.isDir()) {
- DragAndDropHelper::instance().dropUrls(item, item.url(), event, this);
- }
+ Q_UNUSED(event);
+ //DragAndDropHelper::instance().dropUrls(item, item.url(), event, this);
+ }*/
}
}
void FoldersPanel::scrollToLeaf()
{
- const QModelIndex dirIndex = m_dolphinModel->indexForUrl(m_leafDir);
+ /*const QModelIndex dirIndex = m_dolphinModel->indexForUrl(m_leafDir);
const QModelIndex proxyIndex = m_proxyModel->mapFromSource(dirIndex);
if (proxyIndex.isValid()) {
m_treeView->scrollTo(proxyIndex);
- }
+ }*/
}
void FoldersPanel::updateMouseButtons()
void FoldersPanel::slotDirListerCompleted()
{
- m_treeView->resizeColumnToContents(DolphinModel::Name);
+// m_treeView->resizeColumnToContents(DolphinModel::Name);
}
void FoldersPanel::slotHorizontalScrollBarMoved(int value)
m_dirLister->stop();
m_dirLister->openUrl(baseUrl, KDirLister::Reload);
}
- m_dolphinModel->expandToUrl(m_leafDir);
+ //m_dolphinModel->expandToUrl(m_leafDir);
}
void FoldersPanel::selectLeafDirectory()
{
- const QModelIndex dirIndex = m_dolphinModel->indexForUrl(m_leafDir);
+ /*const QModelIndex dirIndex = m_dolphinModel->indexForUrl(m_leafDir);
const QModelIndex proxyIndex = m_proxyModel->mapFromSource(dirIndex);
if (proxyIndex.isValid()) {
QTimer::singleShot(0, this, SLOT(scrollToLeaf()));
m_setLeafVisible = false;
}
- }
+ }*/
}
#include "folderspanel.moc"
FoldersPanel(QWidget* parent = 0);
virtual ~FoldersPanel();
- void setShowHiddenFiles(bool show);
- bool showHiddenFiles() const;
+ void setHiddenFilesShown(bool show);
+ bool hiddenFilesShown() const;
void setAutoScrolling(bool enable);
bool autoScrolling() const;
bool m_setLeafVisible;
Qt::MouseButtons m_mouseButtons;
KDirLister* m_dirLister;
- DolphinModel* m_dolphinModel;
- DolphinSortFilterProxyModel* m_proxyModel;
+ //DolphinModel* m_dolphinModel;
+ //DolphinSortFilterProxyModel* m_proxyModel;
PanelTreeView* m_treeView;
KUrl m_leafDir;
};
#include <QHeaderView>
#include <QScrollBar>
-#include <views/dolphinmodel.h>
-#include <views/draganddrophelper.h>
-
PanelTreeView::PanelTreeView(QWidget* parent) :
KTreeView(parent)
{
switch (event->type()) {
case QEvent::Polish:
// Hide all columns except of the 'Name' column
- for (int i = DolphinModel::Name + 1; i < DolphinModel::ExtraColumnCount; ++i) {
+ /*for (int i = DolphinModel::Name + 1; i < DolphinModel::ExtraColumnCount; ++i) {
hideColumn(i);
}
- header()->hide();
+ header()->hide();*/
break;
case QEvent::Show:
void PanelTreeView::startDrag(Qt::DropActions supportedActions)
{
- DragAndDropHelper::instance().startDrag(this, supportedActions);
+ Q_UNUSED(supportedActions);
+ //DragAndDropHelper::instance().startDrag(this, supportedActions);
}
void PanelTreeView::dragEnterEvent(QDragEnterEvent* event)
QAction* showHiddenFilesAction = new QAction(i18nc("@action:inmenu", "Show Hidden Files"), this);
showHiddenFilesAction->setCheckable(true);
- showHiddenFilesAction->setChecked(m_parent->showHiddenFiles());
+ showHiddenFilesAction->setChecked(m_parent->hiddenFilesShown());
popup->addAction(showHiddenFilesAction);
connect(showHiddenFilesAction, SIGNAL(toggled(bool)), this, SLOT(setShowHiddenFiles(bool)));
void TreeViewContextMenu::setShowHiddenFiles(bool show)
{
- m_parent->setShowHiddenFiles(show);
+ m_parent->setHiddenFilesShown(show);
}
void TreeViewContextMenu::setAutoScrolling(bool enable)
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
<kcfgfile name="dolphinrc"/>
<group name="InformationPanel">
- <entry name="showPreview" type="Bool">
- <label>Show preview</label>
+ <entry name="previewsShown" type="Bool">
+ <label>Previews shown</label>
<default>true</default>
</entry>
</group>
m_nameLabel->setAlignment(Qt::AlignHCenter);
m_nameLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
- const bool showPreview = InformationPanelSettings::showPreview();
- m_preview->setVisible(showPreview);
+ const bool previewsShown = InformationPanelSettings::previewsShown();
+ m_preview->setVisible(previewsShown);
m_metaDataWidget = new KFileMetaDataWidget(parent);
m_metaDataWidget->setFont(KGlobalSettings::smallestReadableFont());
m_metaDataWidget->setItems(KFileItemList() << item);
}
- if (InformationPanelSettings::showPreview()) {
+ if (InformationPanelSettings::previewsShown()) {
const QString mimeType = item.mimetype();
const bool usePhonon = Phonon::BackendCapabilities::isMimeTypeAvailable(mimeType) &&
(mimeType != "image/png"); // TODO: workaround, as Phonon
QAction* previewAction = popup.addAction(i18nc("@action:inmenu", "Preview"));
previewAction->setIcon(KIcon("view-preview"));
previewAction->setCheckable(true);
- previewAction->setChecked(InformationPanelSettings::showPreview());
+ previewAction->setChecked(InformationPanelSettings::previewsShown());
QAction* configureAction = popup.addAction(i18nc("@action:inmenu", "Configure..."));
configureAction->setIcon(KIcon("configure"));
const bool isChecked = action->isChecked();
if (action == previewAction) {
m_preview->setVisible(isChecked);
- InformationPanelSettings::setShowPreview(isChecked);
+ InformationPanelSettings::setPreviewsShown(isChecked);
} else if (action == configureAction) {
FileMetaDataConfigurationDialog* dialog = new FileMetaDataConfigurationDialog();
dialog->setDescription(i18nc("@label::textbox",
#include <KFileItem>
#include <konq_operations.h>
-#include "views/draganddrophelper.h"
PlacesPanel::PlacesPanel(QWidget* parent) :
KFilePlacesView(parent),
void PlacesPanel::slotUrlsDropped(const KUrl& dest, QDropEvent* event, QWidget* parent)
{
- DragAndDropHelper::instance().dropUrls(KFileItem(), dest, event, parent);
+ Q_UNUSED(dest);
+ Q_UNUSED(event);
+ Q_UNUSED(parent);
+ //DragAndDropHelper::instance().dropUrls(KFileItem(), dest, event, parent);
}
void PlacesPanel::emitExtendedUrlChangedSignal(const KUrl& url)
#include "views/additionalinfoaccessor.h"
AdditionalInfoDialog::AdditionalInfoDialog(QWidget* parent,
- KFileItemDelegate::InformationList infoList) :
+ const QList<DolphinView::AdditionalInfo>& infoList) :
KDialog(parent),
m_infoList(infoList),
m_checkBoxes()
// Add checkboxes
const AdditionalInfoAccessor& infoAccessor = AdditionalInfoAccessor::instance();
- const KFileItemDelegate::InformationList keys = infoAccessor.keys();
- foreach (const KFileItemDelegate::Information info, keys) {
+ const QList<DolphinView::AdditionalInfo> keys = infoAccessor.keys();
+ foreach (DolphinView::AdditionalInfo info, keys) {
QCheckBox* checkBox = new QCheckBox(infoAccessor.translation(info), mainWidget);
checkBox->setChecked(infoList.contains(info));
layout->addWidget(checkBox);
saveDialogSize(dialogConfig, KConfigBase::Persistent);
}
-KFileItemDelegate::InformationList AdditionalInfoDialog::informationList() const
+QList<DolphinView::AdditionalInfo> AdditionalInfoDialog::informationList() const
{
return m_infoList;
}
{
m_infoList.clear();
- const KFileItemDelegate::InformationList keys = AdditionalInfoAccessor::instance().keys();
+ const QList<DolphinView::AdditionalInfo> keys = AdditionalInfoAccessor::instance().keys();
int index = 0;
- foreach (const KFileItemDelegate::Information info, keys) {
+ foreach (DolphinView::AdditionalInfo info, keys) {
if (m_checkBoxes[index]->isChecked()) {
m_infoList.append(info);
}
#ifndef ADDITIONALINFODIALOG_H
#define ADDITIONALINFODIALOG_H
+#include <views/dolphinview.h>
#include <KDialog>
-#include <KFileItemDelegate>
#include <QList>
class QCheckBox;
Q_OBJECT
public:
- AdditionalInfoDialog(QWidget* parent, KFileItemDelegate::InformationList infoList);
+ AdditionalInfoDialog(QWidget* parent, const QList<DolphinView::AdditionalInfo>& infoList);
virtual ~AdditionalInfoDialog();
- KFileItemDelegate::InformationList informationList() const;
+ QList<DolphinView::AdditionalInfo> informationList() const;
private slots:
void slotOk();
private:
- KFileItemDelegate::InformationList m_infoList;
+ QList<DolphinView::AdditionalInfo> m_infoList;
QList<QCheckBox*> m_checkBoxes;
};
{
m_viewProps = new ViewProperties(dir);
m_viewProps->setViewMode(viewProps.viewMode());
- m_viewProps->setShowPreview(viewProps.showPreview());
- m_viewProps->setShowHiddenFiles(viewProps.showHiddenFiles());
+ m_viewProps->setPreviewsShown(viewProps.previewsShown());
+ m_viewProps->setHiddenFilesShown(viewProps.hiddenFilesShown());
m_viewProps->setSorting(viewProps.sorting());
m_viewProps->setSortOrder(viewProps.sortOrder());
+++ /dev/null
-File=dolphin_columnmodesettings.kcfg
-ClassName=ColumnModeSettings
-Singleton=false
-Mutators=true
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
- http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
- <include>kiconloader.h</include>
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
<include>kglobalsettings.h</include>
+ <include>kiconloader.h</include>
<kcfgfile name="dolphinrc"/>
- <group name="ColumnMode">
- <entry name="FontFamily" type="String">
- <label>Font family</label>
- <default code="true">KGlobalSettings::generalFont().family()</default>
- </entry>
+ <group name="CompactMode">
<entry name="UseSystemFont" type="Bool">
<label>Use system font</label>
<default>true</default>
</entry>
+ <entry name="FontFamily" type="String">
+ <label>Font family</label>
+ <default code="true">KGlobalSettings::generalFont().family()</default>
+ </entry>
<entry name="FontSize" type="Double">
<label>Font size</label>
<default code="true">KGlobalSettings::generalFont().pointSizeF()</default>
</entry>
<entry name="IconSize" type="Int">
<label>Icon size</label>
- <default code="true">KIconLoader::SizeSmall</default>
+ <default code="true">KIconLoader::SizeMedium</default>
</entry>
<entry name="PreviewSize" type="Int">
<label>Preview size</label>
- <default code="true">KIconLoader::SizeLarge</default>
- </entry>
- <entry name="ColumnWidth" type="Int">
- <label>Column width</label>
- <default>250</default>
+ <default code="true">KIconLoader::SizeHuge</default>
</entry>
</group>
</kcfg>
--- /dev/null
+File=dolphin_compactmodesettings.kcfg
+ClassName=CompactModeSettings
+Singleton=yes
+Mutators=true
<label>Preview size</label>
<default code="true">KIconLoader::SizeLarge</default>
</entry>
- <entry name="ExpandableFolders" type="Bool">
- <label>Expandable folders</label>
- <default>false</default>
- </entry>
<entry name="ColumnPositions" type="IntList">
<label>Position of columns</label>
<default>0,1,2,3,4,5,6,7,8</default>
File=dolphin_detailsmodesettings.kcfg
ClassName=DetailsModeSettings
-Singleton=false
+Singleton=yes
Mutators=true
<kcfgfile arg="true" />
<group name="Settings">
- <entry name="ShowHiddenFiles" key="ShowDotFiles" type="Bool" >
- <label context="@label">Show hidden files</label>
+ <entry name="HiddenFilesShown" type="Bool" >
+ <label context="@label">Hidden files shown</label>
<whatsthis context="@info:whatsthis">When this option is enabled hidden files, such as those starting with a '.', will be shown in the file view.</whatsthis>
<default>false</default>
</entry>
<entry name="Version" type="Int" >
<label context="@label">Version</label>
<whatsthis context="@info:whatsthis">This option defines the used version of the view properties.</whatsthis>
- <default>1</default>
+ <default>2</default>
<min>1</min>
</entry>
<label context="@label">View Mode</label>
<whatsthis context="@info:whatsthis">This option controls the style of the view. Currently supported values include icons (0), details (1) and column (2) views.</whatsthis>
<default>DolphinView::IconsView</default>
- <min>0</min>
- <max code="true">DolphinView::MaxModeEnum</max>
</entry>
- <entry name="ShowPreview" type="Bool" >
- <label context="@label">Show preview</label>
+ <entry name="PreviewsShown" type="Bool" >
+ <label context="@label">Previews shown</label>
<whatsthis context="@info:whatsthis">When this option is enabled, a preview of the file content is shown as an icon.</whatsthis>
<default>false</default>
</entry>
<label context="@label">Sort files by</label>
<whatsthis context="@info:whatsthis">This option defines which attribute (name, size, date, etc.) sorting is performed on.</whatsthis>
<default code="true">DolphinView::SortByName</default>
- <min>0</min>
- <max code="true">DolphinView::MaxSortingEnum</max>
</entry>
<entry name="SortOrder" type="Int" >
<default>true</default>
</entry>
- <entry name="AdditionalInfo" type="Int">
- <label context="@label">Additional information (deprecated, use AdditionInfoV2 instead)</label>
- <default>0</default>
- </entry>
-
- <entry name="AdditionalInfoV2" type="StringList">
+ <entry name="AdditionalInfo" type="StringList">
<label context="@label">Additional information</label>
<default></default>
</entry>
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
<include>kglobalsettings.h</include>
<include>kiconloader.h</include>
- <include>QListView</include>
<kcfgfile name="dolphinrc"/>
<group name="IconsMode">
- <entry name="Arrangement" type="Int">
- <label>Arrangement</label>
- <default code="true">QListView::TopToBottom</default>
- </entry>
<entry name="UseSystemFont" type="Bool">
<label>Use system font</label>
<default>true</default>
<label>Font weight</label>
<default>0</default>
</entry>
- <entry name="ItemHeight" type="Int">
- <label>Item height</label>
- <!--
- check 'void IconsViewSettingsPage::applySettings()' as reference (iconsviewsettingspage.cpp):
- itemHeight += fontHeight * numberOfTextlines + 10;
- /-->
- <default code="true">KIconLoader::SizeMedium + QFontMetrics(KGlobalSettings::generalFont()).height() * 2 + 10</default>
- </entry>
- <entry name="ItemWidth" type="Int">
- <label>Item width</label>
- <!--
- check 'void IconsViewSettingsPage::applySettings()' as reference (iconsviewsettingspage.cpp):
- itemWidth = TopToBottomBase + textSizeIndex * TopToBottomInc;
- /-->
- <default>96</default>
- </entry>
- <entry name="GridSpacing" type="Int">
- <label>Grid spacing</label>
- <default>8</default>
- </entry>
<entry name="IconSize" type="Int">
<label>Icon size</label>
<default code="true">KIconLoader::SizeMedium</default>
</entry>
- <entry name="NumberOfTextlines" type="Int">
- <label>Number of textlines</label>
- <!-- don't forget adjusting the "ItemHeight" too when changing this value /-->
- <default>2</default>
- </entry>
<entry name="PreviewSize" type="Int">
<label>Preview size</label>
<default code="true">KIconLoader::SizeHuge</default>
</entry>
+ <entry name="TextWidthIndex" type="Int">
+ <label>Text width index</label>
+ <default>1</default>
+ </entry>
</group>
</kcfg>
File=dolphin_iconsmodesettings.kcfg
ClassName=IconsModeSettings
-Singleton=false
+Singleton=yes
Mutators=true
#include <KLocale>
#include <KStandardDirs>
-#include "dolphin_columnmodesettings.h"
#include "dolphin_detailsmodesettings.h"
#include "dolphin_generalsettings.h"
#include "dolphin_iconsmodesettings.h"
void DolphinSettings::save()
{
m_generalSettings->writeConfig();
- m_iconsModeSettings->writeConfig();
- m_detailsModeSettings->writeConfig();
- m_columnModeSettings->writeConfig();
}
DolphinSettings::DolphinSettings()
{
m_generalSettings = new GeneralSettings();
- m_iconsModeSettings = new IconsModeSettings();
- m_detailsModeSettings = new DetailsModeSettings();
- m_columnModeSettings = new ColumnModeSettings();
m_placesModel = new KFilePlacesModel();
}
delete m_generalSettings;
m_generalSettings = 0;
- delete m_iconsModeSettings;
- m_iconsModeSettings = 0;
-
- delete m_detailsModeSettings;
- m_detailsModeSettings = 0;
-
- delete m_columnModeSettings;
- m_columnModeSettings = 0;
-
delete m_placesModel;
m_placesModel = 0;
}
#include <libdolphin_export.h>
-class ColumnModeSettings;
-class DetailsModeSettings;
class GeneralSettings;
-class IconsModeSettings;
class KFilePlacesModel;
+// TODO: Remove this class completely and just work with the settings directly instead
+
/**
* @brief Manages and stores all settings from Dolphin.
*
static DolphinSettings& instance();
GeneralSettings* generalSettings() const;
- IconsModeSettings* iconsModeSettings() const;
- DetailsModeSettings* detailsModeSettings() const;
- ColumnModeSettings* columnModeSettings() const;
KFilePlacesModel* placesModel() const;
virtual void save();
private:
GeneralSettings* m_generalSettings;
- IconsModeSettings* m_iconsModeSettings;
- DetailsModeSettings* m_detailsModeSettings;
- ColumnModeSettings* m_columnModeSettings;
KFilePlacesModel* m_placesModel;
};
return m_generalSettings;
}
-inline IconsModeSettings* DolphinSettings::iconsModeSettings() const
-{
- return m_iconsModeSettings;
-}
-
-inline DetailsModeSettings* DolphinSettings::detailsModeSettings() const
-{
- return m_detailsModeSettings;
-}
-
-inline ColumnModeSettings* DolphinSettings::columnModeSettings() const
-{
- return m_columnModeSettings;
-}
-
inline KFilePlacesModel* DolphinSettings::placesModel() const
{
return m_placesModel;
#include <KPluginFactory>
#include <KPluginLoader>
-#include <settings/viewmodes/columnviewsettingspage.h>
#include <settings/viewmodes/detailsviewsettingspage.h>
#include <settings/viewmodes/iconsviewsettingspage.h>
tabWidget->addTab(iconsPage, KIcon("view-list-icons"), i18nc("@title:tab", "Icons"));
connect(iconsPage, SIGNAL(changed()), this, SLOT(changed()));
+ // TODO: initialize 'Compact' tab
+
// initialize 'Details' tab
DetailsViewSettingsPage* detailsPage = new DetailsViewSettingsPage(tabWidget);
- tabWidget->addTab(detailsPage, KIcon("view-list-details"), i18nc("@title:tab", "Details"));
+ tabWidget->addTab(detailsPage, KIcon("view-list-text"), i18nc("@title:tab", "Details"));
connect(detailsPage, SIGNAL(changed()), this, SLOT(changed()));
- // initialize 'Column' tab
- ColumnViewSettingsPage* columnPage = new ColumnViewSettingsPage(tabWidget);
- tabWidget->addTab(columnPage, KIcon("view-file-columns"), i18nc("@title:tab", "Column"));
- connect(columnPage, SIGNAL(changed()), this, SLOT(changed()));
-
m_pages.append(iconsPage);
m_pages.append(detailsPage);
- m_pages.append(columnPage);
topLayout->addWidget(tabWidget, 0, 0);
}
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2006 by Peter Penz <peter.penz19@gmail.com> *
- * *
- * 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 "columnviewsettingspage.h"
-
-#include "dolphinfontrequester.h"
-#include <dolphin_columnmodesettings.h>
-#include "iconsizegroupbox.h"
-
-#include <KDialog>
-#include <KLocale>
-#include <KComboBox>
-
-#include <settings/dolphinsettings.h>
-
-#include <QButtonGroup>
-#include <QCheckBox>
-#include <QGroupBox>
-#include <QHBoxLayout>
-#include <QLabel>
-#include <QSlider>
-#include <QRadioButton>
-
-#include <views/zoomlevelinfo.h>
-
-ColumnViewSettingsPage::ColumnViewSettingsPage(QWidget* parent) :
- ViewSettingsPageBase(parent),
- m_iconSizeGroupBox(0),
- m_fontRequester(0),
- m_textWidthBox(0)
-{
- const int spacing = KDialog::spacingHint();
- const int margin = KDialog::marginHint();
- const QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
-
- setSpacing(spacing);
- setMargin(margin);
-
- // Create "Icon" properties
- m_iconSizeGroupBox = new IconSizeGroupBox(this);
- m_iconSizeGroupBox->setSizePolicy(sizePolicy);
-
- const int min = ZoomLevelInfo::minimumLevel();
- const int max = ZoomLevelInfo::maximumLevel();
- m_iconSizeGroupBox->setDefaultSizeRange(min, max);
- m_iconSizeGroupBox->setPreviewSizeRange(min, max);
-
- // create "Text" properties
- QGroupBox* textGroup = new QGroupBox(i18nc("@title:group", "Text"), this);
- textGroup->setSizePolicy(sizePolicy);
-
- QLabel* fontLabel = new QLabel(i18nc("@label:listbox", "Font:"), textGroup);
- m_fontRequester = new DolphinFontRequester(textGroup);
-
- QLabel* textWidthLabel = new QLabel(i18nc("@label:listbox", "Text width:"), textGroup);
- m_textWidthBox = new KComboBox(textGroup);
- m_textWidthBox->addItem(i18nc("@item:inlistbox Text width", "Small"));
- m_textWidthBox->addItem(i18nc("@item:inlistbox Text width", "Medium"));
- m_textWidthBox->addItem(i18nc("@item:inlistbox Text width", "Large"));
- m_textWidthBox->addItem(i18nc("@item:inlistbox Text width", "Huge"));
-
- QGridLayout* textGroupLayout = new QGridLayout(textGroup);
- textGroupLayout->addWidget(fontLabel, 0, 0, Qt::AlignRight);
- textGroupLayout->addWidget(m_fontRequester, 0, 1);
- textGroupLayout->addWidget(textWidthLabel, 1, 0, Qt::AlignRight);
- textGroupLayout->addWidget(m_textWidthBox, 1, 1);
-
- // Add a dummy widget with no restriction regarding
- // a vertical resizing. This assures that the dialog layout
- // is not stretched vertically.
- new QWidget(this);
-
- loadSettings();
-
- connect(m_iconSizeGroupBox, SIGNAL(defaultSizeChanged(int)), this, SIGNAL(changed()));
- connect(m_iconSizeGroupBox, SIGNAL(previewSizeChanged(int)), this, SIGNAL(changed()));
- connect(m_fontRequester, SIGNAL(changed()), this, SIGNAL(changed()));
- connect(m_textWidthBox, SIGNAL(currentIndexChanged(int)), this, SIGNAL(changed()));
-}
-
-ColumnViewSettingsPage::~ColumnViewSettingsPage()
-{
-}
-
-void ColumnViewSettingsPage::applySettings()
-{
- ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
-
- const int iconSize = ZoomLevelInfo::iconSizeForZoomLevel(m_iconSizeGroupBox->defaultSizeValue());
- const int previewSize = ZoomLevelInfo::iconSizeForZoomLevel(m_iconSizeGroupBox->previewSizeValue());
- settings->setIconSize(iconSize);
- settings->setPreviewSize(previewSize);
-
- const QFont font = m_fontRequester->font();
- settings->setUseSystemFont(m_fontRequester->mode() == DolphinFontRequester::SystemFont);
- settings->setFontFamily(font.family());
- settings->setFontSize(font.pointSizeF());
- settings->setItalicFont(font.italic());
- settings->setFontWeight(font.weight());
-
- const int columnWidth = BaseTextWidth + (m_textWidthBox->currentIndex() * TextInc);
- settings->setColumnWidth(columnWidth);
-
- settings->writeConfig();
-}
-
-void ColumnViewSettingsPage::restoreDefaults()
-{
- ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
- settings->useDefaults(true);
- loadSettings();
- settings->useDefaults(false);
-}
-
-void ColumnViewSettingsPage::loadSettings()
-{
- ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
-
- const QSize iconSize(settings->iconSize(), settings->iconSize());
- const int iconSizeValue = ZoomLevelInfo::zoomLevelForIconSize(iconSize);
- m_iconSizeGroupBox->setDefaultSizeValue(iconSizeValue);
-
- const QSize previewSize(settings->previewSize(), settings->previewSize());
- const int previewSizeValue = ZoomLevelInfo::zoomLevelForIconSize(previewSize);
- m_iconSizeGroupBox->setPreviewSizeValue(previewSizeValue);
-
- if (settings->useSystemFont()) {
- m_fontRequester->setMode(DolphinFontRequester::SystemFont);
- } else {
- QFont font(settings->fontFamily(),
- qRound(settings->fontSize()));
- font.setItalic(settings->italicFont());
- font.setWeight(settings->fontWeight());
- font.setPointSizeF(settings->fontSize());
- m_fontRequester->setMode(DolphinFontRequester::CustomFont);
- m_fontRequester->setCustomFont(font);
- }
-
- m_textWidthBox->setCurrentIndex((settings->columnWidth() - BaseTextWidth) / TextInc);
-}
-
-#include "columnviewsettingspage.moc"
#include <KDialog>
#include <KLocale>
-#include <settings/dolphinsettings.h>
-
#include <QButtonGroup>
#include <QCheckBox>
#include <QComboBox>
DetailsViewSettingsPage::DetailsViewSettingsPage(QWidget* parent) :
ViewSettingsPageBase(parent),
m_iconSizeGroupBox(0),
- m_fontRequester(0),
- m_expandableFolders(0)
+ m_fontRequester(0)
{
const int spacing = KDialog::spacingHint();
const int margin = KDialog::marginHint();
textLayout->addWidget(fontLabel, 0, Qt::AlignRight);
textLayout->addWidget(m_fontRequester);
- // create "Expandable Folders" checkbox
- m_expandableFolders = new QCheckBox(i18nc("@option:check", "Expandable folders"), this);
-
// Add a dummy widget with no restriction regarding
// a vertical resizing. This assures that the dialog layout
// is not stretched vertically.
connect(m_iconSizeGroupBox, SIGNAL(defaultSizeChanged(int)), this, SIGNAL(changed()));
connect(m_iconSizeGroupBox, SIGNAL(previewSizeChanged(int)), this, SIGNAL(changed()));
connect(m_fontRequester, SIGNAL(changed()), this, SIGNAL(changed()));
- connect(m_expandableFolders, SIGNAL(toggled(bool)), this, SIGNAL(changed()));
}
DetailsViewSettingsPage::~DetailsViewSettingsPage()
void DetailsViewSettingsPage::applySettings()
{
- DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
-
const int iconSize = ZoomLevelInfo::iconSizeForZoomLevel(m_iconSizeGroupBox->defaultSizeValue());
const int previewSize = ZoomLevelInfo::iconSizeForZoomLevel(m_iconSizeGroupBox->previewSizeValue());
- settings->setIconSize(iconSize);
- settings->setPreviewSize(previewSize);
+ DetailsModeSettings::setIconSize(iconSize);
+ DetailsModeSettings::setPreviewSize(previewSize);
const QFont font = m_fontRequester->font();
- settings->setUseSystemFont(m_fontRequester->mode() == DolphinFontRequester::SystemFont);
- settings->setFontFamily(font.family());
- settings->setFontSize(font.pointSizeF());
- settings->setItalicFont(font.italic());
- settings->setFontWeight(font.weight());
+ DetailsModeSettings::setUseSystemFont(m_fontRequester->mode() == DolphinFontRequester::SystemFont);
+ DetailsModeSettings::setFontFamily(font.family());
+ DetailsModeSettings::setFontSize(font.pointSizeF());
+ DetailsModeSettings::setItalicFont(font.italic());
+ DetailsModeSettings::setFontWeight(font.weight());
- settings->setExpandableFolders(m_expandableFolders->isChecked());
-
- settings->writeConfig();
+ DetailsModeSettings::self()->writeConfig();
}
void DetailsViewSettingsPage::restoreDefaults()
{
- DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
- settings->useDefaults(true);
+ DetailsModeSettings::self()->useDefaults(true);
loadSettings();
- settings->useDefaults(false);
+ DetailsModeSettings::self()->useDefaults(false);
}
void DetailsViewSettingsPage::loadSettings()
{
- DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
-
- const QSize iconSize(settings->iconSize(), settings->iconSize());
+ const QSize iconSize(DetailsModeSettings::iconSize(), DetailsModeSettings::iconSize());
const int iconSizeValue = ZoomLevelInfo::zoomLevelForIconSize(iconSize);
m_iconSizeGroupBox->setDefaultSizeValue(iconSizeValue);
- const QSize previewSize(settings->previewSize(), settings->previewSize());
+ const QSize previewSize(DetailsModeSettings::previewSize(), DetailsModeSettings::previewSize());
const int previewSizeValue = ZoomLevelInfo::zoomLevelForIconSize(previewSize);
m_iconSizeGroupBox->setPreviewSizeValue(previewSizeValue);
- if (settings->useSystemFont()) {
+ if (DetailsModeSettings::useSystemFont()) {
m_fontRequester->setMode(DolphinFontRequester::SystemFont);
} else {
- QFont font(settings->fontFamily(),
- qRound(settings->fontSize()));
- font.setItalic(settings->italicFont());
- font.setWeight(settings->fontWeight());
- font.setPointSizeF(settings->fontSize());
+ QFont font(DetailsModeSettings::fontFamily(),
+ qRound(DetailsModeSettings::fontSize()));
+ font.setItalic(DetailsModeSettings::italicFont());
+ font.setWeight(DetailsModeSettings::fontWeight());
+ font.setPointSizeF(DetailsModeSettings::fontSize());
m_fontRequester->setMode(DolphinFontRequester::CustomFont);
m_fontRequester->setCustomFont(font);
}
-
- m_expandableFolders->setChecked(settings->expandableFolders());
}
#include "detailsviewsettingspage.moc"
class DolphinFontRequester;
class IconSizeGroupBox;
-class QCheckBox;
/**
* @brief Represents the page from the Dolphin Settings which allows
private:
IconSizeGroupBox* m_iconSizeGroupBox;
DolphinFontRequester* m_fontRequester;
- QCheckBox* m_expandableFolders;
};
#endif
#include "iconsviewsettingspage.h"
#include "dolphinfontrequester.h"
-#include "settings/dolphinsettings.h"
#include "iconsizegroupbox.h"
#include "dolphin_iconsmodesettings.h"
#include <QCheckBox>
#include <QGroupBox>
#include <QLabel>
-#include <QListView>
#include <QPushButton>
#include <QGridLayout>
-#include <QVBoxLayout>
#include <views/zoomlevelinfo.h>
ViewSettingsPageBase(parent),
m_iconSizeGroupBox(0),
m_textWidthBox(0),
- m_fontRequester(0),
- m_textlinesCountBox(0),
- m_arrangementBox(0),
- m_gridSpacingBox(0)
+ m_fontRequester(0)
{
const int spacing = KDialog::spacingHint();
const int margin = KDialog::marginHint();
m_iconSizeGroupBox->setDefaultSizeRange(min, max);
m_iconSizeGroupBox->setPreviewSizeRange(min, max);
- // create 'Text' group for selecting the font, the number of lines
+ // Create 'Text' group for selecting the font, the number of lines
// and the text width
QGroupBox* textGroup = new QGroupBox(i18nc("@title:group", "Text"), this);
textGroup->setSizePolicy(sizePolicy);
QLabel* fontLabel = new QLabel(i18nc("@label:listbox", "Font:"), textGroup);
m_fontRequester = new DolphinFontRequester(textGroup);
- QLabel* textlinesCountLabel = new QLabel(i18nc("@label:textbox", "Number of lines:"), textGroup);
- m_textlinesCountBox = new KIntSpinBox(textGroup);
- m_textlinesCountBox->setMinimum(1);
- m_textlinesCountBox->setMaximum(5);
-
QLabel* textWidthLabel = new QLabel(i18nc("@label:listbox", "Text width:"), textGroup);
m_textWidthBox = new KComboBox(textGroup);
m_textWidthBox->addItem(i18nc("@item:inlistbox Text width", "Small"));
QGridLayout* textGroupLayout = new QGridLayout(textGroup);
textGroupLayout->addWidget(fontLabel, 0, 0, Qt::AlignRight);
textGroupLayout->addWidget(m_fontRequester, 0, 1);
- textGroupLayout->addWidget(textlinesCountLabel, 1, 0, Qt::AlignRight);
- textGroupLayout->addWidget(m_textlinesCountBox, 1, 1);
textGroupLayout->addWidget(textWidthLabel, 2, 0, Qt::AlignRight);
textGroupLayout->addWidget(m_textWidthBox, 2, 1);
- // create the 'Grid' group for selecting the arrangement and the grid spacing
- QGroupBox* gridGroup = new QGroupBox(i18nc("@title:group", "Grid"), this);
- gridGroup->setSizePolicy(sizePolicy);
-
- QLabel* arrangementLabel = new QLabel(i18nc("@label:listbox", "Arrangement:"), gridGroup);
- m_arrangementBox = new KComboBox(gridGroup);
- m_arrangementBox->addItem(i18nc("@item:inlistbox Arrangement", "Columns"));
- m_arrangementBox->addItem(i18nc("@item:inlistbox Arrangement", "Rows"));
-
- QLabel* gridSpacingLabel = new QLabel(i18nc("@label:listbox", "Grid spacing:"), gridGroup);
- m_gridSpacingBox = new KComboBox(gridGroup);
- m_gridSpacingBox->addItem(i18nc("@item:inlistbox Grid spacing", "None"));
- m_gridSpacingBox->addItem(i18nc("@item:inlistbox Grid spacing", "Small"));
- m_gridSpacingBox->addItem(i18nc("@item:inlistbox Grid spacing", "Medium"));
- m_gridSpacingBox->addItem(i18nc("@item:inlistbox Grid spacing", "Large"));
-
- QGridLayout* gridGroupLayout = new QGridLayout(gridGroup);
- gridGroupLayout->addWidget(arrangementLabel, 0, 0, Qt::AlignRight);
- gridGroupLayout->addWidget(m_arrangementBox, 0, 1);
- gridGroupLayout->addWidget(gridSpacingLabel, 1, 0, Qt::AlignRight);
- gridGroupLayout->addWidget(m_gridSpacingBox, 1, 1);
-
// Add a dummy widget with no restriction regarding
// a vertical resizing. This assures that the dialog layout
// is not stretched vertically.
connect(m_iconSizeGroupBox, SIGNAL(defaultSizeChanged(int)), this, SIGNAL(changed()));
connect(m_iconSizeGroupBox, SIGNAL(previewSizeChanged(int)), this, SIGNAL(changed()));
connect(m_fontRequester, SIGNAL(changed()), this, SIGNAL(changed()));
- connect(m_textlinesCountBox, SIGNAL(valueChanged(int)), this, SIGNAL(changed()));
connect(m_textWidthBox, SIGNAL(currentIndexChanged(int)), this, SIGNAL(changed()));
- connect(m_arrangementBox, SIGNAL(currentIndexChanged(int)), this, SIGNAL(changed()));
- connect(m_gridSpacingBox, SIGNAL(currentIndexChanged(int)), this, SIGNAL(changed()));
}
IconsViewSettingsPage::~IconsViewSettingsPage()
void IconsViewSettingsPage::applySettings()
{
- IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings();
-
const int iconSize = ZoomLevelInfo::iconSizeForZoomLevel(m_iconSizeGroupBox->defaultSizeValue());
const int previewSize = ZoomLevelInfo::iconSizeForZoomLevel(m_iconSizeGroupBox->previewSizeValue());
- settings->setIconSize(iconSize);
- settings->setPreviewSize(previewSize);
+ IconsModeSettings::setIconSize(iconSize);
+ IconsModeSettings::setPreviewSize(previewSize);
const QFont font = m_fontRequester->font();
- const int fontHeight = QFontMetrics(font).height();
-
- const int arrangement = (m_arrangementBox->currentIndex() == 0) ?
- QListView::LeftToRight :
- QListView::TopToBottom;
- settings->setArrangement(arrangement);
-
- const int numberOfTextlines = m_textlinesCountBox->value();
-
- const int defaultSize = settings->iconSize();
- int itemWidth = defaultSize;
- int itemHeight = defaultSize;
- const int textSizeIndex = m_textWidthBox->currentIndex();
- if (arrangement == QListView::TopToBottom) {
- itemWidth += TopToBottomBase + textSizeIndex * TopToBottomInc;
- itemHeight += fontHeight * numberOfTextlines + 10;
- } else {
- itemWidth += LeftToRightBase + textSizeIndex * LeftToRightInc;
- }
-
- settings->setItemWidth(itemWidth);
- settings->setItemHeight(itemHeight);
-
- settings->setUseSystemFont(m_fontRequester->mode() == DolphinFontRequester::SystemFont);
- settings->setFontFamily(font.family());
- settings->setFontSize(font.pointSizeF());
- settings->setItalicFont(font.italic());
- settings->setFontWeight(font.weight());
+ IconsModeSettings::setUseSystemFont(m_fontRequester->mode() == DolphinFontRequester::SystemFont);
+ IconsModeSettings::setFontFamily(font.family());
+ IconsModeSettings::setFontSize(font.pointSizeF());
+ IconsModeSettings::setItalicFont(font.italic());
+ IconsModeSettings::setFontWeight(font.weight());
- settings->setNumberOfTextlines(numberOfTextlines);
+ IconsModeSettings::setTextWidthIndex(m_textWidthBox->currentIndex());
- const int index = m_gridSpacingBox->currentIndex();
- if (index == 0) {
- // No grid spacing
- settings->setGridSpacing(0);
- } else {
- settings->setGridSpacing(GridSpacingBase + (index - 1) * GridSpacingInc);
- }
-
- settings->writeConfig();
+ IconsModeSettings::self()->writeConfig();
}
void IconsViewSettingsPage::restoreDefaults()
{
- IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings();
- settings->useDefaults(true);
+ IconsModeSettings::self()->useDefaults(true);
loadSettings();
- settings->useDefaults(false);
+ IconsModeSettings::self()->useDefaults(false);
}
void IconsViewSettingsPage::loadSettings()
{
- IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings();
-
- const QSize iconSize(settings->iconSize(), settings->iconSize());
+ const QSize iconSize(IconsModeSettings::iconSize(), IconsModeSettings::iconSize());
const int iconSizeValue = ZoomLevelInfo::zoomLevelForIconSize(iconSize);
m_iconSizeGroupBox->setDefaultSizeValue(iconSizeValue);
- const QSize previewSize(settings->previewSize(), settings->previewSize());
+ const QSize previewSize(IconsModeSettings::previewSize(), IconsModeSettings::previewSize());
const int previewSizeValue = ZoomLevelInfo::zoomLevelForIconSize(previewSize);
m_iconSizeGroupBox->setPreviewSizeValue(previewSizeValue);
- if (settings->useSystemFont()) {
+ if (IconsModeSettings::useSystemFont()) {
m_fontRequester->setMode(DolphinFontRequester::SystemFont);
} else {
- QFont font(settings->fontFamily(),
- qRound(settings->fontSize()));
- font.setItalic(settings->italicFont());
- font.setWeight(settings->fontWeight());
- font.setPointSizeF(settings->fontSize());
+ QFont font(IconsModeSettings::fontFamily(),
+ qRound(IconsModeSettings::fontSize()));
+ font.setItalic(IconsModeSettings::italicFont());
+ font.setWeight(IconsModeSettings::fontWeight());
+ font.setPointSizeF(IconsModeSettings::fontSize());
m_fontRequester->setMode(DolphinFontRequester::CustomFont);
m_fontRequester->setCustomFont(font);
}
- m_textlinesCountBox->setValue(settings->numberOfTextlines());
-
- const bool leftToRightArrangement = (settings->arrangement() == QListView::LeftToRight);
- int textWidthIndex = 0;
- const int remainingWidth = settings->itemWidth() - settings->iconSize();
- if (leftToRightArrangement) {
- textWidthIndex = (remainingWidth - LeftToRightBase) / LeftToRightInc;
- } else {
- textWidthIndex = (remainingWidth - TopToBottomBase) / TopToBottomInc;
- }
- // ensure that chosen index is always valid
- textWidthIndex = qMax(textWidthIndex, 0);
- textWidthIndex = qMin(textWidthIndex, m_textWidthBox->count() - 1);
-
- m_textWidthBox->setCurrentIndex(textWidthIndex);
- m_arrangementBox->setCurrentIndex(leftToRightArrangement ? 0 : 1);
-
- const int spacing = settings->gridSpacing();
- const int index = (spacing <= 0) ? 0 : 1 + (spacing - GridSpacingBase) / GridSpacingInc;
- m_gridSpacingBox->setCurrentIndex(index);
+ m_textWidthBox->setCurrentIndex(IconsModeSettings::textWidthIndex());
}
#include "iconsviewsettingspage.moc"
#ifndef ICONSVIEWSETTINGSPAGE_H
#define ICONSVIEWSETTINGSPAGE_H
-#include <views/dolphiniconsview.h>
#include "viewsettingspagebase.h"
class DolphinFontRequester;
* - icon size
* - preview size
* - text width
- * - grid spacing
* - font
- * - number of text lines
- * - arrangement
*
* @see DolphinIconsViewSettings
*/
void loadSettings();
private:
- enum
- {
- GridSpacingBase = 8,
- GridSpacingInc = 12,
- LeftToRightBase = 128,
- LeftToRightInc = 64,
- TopToBottomBase = 32,
- TopToBottomInc = 32
- };
-
IconSizeGroupBox* m_iconSizeGroupBox;
KComboBox* m_textWidthBox;
DolphinFontRequester* m_fontRequester;
- KIntSpinBox* m_textlinesCountBox;
-
- KComboBox* m_arrangementBox;
- KComboBox* m_gridSpacingBox;
};
#endif
#include "viewsettingspage.h"
-#include "columnviewsettingspage.h"
#include "iconsviewsettingspage.h"
#include "detailsviewsettingspage.h"
tabWidget->addTab(iconsPage, KIcon("view-list-icons"), i18nc("@title:tab", "Icons"));
connect(iconsPage, SIGNAL(changed()), this, SIGNAL(changed()));
+ // TODO: initialize 'Compact' tab
+
// initialize 'Details' tab
DetailsViewSettingsPage* detailsPage = new DetailsViewSettingsPage(tabWidget);
- tabWidget->addTab(detailsPage, KIcon("view-list-details"), i18nc("@title:tab", "Details"));
+ tabWidget->addTab(detailsPage, KIcon("view-list-text"), i18nc("@title:tab", "Details"));
connect(detailsPage, SIGNAL(changed()), this, SIGNAL(changed()));
- // initialize 'Column' tab
- ColumnViewSettingsPage* columnPage = new ColumnViewSettingsPage(tabWidget);
- tabWidget->addTab(columnPage, KIcon("view-file-columns"), i18nc("@title:tab", "Column"));
- connect(columnPage, SIGNAL(changed()), this, SIGNAL(changed()));
-
m_pages.append(iconsPage);
m_pages.append(detailsPage);
- m_pages.append(columnPage);
topLayout->addWidget(tabWidget, 0, 0);
}
#include <QRadioButton>
#include <QBoxLayout>
-#include <views/dolphinsortfilterproxymodel.h>
#include <views/viewproperties.h>
ViewPropertiesDialog::ViewPropertiesDialog(DolphinView* dolphinView) :
m_sortOrder(0),
m_sorting(0),
m_sortFoldersFirst(0),
- m_showPreview(0),
+ m_previewsShown(0),
m_showInGroups(0),
m_showHiddenFiles(0),
m_additionalInfo(0),
QLabel* viewModeLabel = new QLabel(i18nc("@label:listbox", "View mode:"), propsGrid);
m_viewMode = new KComboBox(propsGrid);
m_viewMode->addItem(KIcon("view-list-icons"), i18nc("@item:inlistbox", "Icons"));
- m_viewMode->addItem(KIcon("view-list-details"), i18nc("@item:inlistbox", "Details"));
- m_viewMode->addItem(KIcon("view-file-columns"), i18nc("@item:inlistbox", "Column"));
+ m_viewMode->addItem(KIcon("feffi"), i18nc("@item:inlistbox", "Compact")); // TODO: adjust icons
+ m_viewMode->addItem(KIcon("view-list-text"), i18nc("@item:inlistbox", "Details"));
QLabel* sortingLabel = new QLabel(i18nc("@label:listbox", "Sorting:"), propsGrid);
QWidget* sortingBox = new QWidget(propsGrid);
// }
#endif
m_sortFoldersFirst = new QCheckBox(i18nc("@option:check", "Show folders first"));
- m_showPreview = new QCheckBox(i18nc("@option:check", "Show preview"));
+ m_previewsShown = new QCheckBox(i18nc("@option:check", "Show preview"));
m_showInGroups = new QCheckBox(i18nc("@option:check", "Show in groups"));
m_showHiddenFiles = new QCheckBox(i18nc("@option:check", "Show hidden files"));
QVBoxLayout* propsBoxLayout = new QVBoxLayout(propsBox);
propsBoxLayout->addWidget(propsGrid);
propsBoxLayout->addWidget(m_sortFoldersFirst);
- propsBoxLayout->addWidget(m_showPreview);
+ propsBoxLayout->addWidget(m_previewsShown);
propsBoxLayout->addWidget(m_showInGroups);
propsBoxLayout->addWidget(m_showHiddenFiles);
propsBoxLayout->addWidget(m_additionalInfo);
this, SLOT(configureAdditionalInfo()));
connect(m_sortFoldersFirst, SIGNAL(clicked()),
this, SLOT(slotSortFoldersFirstChanged()));
- connect(m_showPreview, SIGNAL(clicked()),
+ connect(m_previewsShown, SIGNAL(clicked()),
this, SLOT(slotShowPreviewChanged()));
connect(m_showInGroups, SIGNAL(clicked()),
this, SLOT(slotCategorizedSortingChanged()));
{
m_viewProps->setViewMode(static_cast<DolphinView::Mode>(index));
markAsDirty(true);
-
- const DolphinView::Mode mode = m_viewProps->viewMode();
- m_showInGroups->setEnabled(mode == DolphinView::IconsView);
- m_additionalInfo->setEnabled(mode != DolphinView::ColumnView);
}
void ViewPropertiesDialog::slotSortingChanged(int index)
{
- const DolphinView::Sorting sorting = DolphinSortFilterProxyModel::sortingForColumn(index);
- m_viewProps->setSorting(sorting);
- markAsDirty(true);
+ Q_UNUSED(index);
+ Q_ASSERT(false);
+ //const DolphinView::Sorting sorting = DolphinSortFilterProxyModel::sortingForColumn(index);
+ //m_viewProps->setSorting(sorting);
+ //markAsDirty(true);
}
void ViewPropertiesDialog::slotSortOrderChanged(int index)
void ViewPropertiesDialog::slotShowPreviewChanged()
{
- const bool show = m_showPreview->isChecked();
- m_viewProps->setShowPreview(show);
+ const bool show = m_previewsShown->isChecked();
+ m_viewProps->setPreviewsShown(show);
markAsDirty(true);
}
void ViewPropertiesDialog::slotShowHiddenFilesChanged()
{
const bool show = m_showHiddenFiles->isChecked();
- m_viewProps->setShowHiddenFiles(show);
+ m_viewProps->setHiddenFilesShown(show);
markAsDirty(true);
}
void ViewPropertiesDialog::configureAdditionalInfo()
{
- KFileItemDelegate::InformationList info = m_viewProps->additionalInfo();
+ QList<DolphinView::AdditionalInfo> infoList = m_viewProps->additionalInfoList();
const bool useDefaultInfo = (m_viewProps->viewMode() == DolphinView::DetailsView) &&
- (info.isEmpty() || info.contains(KFileItemDelegate::NoInformation));
+ (infoList.isEmpty() || infoList.contains(DolphinView::NoInfo));
if (useDefaultInfo) {
// Using the details view without any additional information (-> additional column)
// makes no sense and leads to a usability problem as no viewport area is available
// anymore. Hence as fallback provide at least a size and date column.
- info.clear();
- info.append(KFileItemDelegate::Size);
- info.append(KFileItemDelegate::ModificationTime);
- m_viewProps->setAdditionalInfo(info);
+ infoList.clear();
+ infoList.append(DolphinView::SizeInfo);
+ infoList.append(DolphinView::DateInfo);
+ m_viewProps->setAdditionalInfoList(infoList);
}
- QPointer<AdditionalInfoDialog> dialog = new AdditionalInfoDialog(this, info);
+ QPointer<AdditionalInfoDialog> dialog = new AdditionalInfoDialog(this, infoList);
if (dialog->exec() == QDialog::Accepted) {
- m_viewProps->setAdditionalInfo(dialog->informationList());
+ m_viewProps->setAdditionalInfoList(dialog->informationList());
markAsDirty(true);
}
delete dialog;
m_dolphinView->setSortOrder(m_viewProps->sortOrder());
m_dolphinView->setSortFoldersFirst(m_viewProps->sortFoldersFirst());
m_dolphinView->setCategorizedSorting(m_viewProps->categorizedSorting());
- m_dolphinView->setAdditionalInfo(m_viewProps->additionalInfo());
- m_dolphinView->setShowPreview(m_viewProps->showPreview());
- m_dolphinView->setShowHiddenFiles(m_viewProps->showHiddenFiles());
+ m_dolphinView->setAdditionalInfoList(m_viewProps->additionalInfoList());
+ m_dolphinView->setPreviewsShown(m_viewProps->previewsShown());
+ m_dolphinView->setHiddenFilesShown(m_viewProps->hiddenFilesShown());
m_viewProps->save();
m_sortFoldersFirst->setChecked(m_viewProps->sortFoldersFirst());
// load show preview, show in groups and show hidden files settings
- m_showPreview->setChecked(m_viewProps->showPreview());
+ m_previewsShown->setChecked(m_viewProps->previewsShown());
m_showInGroups->setChecked(m_viewProps->categorizedSorting());
m_showInGroups->setEnabled(index == DolphinView::IconsView); // only the icons view supports categorized sorting
- m_showHiddenFiles->setChecked(m_viewProps->showHiddenFiles());
+ m_showHiddenFiles->setChecked(m_viewProps->hiddenFilesShown());
markAsDirty(false);
}
KComboBox* m_sortOrder;
KComboBox* m_sorting;
QCheckBox* m_sortFoldersFirst;
- QCheckBox* m_showPreview;
+ QCheckBox* m_previewsShown;
QCheckBox* m_showInGroups;
QCheckBox* m_showHiddenFiles;
QPushButton* m_additionalInfo;
m_view(view),
m_messageLabel(0),
m_spaceInfo(0),
- m_zoomWidget(0),
- m_zoomOut(0),
m_zoomSlider(0),
- m_zoomIn(0),
m_progressBar(0),
m_stopButton(0),
m_progress(100),
// Initialize message label
m_messageLabel = new KonqStatusBarMessageLabel(this);
- // Initialize zoom slider
- m_zoomWidget = new QWidget(this);
-
- m_zoomOut = new QToolButton(m_zoomWidget);
- m_zoomOut->setIcon(KIcon("file-zoom-out"));
- m_zoomOut->setAutoRaise(true);
-
- m_zoomSlider = new QSlider(Qt::Horizontal, m_zoomWidget);
+ // Initialize zoom widget
+ m_zoomSlider = new QSlider(Qt::Horizontal, this);
m_zoomSlider->setPageStep(1);
const int min = ZoomLevelInfo::minimumLevel();
m_zoomSlider->setValue(view->zoomLevel());
updateZoomSliderToolTip(view->zoomLevel());
- m_zoomIn = new QToolButton(m_zoomWidget);
- m_zoomIn->setIcon(KIcon("file-zoom-in"));
- m_zoomIn->setAutoRaise(true);
-
- // Initialize zoom widget layout
- QHBoxLayout* zoomWidgetLayout = new QHBoxLayout(m_zoomWidget);
- zoomWidgetLayout->setSpacing(0);
- zoomWidgetLayout->setMargin(0);
- zoomWidgetLayout->addWidget(m_zoomOut);
- zoomWidgetLayout->addWidget(m_zoomSlider);
- zoomWidgetLayout->addWidget(m_zoomIn);
-
connect(m_zoomSlider, SIGNAL(valueChanged(int)), this, SLOT(setZoomLevel(int)));
connect(m_zoomSlider, SIGNAL(sliderMoved(int)), this, SLOT(showZoomSliderToolTip(int)));
- connect(m_view, SIGNAL(zoomLevelChanged(int)), m_zoomSlider, SLOT(setValue(int)));
- connect(m_zoomOut, SIGNAL(clicked()), this, SLOT(zoomOut()));
- connect(m_zoomIn, SIGNAL(clicked()), this, SLOT(zoomIn()));
+ connect(m_view, SIGNAL(zoomLevelChanged(int, int)), this, SLOT(slotZoomLevelChanged(int, int)));
// Initialize space information
m_spaceInfo = new StatusBarSpaceInfo(this);
// Initialize top layout and size policies
const int fontHeight = QFontMetrics(m_messageLabel->font()).height();
- const int zoomWidgetHeight = m_zoomWidget->minimumSizeHint().height();
- const int contentHeight = qMax(fontHeight, zoomWidgetHeight);
+ const int zoomSliderHeight = m_zoomSlider->minimumSizeHint().height();
+ const int contentHeight = qMax(fontHeight, zoomSliderHeight);
m_messageLabel->setMinimumTextHeight(contentHeight);
m_spaceInfo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
m_progressBar->setMaximumSize(200, contentHeight);
- m_zoomWidget->setMaximumSize(150, contentHeight);
+ m_zoomSlider->setMaximumSize(150, contentHeight);
m_zoomSlider->setMinimumWidth(30);
QHBoxLayout* topLayout = new QHBoxLayout(this);
topLayout->setMargin(0);
topLayout->setSpacing(4);
topLayout->addWidget(m_messageLabel);
- topLayout->addWidget(m_zoomWidget);
+ topLayout->addWidget(m_zoomSlider);
topLayout->addWidget(m_spaceInfo);
topLayout->addWidget(m_stopButton);
topLayout->addWidget(m_progressText);
} else if (action == showZoomSliderAction) {
const bool visible = showZoomSliderAction->isChecked();
settings->setShowZoomSlider(visible);
- m_zoomWidget->setVisible(visible);
+ m_zoomSlider->setVisible(visible);
} else if (action == showSpaceInfoAction) {
const bool visible = showSpaceInfoAction->isChecked();
settings->setShowSpaceInfo(visible);
void DolphinStatusBar::setZoomLevel(int zoomLevel)
{
- m_zoomOut->setEnabled(zoomLevel > m_zoomSlider->minimum());
- m_zoomIn->setEnabled(zoomLevel < m_zoomSlider->maximum());
m_view->setZoomLevel(zoomLevel);
updateZoomSliderToolTip(zoomLevel);
}
-void DolphinStatusBar::zoomOut()
-{
- const int value = m_zoomSlider->value();
- m_zoomSlider->setValue(value - 1);
-}
-
-void DolphinStatusBar::zoomIn()
-{
- const int value = m_zoomSlider->value();
- m_zoomSlider->setValue(value + 1);
-}
-
void DolphinStatusBar::showZoomSliderToolTip(int zoomLevel)
{
updateZoomSliderToolTip(zoomLevel);
QApplication::sendEvent(m_zoomSlider, &toolTipEvent);
}
+void DolphinStatusBar::slotZoomLevelChanged(int current, int previous)
+{
+ Q_UNUSED(previous);
+ m_zoomSlider->setValue(current);
+}
+
void DolphinStatusBar::updateProgressInfo()
{
const bool isErrorShown = (m_messageLabel->type() == KonqStatusBarMessageLabel::Error);
void DolphinStatusBar::setExtensionsVisible(bool visible)
{
bool showSpaceInfo = visible;
- bool showZoomWidget = visible;
+ bool showZoomSlider = visible;
if (visible) {
const GeneralSettings* settings = DolphinSettings::instance().generalSettings();
showSpaceInfo = settings->showSpaceInfo();
- showZoomWidget = settings->showZoomSlider();
+ showZoomSlider = settings->showZoomSlider();
}
m_spaceInfo->setVisible(showSpaceInfo);
- m_zoomWidget->setVisible(showZoomWidget);
+ m_zoomSlider->setVisible(showZoomSlider);
}
void DolphinStatusBar::updateZoomSliderToolTip(int zoomLevel)
*/
void setZoomLevel(int zoomLevel);
- void zoomOut();
- void zoomIn();
void showZoomSliderToolTip(int zoomLevel);
+ void slotZoomLevelChanged(int current, int previous);
void updateProgressInfo();
KonqStatusBarMessageLabel* m_messageLabel;
StatusBarSpaceInfo* m_spaceInfo;
- QWidget* m_zoomWidget;
- QToolButton* m_zoomOut;
QSlider* m_zoomSlider;
- QToolButton* m_zoomIn;
QLabel* m_progressText;
QProgressBar* m_progressBar;
set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} )
include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BUILD_DIR}/.. ${KDE4_INCLUDES} )
-# DolphinDetailsView
-kde4_add_unit_test(dolphindetailsviewtest TEST dolphindetailsviewtest.cpp testdir.cpp testbase.cpp ../views/zoomlevelinfo.cpp)
-target_link_libraries(dolphindetailsviewtest dolphinprivate ${KDE4_KIO_LIBS} ${QT_QTTEST_LIBRARY})
+# KFileItemListViewTest
+set(kfileitemlistviewtest_SRCS
+ kfileitemlistviewtest.cpp
+ testdir.cpp
+ ../kitemviews/kfileitemmodel.cpp
+ ../kitemviews/kfileitemlistview.cpp
+ ../kitemviews/kitemmodelbase.cpp
+ ../kitemviews/kitemlistview.cpp
+)
+kde4_add_unit_test(kfileitemlistviewtest TEST ${kfileitemlistviewtest_SRCS})
+target_link_libraries(kfileitemlistviewtest dolphinprivate ${KDE4_KIO_LIBS} ${QT_QTTEST_LIBRARY})
+
+# KFileItemModelTest
+set(kfileitemmodeltest_SRCS
+ kfileitemmodeltest.cpp
+ testdir.cpp
+ ../kitemviews/kfileitemmodel.cpp
+ ../kitemviews/kitemmodelbase.cpp
+)
+kde4_add_unit_test(kfileitemmodeltest TEST ${kfileitemmodeltest_SRCS})
+target_link_libraries(kfileitemmodeltest dolphinprivate ${KDE4_KIO_LIBS} ${QT_QTTEST_LIBRARY})
# DolphinSearchBox
if (Nepomuk_FOUND)
kde4_add_unit_test(dolphinsearchboxtest TEST ${dolphinsearchboxtest_SRCS})
target_link_libraries(dolphinsearchboxtest ${KDE4_KIO_LIBS} ${SOPRANO_LIBRARIES} ${NEPOMUK_LIBRARIES} ${NEPOMUK_QUERY_LIBRARIES} nepomukutils ${QT_QTTEST_LIBRARY})
endif (Nepomuk_FOUND)
-
-
-# DolphinTreeView
-kde4_add_unit_test(dolphintreeviewtest TEST dolphintreeviewtest.cpp)
-target_link_libraries(dolphintreeviewtest dolphinprivate ${KDE4_KDEUI_LIBS} ${QT_QTTEST_LIBRARY})
-
-# DolphinView - columns
-kde4_add_unit_test(dolphinviewtest_columns TEST dolphinviewtest_columns.cpp dolphinviewtest_allviewmodes.cpp testdir.cpp testbase.cpp ../views/zoomlevelinfo.cpp)
-target_link_libraries(dolphinviewtest_columns dolphinprivate ${KDE4_KIO_LIBS} ${QT_QTTEST_LIBRARY})
-
-# DolphinView - details
-kde4_add_unit_test(dolphinviewtest_details TEST dolphinviewtest_details.cpp dolphinviewtest_allviewmodes.cpp testdir.cpp testbase.cpp ../views/zoomlevelinfo.cpp)
-target_link_libraries(dolphinviewtest_details dolphinprivate ${KDE4_KIO_LIBS} ${QT_QTTEST_LIBRARY})
-
-# DolphinView - icons
-kde4_add_unit_test(dolphinviewtest_icons TEST dolphinviewtest_icons.cpp dolphinviewtest_allviewmodes.cpp testdir.cpp testbase.cpp ../views/zoomlevelinfo.cpp)
-target_link_libraries(dolphinviewtest_icons dolphinprivate ${KDE4_KIO_LIBS} ${QT_QTTEST_LIBRARY})
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2010 by Frank Reininghaus (frank78ac@googlemail.com) *
- * *
- * 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 <qtest_kde.h>
-
-#include "testbase.h"
-#include "testdir.h"
-
-#include "views/dolphindetailsview.h"
-#include "views/dolphinview.h"
-#include "views/dolphinmodel.h"
-#include "views/dolphinsortfilterproxymodel.h"
-#include "views/zoomlevelinfo.h"
-
-#include <qtestmouse.h>
-#include <qtestkeyboard.h>
-
-class DolphinDetailsViewTest : public TestBase
-{
- Q_OBJECT
-
-private slots:
-
- void testExpandedUrls();
-
- void bug217447_shiftArrowSelection();
- void bug234600_overlappingIconsWhenZooming();
- void bug257401_longFilenamesKeyboardNavigation();
-
-private:
-
- /**
- * initView(DolphinView*) sets the correct view mode, shows the view on the screen, and waits
- * until loading the folder in the view is finished.
- *
- * Many unit tests need access to the internal DolphinDetailsView in DolphinView.
- * Therefore, a pointer to the details view is returned by initView(DolphinView*).
- */
- DolphinDetailsView* initView(DolphinView* view) const {
- QSignalSpy spyFinishedPathLoading(view, SIGNAL(finishedPathLoading(const KUrl&)));
- view->setMode(DolphinView::DetailsView);
- DolphinDetailsView* detailsView = qobject_cast<DolphinDetailsView*>(itemView(view));
- Q_ASSERT(detailsView);
- detailsView->setFoldersExpandable(true);
- view->resize(400, 400);
- view->show();
- QTest::qWaitForWindowShown(view);
-
- // If the DolphinView's finishedPathLoading(const KUrl&) signal has not been received yet,
- // we have to wait a bit more.
- // The reason why the if-statement is needed here is that the signal might have been emitted
- // while we were waiting in QTest::qWaitForWindowShown(view)
- // -> waitForFinishedPathLoading(view) would fail in that case.
- if (spyFinishedPathLoading.isEmpty()) {
- waitForFinishedPathLoading(view);
- }
-
- return detailsView;
- }
-
- QModelIndex proxyModelIndexForUrl(const DolphinView* view, const KUrl& url) const {
- const QModelIndex index = view->m_viewAccessor.m_dolphinModel->indexForUrl(url);
- return view->m_viewAccessor.m_proxyModel->mapFromSource(index);
- }
-};
-
-/**
- * This test verifies that DolphinDetailsView::expandedUrls() returns the right set of URLs.
- * The test creates a folder hierarchy: 3 folders (a, b, c) contain 3 subfolders (also named a, b, c) each.
- * Each of those contains 3 further subfolders of the same name.
- */
-
-void DolphinDetailsViewTest::testExpandedUrls()
-{
- QStringList files;
- QStringList subFolderNames;
- subFolderNames << "a" << "b" << "c";
-
- foreach(const QString& level1, subFolderNames) {
- foreach(const QString& level2, subFolderNames) {
- foreach(const QString& level3, subFolderNames) {
- files << level1 + "/" + level2 + "/" + level3 + "/testfile";
- }
- }
- }
-
- TestDir dir;
- dir.createFiles(files);
- DolphinView view(dir.url(), 0);
- DolphinDetailsView* detailsView = initView(&view);
-
- // We start with an empty set of expanded URLs.
- QSet<KUrl> expectedExpandedUrls;
- QCOMPARE(detailsView->expandedUrls(), expectedExpandedUrls);
-
- // Expand URLs one by one and verify the result of DolphinDetailsView::expandedUrls()
- QStringList itemsToExpand;
- itemsToExpand << "b" << "b/a" << "b/a/c" << "b/c" << "c";
-
- foreach(const QString& item, itemsToExpand) {
- KUrl url(dir.name() + item);
- detailsView->expand(proxyModelIndexForUrl(&view, url));
- expectedExpandedUrls += url;
- QCOMPARE(detailsView->expandedUrls(), expectedExpandedUrls);
-
- // Before we proceed, we have to make sure that the view has finished
- // loading the contents of the expanded folder.
- waitForFinishedPathLoading(&view);
- }
-
- // Collapse URLs one by one and verify the result of DolphinDetailsView::expandedUrls()
- QStringList itemsToCollapse;
- itemsToCollapse << "b/c" << "b/a/c" << "c" << "b/a" << "b";
-
- foreach(const QString& item, itemsToCollapse) {
- KUrl url(dir.name() + item);
- detailsView->collapse(proxyModelIndexForUrl(&view, url));
- expectedExpandedUrls -= url;
- QCOMPARE(detailsView->expandedUrls(), expectedExpandedUrls);
- }
-}
-
-/**
- * When the first item in the view is active and Shift is held while the "arrow down"
- * key is pressed repeatedly, the selection should grow by one item for each key press.
- * A change in Qt 4.6 revealed a bug in DolphinDetailsView which broke this, see
- *
- * https://bugs.kde.org/show_bug.cgi?id=217447
- *
- * The problem was that DolphinDetailsView, which uses not the full width of the "Name"
- * column for an item, but only the width of the actual file name, did not reimplement
- * QTreeView::visualRect(). This caused item selection to fail because QAbstractItemView
- * uses the center of the visualRect of an item internally. If the width of the file name
- * is less than half the width of the "Name" column, the center of an item's visualRect
- * was therefore outside the space that DolphinDetailsView actually assigned to the
- * item, and this led to unexpected deselection of items.
- *
- * TODO: To make the test more reliable, one could adjust the width of the "Name"
- * column before the test in order to really make sure that the column is more than twice
- * as wide as the space actually occupied by the file names (this triggers the bug).
- */
-
-void DolphinDetailsViewTest::bug217447_shiftArrowSelection()
-{
- TestDir dir;
- for (int i = 0; i < 100; i++) {
- dir.createFile(QString("%1").arg(i));
- }
- DolphinView view(dir.url(), 0);
- DolphinDetailsView* detailsView = initView(&view);
-
- // Select the first item
- QModelIndex index0 = detailsView->model()->index(0, 0);
- detailsView->setCurrentIndex(index0);
- QCOMPARE(detailsView->currentIndex(), index0);
-
- // Before we test Shift-selection, we verify that the root cause is fixed a bit more
- // directly: we check that passing the corners or the center of an item's visualRect
- // to itemAt() returns the item (and not an invalid model index).
- QRect rect = detailsView->visualRect(index0);
- QCOMPARE(detailsView->indexAt(rect.center()), index0);
- QCOMPARE(detailsView->indexAt(rect.topLeft()), index0);
- QCOMPARE(detailsView->indexAt(rect.topRight()), index0);
- QCOMPARE(detailsView->indexAt(rect.bottomLeft()), index0);
- QCOMPARE(detailsView->indexAt(rect.bottomRight()), index0);
-
- // Another way to test this is to Ctrl-click the center of the visualRect.
- // The selection state of the item should be toggled.
- detailsView->clearSelection();
- QItemSelectionModel* selectionModel = detailsView->selectionModel();
- QCOMPARE(selectionModel->selectedIndexes().count(), 0);
-
- QTest::mouseClick(detailsView->viewport(), Qt::LeftButton, Qt::ControlModifier, rect.center());
- QModelIndexList selectedIndexes = selectionModel->selectedIndexes();
- QCOMPARE(selectedIndexes.count(), 1);
- QVERIFY(selectedIndexes.contains(index0));
-
- // Now we go down item by item using Shift+Down. In each step, we check that the current item
- // is added to the selection and that the size of the selection grows by one.
-
- int current = 1;
-
- while (current < 100) {
- QTest::keyClick(detailsView->viewport(), Qt::Key_Down, Qt::ShiftModifier);
- QModelIndex currentIndex = detailsView->model()->index(current, 0);
- QCOMPARE(detailsView->currentIndex(), currentIndex);
-
- selectedIndexes = selectionModel->selectedIndexes();
- QCOMPARE(selectedIndexes.count(), current + 1);
- QVERIFY(selectedIndexes.contains(currentIndex));
-
- current++;
- }
-}
-
-/**
- * When the icon size is changed, we have to make sure that the maximumSize given
- * to KFileItemDelegate for rendering each item is updated correctly. If this is not
- * done, the visualRects are clipped by the incorrect maximum size, and the icons
- * may overlap, see
- *
- * https://bugs.kde.org/show_bug.cgi?id=234600
- */
-
-void DolphinDetailsViewTest::bug234600_overlappingIconsWhenZooming()
-{
- QStringList files;
- files << "a" << "b" << "c" << "d";
-
- TestDir dir;
- dir.createFiles(files);
- DolphinView view(dir.url(), 0);
- DolphinDetailsView* detailsView = initView(&view);
-
- QModelIndex index0 = detailsView->model()->index(0, 0);
- detailsView->setCurrentIndex(index0);
- QCOMPARE(detailsView->currentIndex(), index0);
-
- // Setting the zoom level to the minimum value and triggering DolphinDetailsView::currentChanged(...)
- // should make sure that the bug is triggered.
- int zoomLevelBackup = view.zoomLevel();
- int zoomLevel = ZoomLevelInfo::minimumLevel();
- view.setZoomLevel(zoomLevel);
-
- QModelIndex index1 = detailsView->model()->index(1, 0);
- detailsView->setCurrentIndex(index1);
- QCOMPARE(detailsView->currentIndex(), index1);
-
- // Increase the zoom level successively to the maximum.
- while(zoomLevel < ZoomLevelInfo::maximumLevel()) {
- zoomLevel++;
- view.setZoomLevel(zoomLevel);
- QCOMPARE(view.zoomLevel(), zoomLevel);
-
- //Check for each zoom level that the height of each item is at least the icon size.
- QVERIFY(detailsView->visualRect(index1).height() >= ZoomLevelInfo::iconSizeForZoomLevel(zoomLevel));
- }
-
- view.setZoomLevel(zoomLevelBackup);
-}
-
-/**
- * The width of the visualRect of an item is usually replaced by the width of the file name.
- * However, if the file name is wider then the view's name column, this leads to problems with
- * keyboard navigation if files with very long names are present in the current folder, see
- *
- * https://bugs.kde.org/show_bug.cgi?id=257401
- *
- * This test checks that the visualRect of an item is never wider than the "Name" column.
- */
-
-void DolphinDetailsViewTest::bug257401_longFilenamesKeyboardNavigation() {
- TestDir dir;
- QString name;
- for (int i = 0; i < 20; i++) {
- name += "mmmmmmmmmm";
- dir.createFile(name);
- }
- DolphinView view(dir.url(), 0);
- DolphinDetailsView* detailsView = initView(&view);
-
- // Select the first item
- QModelIndex index0 = detailsView->model()->index(0, 0);
- detailsView->setCurrentIndex(index0);
- QCOMPARE(detailsView->currentIndex(), index0);
- QVERIFY(detailsView->visualRect(index0).width() < detailsView->columnWidth(DolphinModel::Name));
-
- QItemSelectionModel* selectionModel = detailsView->selectionModel();
- QModelIndexList selectedIndexes = selectionModel->selectedIndexes();
- QCOMPARE(selectedIndexes.count(), 1);
- QVERIFY(selectedIndexes.contains(index0));
-
- // Move down successively using the "Down" key and check that current item
- // and selection are as expected.
- for (int i = 0; i < 19; i++) {
- QTest::keyClick(detailsView->viewport(), Qt::Key_Down, Qt::NoModifier);
- QModelIndex currentIndex = detailsView->model()->index(i + 1, 0);
- QCOMPARE(detailsView->currentIndex(), currentIndex);
- QVERIFY(detailsView->visualRect(currentIndex).width() <= detailsView->columnWidth(DolphinModel::Name));
- selectedIndexes = selectionModel->selectedIndexes();
- QCOMPARE(selectedIndexes.count(), 1);
- QVERIFY(selectedIndexes.contains(currentIndex));
- }
-}
-
-QTEST_KDEMAIN(DolphinDetailsViewTest, GUI)
-
-#include "dolphindetailsviewtest.moc"
+++ /dev/null
-/*****************************************************************************
- * Copyright (C) 2010-2011 by Frank Reininghaus (frank78ac@googlemail.com) *
- * *
- * 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 <qtest_kde.h>
-#include <KDebug>
-#include <KAction>
-
-#include "views/dolphintreeview.h"
-
-#include <qtestkeyboard.h>
-#include <qtestmouse.h>
-#include <QStringListModel>
-
-class DolphinTreeViewTest : public QObject
-{
- Q_OBJECT
-
-private slots:
-
- void testKeyboardNavigationSelectionUpdate();
-
- void bug218114_visualRegionForSelection();
- void bug220898_focusOut();
-
-private:
-
- /** A method that simplifies checking a view's current item and selection */
- static void verifyCurrentItemAndSelection(const QAbstractItemView& view, const QModelIndex& expectedCurrent, const QModelIndexList& expectedSelection) {
- QCOMPARE(view.currentIndex(), expectedCurrent);
- const QModelIndexList selectedIndexes = view.selectionModel()->selectedIndexes();
- QCOMPARE(selectedIndexes.count(), expectedSelection.count());
- foreach(const QModelIndex& index, expectedSelection) {
- QVERIFY(selectedIndexes.contains(index));
- }
- }
-
- /** Use this method if only one item is selected */
- static void verifyCurrentItemAndSelection(const QAbstractItemView& view, const QModelIndex& current, const QModelIndex& selected) {
- QModelIndexList list;
- list << selected;
- verifyCurrentItemAndSelection(view, current, list);
- }
-
- /** Use this method if the only selected item is the current item */
- static void verifyCurrentItemAndSelection(const QAbstractItemView& view, const QModelIndex& current) {
- verifyCurrentItemAndSelection(view, current, current);
- }
-
-};
-
-/**
- * TestView is a simple view class derived from DolphinTreeView.
- * It makes sure that the visualRect for each index contains only the item text as
- * returned by QAbstractItemModel::data(...) for the role Qt::DisplayRole.
- *
- * We have to check that DolphinTreeView handles the case of visualRects with different widths
- * correctly because this is the case in DolphinDetailsView which is derived from DolphinTreeView.
- */
-
-class TestView : public DolphinTreeView
-{
- Q_OBJECT
-
-public:
-
- TestView(QWidget* parent = 0) : DolphinTreeView(parent) {};
- ~TestView() {};
-
- QRect visualRect(const QModelIndex& index) const {
- QRect rect = DolphinTreeView::visualRect(index);
-
- const QStyleOptionViewItem option = viewOptions();
- const QFontMetrics fontMetrics(option.font);
- int width = option.decorationSize.width() + fontMetrics.width(model()->data(index).toString());
-
- rect.setWidth(width);
- return rect;
- }
-
-};
-
-/**
- * This test checks that updating the selection after key presses works as expected.
- * Qt does not handle this internally if the first letter of an item is pressed, which
- * is why DolphinTreeView has some custom code for this. The test verifies that this
- * works without unwanted side effects.
- *
- * The test uses the class TreeViewWithDeleteShortcut which deletes the selected items
- * when Shift-Delete is pressed. This is needed to test the fix for bug 259656 (see below).
- */
-
-class TreeViewWithDeleteShortcut : public DolphinTreeView {
-
- Q_OBJECT
-
-public:
-
- TreeViewWithDeleteShortcut(QWidget* parent = 0) : DolphinTreeView(parent) {
- // To test the fix for bug 259656, we need a delete shortcut.
- KAction* deleteAction = new KAction(this);
- deleteAction->setShortcut(Qt::SHIFT | Qt::Key_Delete);
- addAction(deleteAction);
- connect(deleteAction, SIGNAL(triggered()), this, SLOT(deleteSelectedItems()));
- };
-
- ~TreeViewWithDeleteShortcut() {};
-
-public slots:
-
- void deleteSelectedItems() {
- // We have to delete the items one by one and update the list of selected items after
- // each step because every removal will invalidate the model indexes in the list.
- QModelIndexList selectedItems = selectionModel()->selectedIndexes();
- while (!selectedItems.isEmpty()) {
- const QModelIndex index = selectedItems.takeFirst();
- model()->removeRow(index.row());
- selectedItems = selectionModel()->selectedIndexes();
- }
- }
-};
-
-void DolphinTreeViewTest::testKeyboardNavigationSelectionUpdate() {
- QStringList items;
- items << "a" << "b" << "c" << "d" << "e";
- QStringListModel model(items);
-
- QModelIndex index[5];
- for (int i = 0; i < 5; i++) {
- index[i] = model.index(i, 0);
- }
-
- TreeViewWithDeleteShortcut view;
- view.setModel(&model);
- view.setSelectionMode(QAbstractItemView::ExtendedSelection);
- view.resize(400, 400);
- view.show();
- QTest::qWaitForWindowShown(&view);
-
- view.clearSelection();
- QVERIFY(view.selectionModel()->selectedIndexes().isEmpty());
-
- /**
- * Check that basic keyboard navigation with arrow keys works.
- */
-
- view.setCurrentIndex(index[0]);
- verifyCurrentItemAndSelection(view, index[0]);
-
- // Go down -> item 1 ("b") should be selected
- kDebug() << "Down";
- QTest::keyClick(view.viewport(), Qt::Key_Down);
- verifyCurrentItemAndSelection(view, index[1]);
-
- // Go down -> item 2 ("c") should be selected
- kDebug() << "Down";
- QTest::keyClick(view.viewport(), Qt::Key_Down);
- verifyCurrentItemAndSelection(view, index[2]);
-
- // Ctrl-Up -> item 2 ("c") remains selected
- kDebug() << "Ctrl-Up";
- QTest::keyClick(view.viewport(), Qt::Key_Up, Qt::ControlModifier);
- verifyCurrentItemAndSelection(view, index[1], index[2]);
-
- // Go up -> item 0 ("a") should be selected
- kDebug() << "Up";
- QTest::keyClick(view.viewport(), Qt::Key_Up);
- verifyCurrentItemAndSelection(view, index[0]);
-
- // Shift-Down -> items 0 and 1 ("a" and "b") should be selected
- kDebug() << "Shift-Down";
- QTest::keyClick(view.viewport(), Qt::Key_Down, Qt::ShiftModifier);
- QModelIndexList expectedSelection;
- expectedSelection << index[0] << index[1];
- verifyCurrentItemAndSelection(view, index[1], expectedSelection);
-
- /**
- * When the first letter of a file name is pressed, this file becomes the current item
- * and gets selected. If the user then Shift-clicks another item, it is expected that
- * all items between these two items get selected. Before the bug
- *
- * https://bugs.kde.org/show_bug.cgi?id=201459
- *
- * was fixed, this was not the case: the starting point for the Shift-selection was not
- * updated if an item was selected by pressing the first letter of the file name.
- */
-
- view.clearSelection();
- QVERIFY(view.selectionModel()->selectedIndexes().isEmpty());
-
- // Control-click item 0 ("a")
- kDebug() << "Ctrl-click on \"a\"";
- QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ControlModifier, view.visualRect(index[0]).center());
- verifyCurrentItemAndSelection(view, index[0]);
-
- // Press "c", such that item 2 ("c") should be the current one.
- kDebug() << "Press \"c\"";
- QTest::keyClick(view.viewport(), Qt::Key_C);
- verifyCurrentItemAndSelection(view, index[2]);
-
- // Now Shift-Click the last item ("e"). We expect that 3 items ("c", "d", "e") are selected.
- kDebug() << "Shift-click on \"e\"";
- QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ShiftModifier, view.visualRect(index[4]).center());
- expectedSelection.clear();
- expectedSelection << index[2] << index[3] << index[4];
- verifyCurrentItemAndSelection(view, index[4], expectedSelection);
-
- /**
- * Starting a drag&drop operation should not clear the selection, see
- *
- * https://bugs.kde.org/show_bug.cgi?id=158649
- */
-
- view.clearSelection();
- QVERIFY(view.selectionModel()->selectedIndexes().isEmpty());
-
- // Click item 0 ("a")
- kDebug() << "Click on \"a\"";
- QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, view.visualRect(index[0]).center());
- verifyCurrentItemAndSelection(view, index[0]);
-
- // Shift-Down -> "a" and "b" should be selected
- kDebug() << "Shift-Down";
- QTest::keyClick(view.viewport(), Qt::Key_Down, Qt::ShiftModifier);
- expectedSelection.clear();
- expectedSelection << index[0] << index[1];
- verifyCurrentItemAndSelection(view, index[1], expectedSelection);
-
- // Press mouse button on item 0 ("a"), but do not release it. Check that the selection is unchanged
- kDebug() << "Mouse press on \"a\"";
- QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::NoModifier, view.visualRect(index[0]).center());
- verifyCurrentItemAndSelection(view, index[0], expectedSelection);
-
- // Move mouse to item 1 ("b"), check that selection is unchanged
- kDebug() << "Move mouse to \"b\"";
- QMouseEvent moveEvent(QEvent::MouseMove, view.visualRect(index[1]).center(), Qt::NoButton, Qt::LeftButton, Qt::NoModifier);
- bool moveEventReceived = qApp->notify(view.viewport(), &moveEvent);
- QVERIFY(moveEventReceived);
- verifyCurrentItemAndSelection(view, index[0], expectedSelection);
-
- // Release mouse button on item 1 ("b"), check that selection is unchanged
- kDebug() << "Mouse release on \"b\"";
- QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::NoModifier, view.visualRect(index[1]).center());
- verifyCurrentItemAndSelection(view, index[0], expectedSelection);
-
- /**
- * Keeping Shift+Delete pressed for some time should delete only one item, see
- *
- * https://bugs.kde.org/show_bug.cgi?id=259656
- */
-
- view.clearSelection();
- QVERIFY(view.selectionModel()->selectedIndexes().isEmpty());
-
- // Click item 0 ("a")
- kDebug() << "Click on \"a\"";
- QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::NoModifier, view.visualRect(index[0]).center());
- verifyCurrentItemAndSelection(view, index[0]);
-
- // Press Shift-Delete and keep the keys pressed for some time
- kDebug() << "Press Shift-Delete";
- QTest::keyPress(view.viewport(), Qt::Key_Delete, Qt::ShiftModifier);
- QTest::qWait(200);
- QTest::keyRelease(view.viewport(), Qt::Key_Delete, Qt::ShiftModifier);
-
- // Verify that only one item has been deleted
- QCOMPARE(view.model()->rowCount(), 4);
-}
-
-/**
- * QTreeView assumes implicitly that the width of each item's visualRect is the same. This leads to painting
- * problems in Dolphin if items with different widths are in one QItemSelectionRange, see
- *
- * https://bugs.kde.org/show_bug.cgi?id=218114
- *
- * To fix this, DolphinTreeView has a custom implementation of visualRegionForSelection(). The following
- * unit test checks that.
- */
-
-void DolphinTreeViewTest::bug218114_visualRegionForSelection()
-{
- QStringList items;
- items << "a" << "an item with a long name" << "a";
- QStringListModel model(items);
-
- QModelIndex index0 = model.index(0, 0);
- QModelIndex index1 = model.index(1, 0);
- QModelIndex index2 = model.index(2, 0);
-
- TestView view;
- view.setModel(&model);
- view.setSelectionMode(QAbstractItemView::ExtendedSelection);
- view.resize(400, 400);
- view.show();
- QTest::qWaitForWindowShown(&view);
-
- // First check that the width of index1 is larger than that of index0 and index2 (this triggers the bug).
-
- QVERIFY(view.visualRect(index0).width() < view.visualRect(index1).width());
- QVERIFY(view.visualRect(index2).width() < view.visualRect(index1).width());
-
- // Select all items in one go.
-
- view.selectAll();
- const QItemSelection selection = view.selectionModel()->selection();
- QCOMPARE(selection.count(), 1);
- QCOMPARE(selection.indexes().count(), 3);
-
- // Verify that the visualRegionForSelection contains all visualRects.
- // We do this indirectly using QRegion::boundingRect() because
- // QRegion::contains(const QRect&) returns true even if the QRect is not
- // entirely inside the QRegion.
-
- const QRegion region = view.visualRegionForSelection(selection);
- const QRect boundingRect = region.boundingRect();
-
- QVERIFY(boundingRect.contains(view.visualRect(index0)));
- QVERIFY(boundingRect.contains(view.visualRect(index1)));
- QVERIFY(boundingRect.contains(view.visualRect(index2)));
-}
-
-/**
- * This test verifies that selection of multiple items with the mouse works
- * if a key was pressed and the keyboard focus moved to another window before the
- * key was released, see
- *
- * https://bugs.kde.org/show_bug.cgi?id=220898
- */
-
-void DolphinTreeViewTest::bug220898_focusOut()
-{
- QStringList items;
- items << "a" << "b" << "c" << "d" << "e";
- QStringListModel model(items);
-
- QModelIndex index[5];
- for (int i = 0; i < 5; i++) {
- index[i] = model.index(i, 0);
- }
-
- TestView view;
- view.setModel(&model);
- view.setSelectionMode(QAbstractItemView::ExtendedSelection);
- view.resize(400, 400);
- view.show();
- QTest::qWaitForWindowShown(&view);
-
- view.setCurrentIndex(index[0]);
- verifyCurrentItemAndSelection(view, index[0]);
-
- // Press Down
- QTest::keyPress(view.viewport(), Qt::Key_Down, Qt::NoModifier);
-
- // Move keyboard focus to another widget
- QWidget widget;
- widget.show();
- QTest::qWaitForWindowShown(&widget);
- widget.setFocus();
-
- // Wait until the widgets have received the focus events
- while (view.viewport()->hasFocus()) {
- QTest::qWait(10);
- }
- QVERIFY(!view.viewport()->hasFocus());
-
- // Release the "Down" key
- QTest::keyRelease(&widget, Qt::Key_Down, Qt::NoModifier);
-
- // Move keyboard focus back to the view
- widget.hide();
- view.viewport()->setFocus();
-
- // Wait until the widgets have received the focus events
- while (widget.hasFocus()) {
- QTest::qWait(10);
- }
- QVERIFY(!widget.hasFocus());
-
- // Press left mouse button below the last item
- const int lastRowHeight = view.sizeHintForRow(4);
- QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::NoModifier, view.visualRect(index[4]).center() + QPoint(0, lastRowHeight));
-
- // Move mouse to the first item and release
- QTest::mouseMove(view.viewport(), view.visualRect(index[0]).center());
- QMouseEvent moveEvent(QEvent::MouseMove, view.visualRect(index[0]).center(), Qt::NoButton, Qt::LeftButton, Qt::NoModifier);
- bool moveEventReceived = qApp->notify(view.viewport(), &moveEvent);
- QVERIFY(moveEventReceived);
- QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::NoModifier, view.visualRect(index[0]).center());
-
- // All items should be selected
- QModelIndexList expectedSelection;
- expectedSelection << index[0] << index[1] << index[2] << index[3] << index[4];
- verifyCurrentItemAndSelection(view, index[0], expectedSelection);
-}
-
-QTEST_KDEMAIN(DolphinTreeViewTest, GUI)
-
-#include "dolphintreeviewtest.moc"
+++ /dev/null
-/****************************************************************************
- * Copyright (C) 2010-2011 by Frank Reininghaus (frank78ac@googlemail.com) *
- * *
- * 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 <kdebug.h>
-
-#include "dolphinviewtest_allviewmodes.h"
-
-#include <qtest_kde.h>
-
-#include "testdir.h"
-
-#include "views/dolphinview.h"
-#include "views/dolphinmodel.h"
-#include "views/dolphindirlister.h"
-#include "views/dolphinsortfilterproxymodel.h"
-#include "views/zoomlevelinfo.h"
-
-#include <QScrollBar>
-
-#include <qtestmouse.h>
-#include <qtestkeyboard.h>
-
-DolphinViewTest_AllViewModes::DolphinViewTest_AllViewModes() {
- // Need to register KFileItemList for use with QSignalSpy
- qRegisterMetaType<KFileItemList>("KFileItemList");
-}
-
-/**
- * testSelection() checks the basic selection functionality of DolphinView, including:
- *
- * selectedItems()
- * selectedItemsCount()
- * selectAll()
- * invertSelection()
- * clearSelection()
- * hasSelection()
- *
- * and the signal selectionChanged(const KFileItemList& selection)
- */
-
-Q_DECLARE_METATYPE(KFileItemList)
-
-void DolphinViewTest_AllViewModes::testSelection() {
- TestDir dir;
- const int totalItems = 50;
- for (int i = 0; i < totalItems; i++) {
- dir.createFile(QString("%1").arg(i));
- }
-
- DolphinView view(dir.url(), 0);
- QAbstractItemView* itemView = initView(&view);
-
- // Start with an empty selection
- view.clearSelection();
-
- QCOMPARE(view.selectedItems().count(), 0);
- QCOMPARE(view.selectedItemsCount(), 0);
- QVERIFY(!view.hasSelection());
-
- // First some simple tests where either all or no items are selected
- view.selectAll();
- verifySelectedItemsCount(&view, totalItems);
-
- view.invertSelection();
- verifySelectedItemsCount(&view, 0);
-
- view.invertSelection();
- verifySelectedItemsCount(&view, totalItems);
-
- view.clearSelection();
- verifySelectedItemsCount(&view, 0);
-
- // Now we select individual items using mouse clicks
- QModelIndex index = itemView->model()->index(2, 0);
- itemView->scrollTo(index);
- QTest::mouseClick(itemView->viewport(), Qt::LeftButton, Qt::ControlModifier, itemView->visualRect(index).center());
- verifySelectedItemsCount(&view, 1);
-
- index = itemView->model()->index(totalItems - 5, 0);
- itemView->scrollTo(index);
- QTest::mouseClick(itemView->viewport(), Qt::LeftButton, Qt::ControlModifier, itemView->visualRect(index).center());
- verifySelectedItemsCount(&view, 2);
-
- index = itemView->model()->index(totalItems - 2, 0);
- itemView->scrollTo(index);
- QTest::mouseClick(itemView->viewport(), Qt::LeftButton, Qt::ShiftModifier, itemView->visualRect(index).center());
- verifySelectedItemsCount(&view, 5);
-
- view.invertSelection();
- verifySelectedItemsCount(&view, totalItems - 5);
-
- // Pressing Esc should clear the selection
- QTest::keyClick(itemView->viewport(), Qt::Key_Escape);
- verifySelectedItemsCount(&view, 0);
-}
-
-/**
- * Check that setting the directory view properties works.
- */
-
-void DolphinViewTest_AllViewModes::testViewPropertySettings()
-{
- // Create some files with different sizes and modification times to check the different sorting options
- QDateTime now = QDateTime::currentDateTime();
-
- TestDir dir;
- dir.createFile("a", "A file", now.addDays(-3));
- dir.createFile("b", "A larger file", now.addDays(0));
- dir.createDir("c", now.addDays(-2));
- dir.createFile("d", "The largest file in this directory", now.addDays(-1));
- dir.createFile("e", "An even larger file", now.addDays(-4));
- dir.createFile(".f");
-
- DolphinView view(dir.url(), 0);
- initView(&view);
-
- // First set all settings to the default.
- view.setSorting(DolphinView::SortByName);
- QCOMPARE(view.sorting(), DolphinView::SortByName);
-
- view.setSortOrder(Qt::AscendingOrder);
- QCOMPARE(view.sortOrder(), Qt::AscendingOrder);
-
- view.setSortFoldersFirst(true);
- QVERIFY(view.sortFoldersFirst());
-
- view.setShowPreview(false);
- QVERIFY(!view.showPreview());
-
- if (view.showHiddenFiles()) {
- // Changing the "hidden files" setting triggers the dir lister
- // -> we have to wait until loading the hidden files is finished
- view.setShowHiddenFiles(false);
- waitForFinishedPathLoading(&view);
- }
- QVERIFY(!view.showHiddenFiles());
-
- /** Check that the sort order is correct for different kinds of settings */
-
- // Sort by Name, ascending
- QCOMPARE(view.sorting(), DolphinView::SortByName);
- QCOMPARE(view.sortOrder(), Qt::AscendingOrder);
- QCOMPARE(viewItems(&view), QStringList() << "c" << "a" << "b" << "d" << "e");
-
- // Sort by Name, descending
- view.setSortOrder(Qt::DescendingOrder);
- QCOMPARE(view.sorting(), DolphinView::SortByName);
- QCOMPARE(view.sortOrder(), Qt::DescendingOrder);
- QCOMPARE(viewItems(&view), QStringList() << "c" << "e" << "d" << "b" << "a");
-
- // Sort by Size, descending
- view.setSorting(DolphinView::SortBySize);
- QCOMPARE(view.sorting(), DolphinView::SortBySize);
- QCOMPARE(view.sortOrder(), Qt::DescendingOrder);
- QCOMPARE(viewItems(&view), QStringList() << "c" << "d" << "e" << "b" << "a");
-
- // Sort by Size, ascending
- view.setSortOrder(Qt::AscendingOrder);
- QCOMPARE(view.sorting(), DolphinView::SortBySize);
- QCOMPARE(view.sortOrder(), Qt::AscendingOrder);
- QCOMPARE(viewItems(&view), QStringList() << "c" << "a" << "b" << "e" << "d");
-
- // Sort by Date, ascending
- view.setSorting(DolphinView::SortByDate);
- QCOMPARE(view.sorting(), DolphinView::SortByDate);
- QCOMPARE(view.sortOrder(), Qt::AscendingOrder);
- QCOMPARE(viewItems(&view), QStringList() << "c" << "e" << "a" << "d" << "b");
-
- // Sort by Date, descending
- view.setSortOrder(Qt::DescendingOrder);
- QCOMPARE(view.sorting(), DolphinView::SortByDate);
- QCOMPARE(view.sortOrder(), Qt::DescendingOrder);
- QCOMPARE(viewItems(&view), QStringList() << "c" << "b" << "d" << "a" << "e");
-
- // Disable "Sort Folders First"
- view.setSortFoldersFirst(false);
- QVERIFY(!view.sortFoldersFirst());
- QCOMPARE(viewItems(&view), QStringList()<< "b" << "d" << "c" << "a" << "e");
-
- // Try again with Sort by Name, ascending
- view.setSorting(DolphinView::SortByName);
- view.setSortOrder(Qt::AscendingOrder);
- QCOMPARE(view.sorting(), DolphinView::SortByName);
- QCOMPARE(view.sortOrder(), Qt::AscendingOrder);
- QCOMPARE(viewItems(&view), QStringList() << "a" << "b" << "c" << "d" << "e");
-
- // Show hidden files. This triggers the dir lister
- // -> we have to wait until loading the hidden files is finished
- view.setShowHiddenFiles(true);
- waitForFinishedPathLoading(&view);
- QVERIFY(view.showHiddenFiles());
-
- // Depending on the settings, a .directory file might have been created.
- // Remove it from the list to get consistent results.
- QStringList result = viewItems(&view);
- result.removeAll(".directory");
- QCOMPARE(result, QStringList() << ".f" << "a" << "b" << "c" << "d" << "e");
-
- // Previews
- view.setShowPreview(true);
- QVERIFY(view.showPreview());
-
- // TODO: Check that the view properties are restored correctly when changing the folder and then going back.
-}
-
-/**
- * testZoomLevel() checks that setting the zoom level works, both using DolphinView's API and using Ctrl+mouse wheel.
- */
-
-void DolphinViewTest_AllViewModes::testZoomLevel()
-{
- TestDir dir;
- dir.createFiles(QStringList() << "a" << "b");
- DolphinView view(dir.url(), 0);
- QAbstractItemView* itemView = initView(&view);
-
- view.setShowPreview(false);
- QVERIFY(!view.showPreview());
-
- int zoomLevelBackup = view.zoomLevel();
-
- int zoomLevel = ZoomLevelInfo::minimumLevel();
- view.setZoomLevel(zoomLevel);
- QCOMPARE(view.zoomLevel(), zoomLevel);
-
- // Increase the zoom level successively to the maximum.
- while(zoomLevel < ZoomLevelInfo::maximumLevel()) {
- zoomLevel++;
- view.setZoomLevel(zoomLevel);
- QCOMPARE(view.zoomLevel(), zoomLevel);
- }
-
- // Try setting a zoom level larger than the maximum
- view.setZoomLevel(ZoomLevelInfo::maximumLevel() + 1);
- QCOMPARE(view.zoomLevel(), ZoomLevelInfo::maximumLevel());
-
- // Turn previews on and try setting a zoom level smaller than the minimum
- view.setShowPreview(true);
- QVERIFY(view.showPreview());
- view.setZoomLevel(ZoomLevelInfo::minimumLevel() - 1);
- QCOMPARE(view.zoomLevel(), ZoomLevelInfo::minimumLevel());
-
- // Turn previews off again and check that the zoom level is restored
- view.setShowPreview(false);
- QVERIFY(!view.showPreview());
- QCOMPARE(view.zoomLevel(), ZoomLevelInfo::maximumLevel());
-
- // Change the zoom level using Ctrl+mouse wheel
- QModelIndex index = itemView->model()->index(0, 0);
- itemView->scrollTo(index);
-
- while (view.zoomLevel() > ZoomLevelInfo::minimumLevel()) {
- int oldZoomLevel = view.zoomLevel();
- QWheelEvent wheelEvent(itemView->visualRect(index).center(), -1, Qt::NoButton, Qt::ControlModifier);
- bool wheelEventReceived = qApp->notify(itemView->viewport(), &wheelEvent);
- QVERIFY(wheelEventReceived);
- QVERIFY(view.zoomLevel() < oldZoomLevel);
- }
- QCOMPARE(view.zoomLevel(), ZoomLevelInfo::minimumLevel());
-
- while (view.zoomLevel() < ZoomLevelInfo::maximumLevel()) {
- int oldZoomLevel = view.zoomLevel();
- QWheelEvent wheelEvent(itemView->visualRect(index).center(), 1, Qt::NoButton, Qt::ControlModifier);
- bool wheelEventReceived = qApp->notify(itemView->viewport(), &wheelEvent);
- QVERIFY(wheelEventReceived);
- QVERIFY(view.zoomLevel() > oldZoomLevel);
- }
- QCOMPARE(view.zoomLevel(), ZoomLevelInfo::maximumLevel());
-
- // Turn previews on again and check that the zoom level is restored
- view.setShowPreview(true);
- QVERIFY(view.showPreview());
- QCOMPARE(view.zoomLevel(), ZoomLevelInfo::minimumLevel());
-
- // Restore the initial state
- view.setZoomLevel(zoomLevelBackup);
- view.setShowPreview(false);
- view.setZoomLevel(zoomLevelBackup);
-}
-
-/**
- * testSaveAndRestoreState() checks if saving and restoring the view state (current item, scroll position).
- *
- * Note that we call qApp->sendPostedEvents() every time the view's finishedPathLoading(const KUrl&) signal
- * is received. The reason is that the scroll position is restored in the slot restoreContentsPosition(),
- * which is been invoked using a queued connection in DolphinView::slotLoadingCompleted(). To make sure
- * that this slot is really executed before we proceed, we have to empty the event queue using qApp->sendPostedEvents().
- */
-
-void DolphinViewTest_AllViewModes::testSaveAndRestoreState()
-{
- const int totalItems = 50;
- TestDir dir;
- for (int i = 0; i < totalItems; i++) {
- dir.createFile(QString("%1").arg(i));
- }
- dir.createDir("51");
- DolphinView view(dir.url(), 0);
- initView(&view);
-
- // Set sorting settings to the default to make sure that the item positions are reproducible.
- view.setSorting(DolphinView::SortByName);
- QCOMPARE(view.sorting(), DolphinView::SortByName);
- view.setSortOrder(Qt::AscendingOrder);
- QCOMPARE(view.sortOrder(), Qt::AscendingOrder);
-
- // Make sure that previews are off and that the icon size does not depend on the preview setting.
- // This is needed for the test for bug 270437, see below.
- view.setShowPreview(false);
- int zoomLevel = view.zoomLevel();
- view.setShowPreview(true);
- view.setZoomLevel(zoomLevel);
- view.setShowPreview(false);
-
- // Select item 45
- const QModelIndex index45 = itemView(&view)->model()->index(45, 0);
- itemView(&view)->scrollTo(index45);
- itemView(&view)->setCurrentIndex(index45);
- const int scrollPosX = itemView(&view)->horizontalScrollBar()->value();
- const int scrollPosY = itemView(&view)->verticalScrollBar()->value();
-
- // Save the view state
- QByteArray viewState;
- QDataStream saveStream(&viewState, QIODevice::WriteOnly);
- view.saveState(saveStream);
-
- // Change the URL
- view.setUrl(KUrl(dir.name() + "51"));
- waitForFinishedPathLoading(&view);
- qApp->sendPostedEvents();
-
- // Go back, but do not call DolphinView::restoreState()
- view.setUrl(dir.url());
- waitForFinishedPathLoading(&view);
- qApp->sendPostedEvents();
-
- // Verify that the view is scrolled to top-left corner and that item 45 is not the current item.
- // Note that the vertical position of the columns view might not be zero -> skip that part
- // of the check in this case.
- QVERIFY(itemView(&view)->currentIndex() != index45);
- QCOMPARE(itemView(&view)->horizontalScrollBar()->value(), 0);
- if (mode() != DolphinView::ColumnView) {
- QCOMPARE(itemView(&view)->verticalScrollBar()->value(), 0);
- }
-
- // Change the URL again
- view.setUrl(KUrl(dir.name() + "51"));
- waitForFinishedPathLoading(&view);
- qApp->sendPostedEvents();
-
- // Check that the current item and scroll position are correct if DolphinView::restoreState()
- // is called after the URL change
- view.setUrl(dir.url());
- QDataStream restoreStream(viewState);
- view.restoreState(restoreStream);
- waitForFinishedPathLoading(&view);
- qApp->sendPostedEvents();
-
- QCOMPARE(itemView(&view)->currentIndex(), index45);
- QCOMPARE(itemView(&view)->horizontalScrollBar()->value(), scrollPosX);
- QCOMPARE(itemView(&view)->verticalScrollBar()->value(), scrollPosY);
-
- /**
- * Additionally, we verify the fix for the bug https://bugs.kde.org/show_bug.cgi?id=270437
- * Actually, it's a bug in KFilePreviewGenerator, but it is easier to test it here.
- */
-
- // Turn previews on.
- view.setShowPreview(true);
- QVERIFY(view.showPreview());
-
- // We have to process all events in the queue to make sure that previews are really on.
- qApp->sendPostedEvents();
-
- // Current item and scroll position should not change.
- QCOMPARE(itemView(&view)->currentIndex(), index45);
- QCOMPARE(itemView(&view)->horizontalScrollBar()->value(), scrollPosX);
- QCOMPARE(itemView(&view)->verticalScrollBar()->value(), scrollPosY);
-
- // Turn previews off again. Before bug 270437, this triggered the dir lister's openUrl() method
- // -> we check that by listening to the view's startedPathLoading() signal and wait until the loading is finished in that case.
- QSignalSpy spy(&view, SIGNAL(startedPathLoading(const KUrl&)));
- view.setShowPreview(false);
- QVERIFY(!view.showPreview());
- qApp->sendPostedEvents();
- if (!spy.isEmpty()) {
- // The dir lister reloads the directory. We wait until the loading is finished.
- waitForFinishedPathLoading(&view);
- }
-
- // Current item and scroll position should not change.
- QCOMPARE(itemView(&view)->currentIndex(), index45);
- QCOMPARE(itemView(&view)->horizontalScrollBar()->value(), scrollPosX);
- QCOMPARE(itemView(&view)->verticalScrollBar()->value(), scrollPosY);
-}
-
-/**
- * testKeyboardFocus() checks whether a view grabs the keyboard focus.
- *
- * A view may never grab the keyboard focus itself and must respect the focus-state
- * when switching the view mode, see
- *
- * https://bugs.kde.org/show_bug.cgi?id=261147
- */
-
-void DolphinViewTest_AllViewModes::testKeyboardFocus()
-{
- TestDir dir;
- dir.createFiles(QStringList() << "a" << "b");
- DolphinView view(dir.url(), 0);
- initView(&view);
-
- // Move the keyboard focus to another widget.
- QWidget widget;
- widget.show();
- QTest::qWaitForWindowShown(&widget);
- widget.setFocus();
-
- QVERIFY(!view.hasFocus());
-
- // Switch view modes and verify that the view does not get the focus back
- for (int i = 0; i <= DolphinView::MaxModeEnum; ++i) {
- view.setMode(static_cast<DolphinView::Mode>(i));
- QVERIFY(!view.hasFocus());
- }
-}
-
-/**
- * testCutCopyPaste() checks if cutting or copying items in one view and pasting
- * them in another one works.
- */
-
-void DolphinViewTest_AllViewModes::testCutCopyPaste()
-{
- TestDir dir1;
- dir1.createFiles(QStringList() << "a" << "b" << "c" << "d");
- DolphinView view1(dir1.url(), 0);
- QAbstractItemView* itemView1 = initView(&view1);
-
- TestDir dir2;
- dir2.createFiles(QStringList() << "1" << "2" << "3" << "4");
- dir2.createDir("subfolder");
- DolphinView view2(dir2.url(), 0);
- QAbstractItemView* itemView2 = initView(&view2);
-
- // Make sure that both views are sorted by name in ascending order
- // TODO: Maybe that should be done in initView(), such all tests can rely on it...?
- view1.setSorting(DolphinView::SortByName);
- view1.setSortOrder(Qt::AscendingOrder);
- view2.setSorting(DolphinView::SortByName);
- view2.setSortOrder(Qt::AscendingOrder);
- view2.setSortFoldersFirst(true);
-
- QCOMPARE(viewItems(&view1), QStringList() << "a" << "b" << "c" << "d");
- QCOMPARE(viewItems(&view2), QStringList() << "subfolder" << "1" << "2" << "3" << "4");
-
- /** Copy and paste */
- // Select an item ("d") n view1, copy it and paste it in view2.
- // Note that we have to wait for view2's finishedPathLoading() signal because the pasting is done in the background.
- QModelIndex index = itemView1->model()->index(3, 0);
- itemView1->scrollTo(index);
- QTest::mouseClick(itemView1->viewport(), Qt::LeftButton, Qt::ControlModifier, itemView1->visualRect(index).center());
- verifySelectedItemsCount(&view1, 1);
- QCOMPARE(selectedItems(&view1), QStringList() << "d");
- view1.copySelectedItems();
- view2.paste();
- waitForFinishedPathLoading(&view2);
- QCOMPARE(viewItems(&view1), QStringList() << "a" << "b" << "c" << "d");
- QCOMPARE(viewItems(&view2), QStringList() << "subfolder" << "1" << "2" << "3" << "4" << "d");
- // The pasted item should be selected
- QCOMPARE(selectedItems(&view2), QStringList() << "d");
-
- /** Cut and paste */
- // Select two items ("3", "4") in view2, cut and paste in view1.
- view2.clearSelection();
- index = itemView2->model()->index(3, 0);
- itemView2->scrollTo(index);
- QTest::mouseClick(itemView2->viewport(), Qt::LeftButton, Qt::ControlModifier, itemView2->visualRect(index).center());
- verifySelectedItemsCount(&view2, 1);
- index = itemView2->model()->index(4, 0);
- itemView2->scrollTo(index);
- QTest::mouseClick(itemView2->viewport(), Qt::LeftButton, Qt::ShiftModifier, itemView2->visualRect(index).center());
- verifySelectedItemsCount(&view2, 2);
- QCOMPARE(selectedItems(&view2), QStringList() << "3" << "4");
- view2.cutSelectedItems();
- // In view1, "d" is still selected
- QCOMPARE(selectedItems(&view1), QStringList() << "d");
- // Paste "3" and "4"
- view1.paste();
- waitForFinishedPathLoading(&view1);
- // In principle, KIO could implement copy&paste such that the pasted items are already there, but the cut items
- // have not been removed yet. Therefore, we check the number of items in view2 and also wait for that view's
- // finishedPathLoading() signal if the cut items are still there.
- if (viewItems(&view2).count() > 4) {
- waitForFinishedPathLoading(&view2);
- }
- QCOMPARE(viewItems(&view1), QStringList() << "3" << "4" << "a" << "b" << "c" << "d");
- QCOMPARE(viewItems(&view2), QStringList() << "subfolder" << "1" << "2" << "d");
- // The pasted items ("3", "4") should be selected now, and the previous selection ("d") should be cleared.
- QCOMPARE(selectedItems(&view1), QStringList() << "3" << "4");
-
- /** Copy and paste into subfolder */
- view1.clearSelection();
- index = itemView1->model()->index(3, 0);
- itemView1->scrollTo(index);
- QTest::mouseClick(itemView1->viewport(), Qt::LeftButton, Qt::ControlModifier, itemView1->visualRect(index).center());
- verifySelectedItemsCount(&view1, 1);
- QCOMPARE(selectedItems(&view1), QStringList() << "b");
- view1.copySelectedItems();
- // Now we use view1 to display the subfolder, which is still empty.
- view1.setUrl(KUrl(dir2.name() + "subfolder"));
- waitForFinishedPathLoading(&view1);
- QCOMPARE(viewItems(&view1), QStringList());
- // Select the subfolder.in view2
- view2.clearSelection();
- index = itemView2->model()->index(0, 0);
- itemView2->scrollTo(index);
- QTest::mouseClick(itemView2->viewport(), Qt::LeftButton, Qt::ControlModifier, itemView2->visualRect(index).center());
- verifySelectedItemsCount(&view2, 1);
- // Paste into the subfolder
- view2.pasteIntoFolder();
- waitForFinishedPathLoading(&view1);
- QCOMPARE(viewItems(&view1), QStringList() << "b");
- // The pasted items in view1 are *not* selected now (because the pasting was done indirectly using view2.pasteIntoFolder()).
-}
-
-// Private member functions which are used by the tests
-
-/**
- * initView(DolphinView*) sets the correct view mode, shows the view on the screen, and waits until loading the
- * folder in the view is finished.
- *
- * Many unit tests need access to DolphinView's internal item view (icons, details, or columns).
- * Therefore, a pointer to the item view is returned by initView(DolphinView*).
- */
-
-QAbstractItemView* DolphinViewTest_AllViewModes::initView(DolphinView* view) const
-{
- QSignalSpy spyFinishedPathLoading(view, SIGNAL(finishedPathLoading(const KUrl&)));
- view->setMode(mode());
- Q_ASSERT(verifyCorrectViewMode(view));
- view->resize(200, 300);
- view->show();
- QTest::qWaitForWindowShown(view);
-
- // If the DolphinView's finishedPathLoading(const KUrl&) signal has not been received yet,
- // we have to wait a bit more.
- // The reason why the if-statement is needed here is that the signal might have been emitted
- // while we were waiting in QTest::qWaitForWindowShown(view)
- // -> waitForFinishedPathLoading(view) would fail in that case.
- if (spyFinishedPathLoading.isEmpty()) {
- waitForFinishedPathLoading(view);
- }
-
- return itemView(view);
-}
-
-/**
- * verifySelectedItemsCount(int) waits until the DolphinView's selectionChanged(const KFileItemList&)
- * signal is received and checks that the selection state of the view is as expected.
- */
-
-void DolphinViewTest_AllViewModes::verifySelectedItemsCount(DolphinView* view, int itemsCount) const
-{
- QSignalSpy spySelectionChanged(view, SIGNAL(selectionChanged(const KFileItemList&)));
- QVERIFY(QTest::kWaitForSignal(view, SIGNAL(selectionChanged(const KFileItemList&)), 2000));
-
- QCOMPARE(view->selectedItems().count(), itemsCount);
- QCOMPARE(view->selectedItemsCount(), itemsCount);
- QCOMPARE(spySelectionChanged.count(), 1);
- QCOMPARE(qvariant_cast<KFileItemList>(spySelectionChanged.at(0).at(0)).count(), itemsCount);
- if (itemsCount) {
- QVERIFY(view->hasSelection());
- }
- else {
- QVERIFY(!view->hasSelection());
- }
-}
-
-#include "dolphinviewtest_allviewmodes.moc"
+++ /dev/null
-/*****************************************************************************
- * Copyright (C) 2010-2011 by Frank Reininghaus (frank78ac@googlemail.com) *
- * *
- * 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 DOLPHINVIEWTEST_ALLVIEWMODES
-#define DOLPHINVIEWTEST_ALLVIEWMODES
-
-#include "testbase.h"
-
-#include "views/dolphinview.h"
-
-/**
- * DolphinViewTest_AllViewModes is used as a base class for tests that check the
- * basic functionality of DolphinView in all view modes. The derived classes
- * have to provide implementations for the virtual methods mode() and verifyCorrectViewMode(),
- * see below.
- *
- * Tests for DolphinView functionality that is specific to a particular view mode or
- * to switching between different view modes should not be added here, but to another
- * DolphinView unit test.
- */
-
-class DolphinViewTest_AllViewModes : public TestBase
-{
- Q_OBJECT
-
-public:
-
- DolphinViewTest_AllViewModes();
-
-private slots:
-
- void testSelection();
- void testViewPropertySettings();
- void testZoomLevel();
- void testSaveAndRestoreState();
- void testKeyboardFocus();
- void testCutCopyPaste();
-
-private:
-
- /**
- * Sets the correct view mode, shows the view on the screen, and waits until loading the
- * folder in the view is finished.
- *
- * Many unit tests need access to DolphinVie's internal item view (icons, details, or columns).
- * Therefore, a pointer to the item view is returned by initView(DolphinView*).
- */
- QAbstractItemView* initView(DolphinView* view) const;
-
- /** Returns the view mode (Icons, Details, Columns) to be used in the test. */
- virtual DolphinView::Mode mode() const = 0;
-
- /** Should return true if the view mode is correct. */
- virtual bool verifyCorrectViewMode(const DolphinView* view) const = 0;
-
- /**
- * Waits for the DolphinView's selectionChanged(const KFileItemList&) to be emitted
- * and verifies that the number of selected items is as expected.
- */
- void verifySelectedItemsCount(DolphinView* view, int itemsCount) const;
-
-};
-
-#endif
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 <qtest_kde.h>
+
+#include <KDirLister>
+#include "kitemviews/kfileitemlistview.h"
+#include "kitemviews/kfileitemmodel.h"
+#include "testdir.h"
+
+#include <QGraphicsView>
+
+namespace {
+ const int DefaultTimeout = 2000;
+};
+
+class KFileItemListViewTest : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void init();
+ void cleanup();
+
+ void testFeffi();
+
+private:
+ KFileItemListView* m_listView;
+ KFileItemModel* m_model;
+ KDirLister* m_dirLister;
+ TestDir* m_testDir;
+ QGraphicsView* m_graphicsView;
+};
+
+void KFileItemListViewTest::init()
+{
+ qRegisterMetaType<KItemRangeList>("KItemRangeList");
+ qRegisterMetaType<KFileItemList>("KFileItemList");
+
+ m_testDir = new TestDir();
+ m_dirLister = new KDirLister();
+ m_model = new KFileItemModel(m_dirLister);
+
+ m_listView = new KFileItemListView();
+ m_listView->onModelChanged(m_model, 0);
+
+ m_graphicsView = new QGraphicsView();
+ m_graphicsView->show();
+ QTest::qWaitForWindowShown(m_graphicsView);
+}
+
+void KFileItemListViewTest::cleanup()
+{
+ delete m_graphicsView;
+ m_graphicsView = 0;
+
+ delete m_listView;
+ m_listView = 0;
+
+ delete m_model;
+ m_model = 0;
+
+ delete m_dirLister;
+ m_dirLister = 0;
+
+ delete m_testDir;
+ m_testDir = 0;
+}
+
+void KFileItemListViewTest::testFeffi()
+{
+ QStringList files;
+ files << "a.txt" << "b.txt" << "c.txt";
+ m_testDir->createFiles(files);
+
+ m_dirLister->openUrl(m_testDir->url());
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+
+ QCOMPARE(m_model->count(), 3);
+}
+
+QTEST_KDEMAIN(KFileItemListViewTest, GUI)
+
+#include "kfileitemlistviewtest.moc"
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 <qtest_kde.h>
+
+#include <KDirLister>
+#include "kitemviews/kfileitemmodel.h"
+#include "testdir.h"
+
+namespace {
+ const int DefaultTimeout = 2000;
+};
+
+class KFileItemModelTest : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void init();
+ void cleanup();
+
+ void testDefaultRoles();
+ void testDefaultSortRole();
+ void testDefaultGroupRole();
+ void testNewItems();
+ void testInsertingItems();
+
+ void testExpansionLevelsCompare_data();
+ void testExpansionLevelsCompare();
+
+private:
+ bool isModelConsistent() const;
+
+private:
+ KFileItemModel* m_model;
+ KDirLister* m_dirLister;
+ TestDir* m_testDir;
+};
+
+void KFileItemModelTest::init()
+{
+ qRegisterMetaType<KItemRangeList>("KItemRangeList");
+ qRegisterMetaType<KFileItemList>("KFileItemList");
+
+ m_testDir = new TestDir();
+ m_dirLister = new KDirLister();
+ m_model = new KFileItemModel(m_dirLister);
+}
+
+void KFileItemModelTest::cleanup()
+{
+ delete m_model;
+ m_model = 0;
+
+ delete m_dirLister;
+ m_dirLister = 0;
+
+ delete m_testDir;
+ m_testDir = 0;
+}
+
+void KFileItemModelTest::testDefaultRoles()
+{
+ const QSet<QByteArray> roles = m_model->roles();
+ QCOMPARE(roles.count(), 2);
+ QVERIFY(roles.contains("name"));
+ QVERIFY(roles.contains("isDir"));
+}
+
+void KFileItemModelTest::testDefaultSortRole()
+{
+ QCOMPARE(m_model->sortRole(), QByteArray("name"));
+
+ QStringList files;
+ files << "c.txt" << "a.txt" << "b.txt";
+
+ m_testDir->createFiles(files);
+
+ m_dirLister->openUrl(m_testDir->url());
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+
+ QCOMPARE(m_model->count(), 3);
+ QCOMPARE(m_model->data(0)["name"].toString(), QString("a.txt"));
+ QCOMPARE(m_model->data(1)["name"].toString(), QString("b.txt"));
+ QCOMPARE(m_model->data(2)["name"].toString(), QString("c.txt"));
+}
+
+void KFileItemModelTest::testDefaultGroupRole()
+{
+ QVERIFY(m_model->groupRole().isEmpty());
+}
+
+void KFileItemModelTest::testNewItems()
+{
+ QStringList files;
+ files << "a.txt" << "b.txt" << "c.txt";
+ m_testDir->createFiles(files);
+
+ m_dirLister->openUrl(m_testDir->url());
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+
+ QCOMPARE(m_model->count(), 3);
+
+ QVERIFY(isModelConsistent());
+}
+
+void KFileItemModelTest::testInsertingItems()
+{
+ // QSKIP("Temporary disabled", SkipSingle);
+
+ // KFileItemModel prevents that inserting a punch of items sequentially
+ // results in an itemsInserted()-signal for each item. Instead internally
+ // a timeout is given that collects such operations and results in only
+ // one itemsInserted()-signal. However in this test we want to stress
+ // KFileItemModel to do a lot of insert operation and hence decrease
+ // the timeout to 1 millisecond.
+ m_model->m_minimumUpdateIntervalTimer->setInterval(1);
+
+ m_testDir->createFile("1");
+ m_dirLister->openUrl(m_testDir->url());
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+ QCOMPARE(m_model->count(), 1);
+
+ // Insert 10 items for 20 times. After each insert operation the model consistency
+ // is checked.
+ QSet<int> insertedItems;
+ for (int i = 0; i < 20; ++i) {
+ QSignalSpy spy(m_model, SIGNAL(itemsInserted(KItemRangeList)));
+
+ for (int j = 0; j < 10; ++j) {
+ int itemName = qrand();
+ while (insertedItems.contains(itemName)) {
+ itemName = qrand();
+ }
+ insertedItems.insert(itemName);
+
+ m_testDir->createFile(QString::number(itemName));
+ }
+
+ m_dirLister->updateDirectory(m_testDir->url());
+ if (spy.count() == 0) {
+ QVERIFY(QTest::kWaitForSignal(m_model, SIGNAL(itemsInserted(KItemRangeList)), DefaultTimeout));
+ }
+
+ QVERIFY(isModelConsistent());
+ }
+
+ QCOMPARE(m_model->count(), 201);
+}
+
+void KFileItemModelTest::testExpansionLevelsCompare_data()
+{
+ QTest::addColumn<QString>("urlA");
+ QTest::addColumn<QString>("urlB");
+ QTest::addColumn<int>("result");
+
+ QTest::newRow("Equal") << "/a/b" << "/a/b" << 0;
+ QTest::newRow("Sub path: A < B") << "/a/b" << "/a/b/c" << -1;
+ QTest::newRow("Sub path: A > B") << "/a/b/c" << "/a/b" << +1;
+}
+
+void KFileItemModelTest::testExpansionLevelsCompare()
+{
+ QFETCH(QString, urlA);
+ QFETCH(QString, urlB);
+ QFETCH(int, result);
+
+ const KFileItem a(KUrl(urlA), QString(), mode_t(-1));
+ const KFileItem b(KUrl(urlB), QString(), mode_t(-1));
+ QCOMPARE(m_model->expansionLevelsCompare(a, b), result);
+}
+
+bool KFileItemModelTest::isModelConsistent() const
+{
+ for (int i = 0; i < m_model->count(); ++i) {
+ const KFileItem item = m_model->fileItem(i);
+ if (item.isNull()) {
+ qWarning() << "Item" << i << "is null";
+ return false;
+ }
+
+ const int itemIndex = m_model->index(item);
+ if (itemIndex != i) {
+ qWarning() << "Item" << i << "has a wrong index:" << itemIndex;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+QTEST_KDEMAIN(KFileItemModelTest, NoGUI)
+
+#include "kfileitemmodeltest.moc"
+++ /dev/null
-/*****************************************************************************
- * Copyright (C) 2010-2011 by Frank Reininghaus (frank78ac@googlemail.com) *
- * *
- * 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 "testbase.h"
-
-#include <qtest_kde.h>
-
-#include "views/dolphinview.h"
-#include "views/dolphinmodel.h"
-#include "views/dolphindirlister.h"
-#include "views/dolphinsortfilterproxymodel.h"
-
-#include <QAbstractItemView>
-
-QAbstractItemView* TestBase::itemView(const DolphinView* view)
-{
- return view->m_viewAccessor.itemView();
-}
-
-void TestBase::waitForFinishedPathLoading(DolphinView* view, int milliseconds)
-{
- // If the signal is not received, somthing is going seriously wrong.
- // -> assert here rather than continuing, which might result in test failures which are hard to unterstand.
- bool viewHasFinishedLoading = QTest::kWaitForSignal(view, SIGNAL(finishedPathLoading(const KUrl&)), milliseconds);
- Q_ASSERT(viewHasFinishedLoading);
- Q_UNUSED(viewHasFinishedLoading) // suppress compiler warining is asserts are disabled
-}
-
-void TestBase::reloadViewAndWait(DolphinView* view)
-{
- view->reload();
- waitForFinishedPathLoading(view);
-}
-
-QStringList TestBase::viewItems(const DolphinView* view)
-{
- QStringList itemList;
- const QAbstractItemModel* model = itemView(view)->model();
-
- for (int row = 0; row < model->rowCount(); row++) {
- itemList << model->data(model->index(row, 0), Qt::DisplayRole).toString();
- }
-
- return itemList;
-}
-
-QStringList TestBase::selectedItems(const DolphinView* view)
-{
- QStringList itemList;
- const QAbstractItemModel* model = itemView(view)->model();
- const QModelIndexList selectedIndexes = itemView(view)->selectionModel()->selectedIndexes();
-
- for (int row = 0; row < model->rowCount(); row++) {
- const QModelIndex index = model->index(row, 0);
- if (selectedIndexes.contains(index)) {
- itemList << model->data(model->index(row, 0), Qt::DisplayRole).toString();
- }
- }
-
- return itemList;
-}
+++ /dev/null
-/*****************************************************************************
- * Copyright (C) 2010-2011 by Frank Reininghaus (frank78ac@googlemail.com) *
- * *
- * 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 TESTBASE_H
-#define TESTBASE_H
-
-#include <QtCore/QObject>
-
-class QAbstractItemView;
-class DolphinDirLister;
-class DolphinModel;
-class DolphinSortFilterProxyModel;
-class DolphinView;
-
-/**
- * The class TestBase (which is a friend of DolphinView's) provides access to some
- * parts of DolphinView to the unit tests.
- *
- * TODO: TestBase should also backup the DolphinSettings and restore them later!
- */
-
-class TestBase : public QObject
-{
- Q_OBJECT
-
-public:
-
- TestBase() {};
- ~TestBase() {};
-
- /** Returns the item view (icons, details, or columns) */
- static QAbstractItemView* itemView(const DolphinView* view);
-
- /**
- * Waits until the view emits its finishedPathLoading(const KUrl&) signal.
- * Asserts if the signal is not received within the given number of milliseconds.
- */
- static void waitForFinishedPathLoading(DolphinView* view, int milliseconds=20000);
-
- /** Reloads the view and waits for the finishedPathLoading(const KUrl&) signal. */
- static void reloadViewAndWait(DolphinView* view);
-
- /** Returns the items shown in the view. The order corresponds to the sort order of the view. */
- static QStringList viewItems(const DolphinView* view);
-
- /** Returns the items which are selected in the view. The order corresponds to the sort order of the view. */
- static QStringList selectedItems(const DolphinView* view);
-
-};
-
-#endif
#include <sys/utime.h>
#endif
-/** The following function is taken from kdelibs/kio/tests/kiotesthelper.h, copyright (C) 2006 by David Faure */
+TestDir::TestDir()
+{
+}
+
+TestDir::~TestDir()
+{
+}
+KUrl TestDir::url() const
+{
+ return KUrl(name());
+}
+
+/** The following function is taken from kdelibs/kio/tests/kiotesthelper.h, copyright (C) 2006 by David Faure */
static void setTimeStamp(const QString& path, const QDateTime& mtime)
{
#ifdef Q_OS_UNIX
void TestDir::createFiles(const QStringList& files)
{
- foreach(const QString& path, files) {
+ foreach (const QString& path, files) {
createFile(path);
}
}
* TestDir provides a temporary directory. In addition to KTempDir, it has
* methods that create files and subdirectories inside the directory.
*/
-
class TestDir : public KTempDir
{
public:
+ TestDir();
+ virtual ~TestDir();
- TestDir() {}
- ~TestDir() {}
-
- KUrl url() const { return KUrl(name()); }
+ KUrl url() const;
/**
* The following functions create either a file, a list of files, or a directory.
* The paths may be absolute or relative to the test directory. Any missing parent
* directories will be created automatically.
*/
-
- void createFile(const QString& path, const QByteArray& data = QByteArray("test"), const QDateTime& time = QDateTime());
+ void createFile(const QString& path,
+ const QByteArray& data = QByteArray("test"),
+ const QDateTime& time = QDateTime());
void createFiles(const QStringList& files);
void createDir(const QString& path, const QDateTime& time = QDateTime());
private:
-
void makePathAbsoluteAndCreateParents(QString& path);
};
#include "additionalinfoaccessor.h"
-#include "dolphinmodel.h"
#include <KGlobal>
#include <KLocale>
return s_additionalInfoManager->instance;
}
-KFileItemDelegate::InformationList AdditionalInfoAccessor::keys() const
+QList<DolphinView::AdditionalInfo> AdditionalInfoAccessor::keys() const
{
- return m_information;
+ return m_infoList;
}
-KFileItemDelegate::Information AdditionalInfoAccessor::keyForColumn(int columnIndex) const
+QByteArray AdditionalInfoAccessor::role(DolphinView::AdditionalInfo info) const
{
- KFileItemDelegate::Information info = KFileItemDelegate::NoInformation;
-
- switch (columnIndex) {
- case DolphinModel::Size: info = KFileItemDelegate::Size; break;
- case DolphinModel::ModifiedTime: info = KFileItemDelegate::ModificationTime; break;
- case DolphinModel::Permissions: info = KFileItemDelegate::Permissions; break;
- case DolphinModel::Owner: info = KFileItemDelegate::Owner; break;
- case DolphinModel::Group: info = KFileItemDelegate::OwnerAndGroup; break;
- case DolphinModel::Type: info = KFileItemDelegate::FriendlyMimeType; break;
- case DolphinModel::LinkDest: info = KFileItemDelegate::LinkDest; break;
- case DolphinModel::LocalPathOrUrl: info = KFileItemDelegate::LocalPathOrUrl; break;
+ QByteArray role;
+ switch (info) {
+ case DolphinView::NameInfo: role = "name"; break;
+ case DolphinView::SizeInfo: role = "size"; break;
+ case DolphinView::DateInfo: role = "date"; break;
+ case DolphinView::PermissionsInfo: role = "permissions"; break;
+ case DolphinView::OwnerInfo: role = "owner"; break;
+ case DolphinView::GroupInfo: role = "group"; break;
+ case DolphinView::TypeInfo: role = "type"; break;
+ case DolphinView::DestinationInfo: role = "destination"; break;
+ case DolphinView::PathInfo: role = "path"; break;
default: break;
}
- return info;
+ return role;
}
-QString AdditionalInfoAccessor::actionCollectionName(KFileItemDelegate::Information info,
+QString AdditionalInfoAccessor::actionCollectionName(DolphinView::AdditionalInfo info,
ActionCollectionType type) const
{
QString name;
return name;
}
-QString AdditionalInfoAccessor::translation(KFileItemDelegate::Information info) const
+QString AdditionalInfoAccessor::translation(DolphinView::AdditionalInfo info) const
{
return i18nc(m_map[info]->context, m_map[info]->translation);
}
-QString AdditionalInfoAccessor::value(KFileItemDelegate::Information info) const
+QString AdditionalInfoAccessor::value(DolphinView::AdditionalInfo info) const
{
return m_map[info]->value;
}
-DolphinView::Sorting AdditionalInfoAccessor::sorting(KFileItemDelegate::Information info) const
+DolphinView::Sorting AdditionalInfoAccessor::sorting(DolphinView::AdditionalInfo info) const
{
return m_map[info]->sorting;
}
-int AdditionalInfoAccessor::bitValue(KFileItemDelegate::Information info) const
-{
- return m_map[info]->bitValue;
-}
-
AdditionalInfoAccessor::AdditionalInfoAccessor() :
- m_information(),
+ m_infoList(),
m_map()
{
static const AdditionalInfoAccessor::AdditionalInfo additionalInfo[] = {
// Entries for view-properties version 1:
- { "size", I18N_NOOP2_NOSTRIP("@label", "Size"), "Size", DolphinView::SortBySize, 1 },
- { "date", I18N_NOOP2_NOSTRIP("@label", "Date"), "Date", DolphinView::SortByDate, 2 },
- { "permissions", I18N_NOOP2_NOSTRIP("@label", "Permissions"), "Permissions", DolphinView::SortByPermissions, 4 },
- { "owner", I18N_NOOP2_NOSTRIP("@label", "Owner"), "Owner", DolphinView::SortByOwner, 8 },
- { "group", I18N_NOOP2_NOSTRIP("@label", "Group"), "Group", DolphinView::SortByGroup, 16 },
- { "type", I18N_NOOP2_NOSTRIP("@label", "Type"), "Type", DolphinView::SortByType, 32 },
- { "destination", I18N_NOOP2_NOSTRIP("@label", "Link Destination"), "LinkDestination", DolphinView::SortByDestination, 64 },
- { "path", I18N_NOOP2_NOSTRIP("@label", "Path"), "Path", DolphinView::SortByPath, 128 }
- // Entries for view-properties version >= 2 (the last column can be set to 0):
+ { "size", I18N_NOOP2_NOSTRIP("@label", "Size"), "Size", DolphinView::SortBySize},
+ { "date", I18N_NOOP2_NOSTRIP("@label", "Date"), "Date", DolphinView::SortByDate},
+ { "permissions", I18N_NOOP2_NOSTRIP("@label", "Permissions"), "Permissions", DolphinView::SortByPermissions},
+ { "owner", I18N_NOOP2_NOSTRIP("@label", "Owner"), "Owner", DolphinView::SortByOwner},
+ { "group", I18N_NOOP2_NOSTRIP("@label", "Group"), "Group", DolphinView::SortByGroup},
+ { "type", I18N_NOOP2_NOSTRIP("@label", "Type"), "Type", DolphinView::SortByType},
+ { "destination", I18N_NOOP2_NOSTRIP("@label", "Link Destination"), "LinkDestination", DolphinView::SortByDestination},
+ { "path", I18N_NOOP2_NOSTRIP("@label", "Path"), "Path", DolphinView::SortByPath}
};
- m_map.insert(KFileItemDelegate::Size, &additionalInfo[0]);
- m_map.insert(KFileItemDelegate::ModificationTime, &additionalInfo[1]);
- m_map.insert(KFileItemDelegate::Permissions, &additionalInfo[2]);
- m_map.insert(KFileItemDelegate::Owner, &additionalInfo[3]);
- m_map.insert(KFileItemDelegate::OwnerAndGroup, &additionalInfo[4]);
- m_map.insert(KFileItemDelegate::FriendlyMimeType, &additionalInfo[5]);
- m_map.insert(KFileItemDelegate::LinkDest, &additionalInfo[6]);
- m_map.insert(KFileItemDelegate::LocalPathOrUrl, &additionalInfo[7]);
-
- // The m_information list defines all available keys and the sort order
- // (don't use m_information = m_map.keys(), as the order is undefined).
- m_information.append(KFileItemDelegate::Size);
- m_information.append(KFileItemDelegate::ModificationTime);
- m_information.append(KFileItemDelegate::Permissions);
- m_information.append(KFileItemDelegate::Owner);
- m_information.append(KFileItemDelegate::OwnerAndGroup);
- m_information.append(KFileItemDelegate::FriendlyMimeType);
- m_information.append(KFileItemDelegate::LinkDest);
- m_information.append(KFileItemDelegate::LocalPathOrUrl);
+ m_map.insert(DolphinView::SizeInfo, &additionalInfo[0]);
+ m_map.insert(DolphinView::DateInfo, &additionalInfo[1]);
+ m_map.insert(DolphinView::PermissionsInfo, &additionalInfo[2]);
+ m_map.insert(DolphinView::OwnerInfo, &additionalInfo[3]);
+ m_map.insert(DolphinView::GroupInfo, &additionalInfo[4]);
+ m_map.insert(DolphinView::TypeInfo, &additionalInfo[5]);
+ m_map.insert(DolphinView::DestinationInfo, &additionalInfo[6]);
+ m_map.insert(DolphinView::PathInfo, &additionalInfo[7]);
+
+ // The m_infoList defines all available keys and the sort order
+ // (don't use m_information = m_map.keys(), as the order would be undefined).
+ m_infoList.append(DolphinView::SizeInfo);
+ m_infoList.append(DolphinView::DateInfo);
+ m_infoList.append(DolphinView::PermissionsInfo);
+ m_infoList.append(DolphinView::OwnerInfo);
+ m_infoList.append(DolphinView::GroupInfo);
+ m_infoList.append(DolphinView::TypeInfo);
+ m_infoList.append(DolphinView::DestinationInfo);
+ m_infoList.append(DolphinView::PathInfo);
}
AdditionalInfoAccessor::~AdditionalInfoAccessor()
* All entries of this list are keys for accessing the corresponding
* data (see actionCollectionName(), translation(), bitValue()).
*/
- KFileItemDelegate::InformationList keys() const;
+ QList<DolphinView::AdditionalInfo> keys() const;
- /**
- * @return Key for the model column with the index \p columnIndex.
- */
- KFileItemDelegate::Information keyForColumn(int columnIndex) const;
+ QByteArray role(DolphinView::AdditionalInfo info) const;
- QString actionCollectionName(KFileItemDelegate::Information info, ActionCollectionType type) const;
+ QString actionCollectionName(DolphinView::AdditionalInfo info, ActionCollectionType type) const;
- QString translation(KFileItemDelegate::Information info) const;
+ QString translation(DolphinView::AdditionalInfo info) const;
/**
* @return String representation of the value that is stored in the .directory
* by ViewProperties.
*/
- QString value(KFileItemDelegate::Information info) const;
-
- DolphinView::Sorting sorting(KFileItemDelegate::Information info) const;
+ QString value(DolphinView::AdditionalInfo info) const;
- /**
- * @return Bitvalue for \p info that is stored in a ViewProperties instance.
- * Is required only for backward compatibility with the version 1 of
- * the view-properties.
- */
- int bitValue(KFileItemDelegate::Information info) const;
+ DolphinView::Sorting sorting(DolphinView::AdditionalInfo info) const;
protected:
AdditionalInfoAccessor();
const char* const translation;
const char* const value;
const DolphinView::Sorting sorting;
- const int bitValue; // for backward compatibility with version 1 of view-properties
};
- KFileItemDelegate::InformationList m_information;
- QMap<KFileItemDelegate::Information, const AdditionalInfo*> m_map;
+ QList<DolphinView::AdditionalInfo> m_infoList;
+ QMap<DolphinView::AdditionalInfo, const AdditionalInfo*> m_map;
};
#endif
+++ /dev/null
-/*
- * This file is part of the KDE project
- * Copyright (C) 2007 Rafael Fernández López <ereslibre@kde.org>
- *
- * 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.
- */
-
-#include "dolphincategorydrawer.h"
-
-#include <config-nepomuk.h>
-
-#include <QPainter>
-#include <QFile>
-#include <QDir>
-#include <QApplication>
-#include <QStyleOption>
-
-#ifdef HAVE_NEPOMUK
-#include <Nepomuk/KRatingPainter>
-#endif
-
-#include <KIconLoader>
-#include <KIconEffect>
-#include <KCategorizedSortFilterProxyModel>
-#include <KUser>
-#include <KCategorizedView>
-
-#include "dolphinview.h"
-#include "dolphinmodel.h"
-
-#define HORIZONTAL_HINT 3
-
-DolphinCategoryDrawer::DolphinCategoryDrawer(KCategorizedView *view)
- : KCategoryDrawerV3(view)
- , hotSpotPressed(NoneHotSpot)
- , selectAll(KIconLoader::global()->loadIcon("list-add", KIconLoader::Desktop, 16))
- , selectAllHovered(KIconLoader::global()->iconEffect()->apply(selectAll, KIconLoader::Desktop, KIconLoader::ActiveState))
- , selectAllDisabled(KIconLoader::global()->iconEffect()->apply(selectAll, KIconLoader::Desktop, KIconLoader::DisabledState))
- , unselectAll(KIconLoader::global()->loadIcon("list-remove", KIconLoader::Desktop, 16))
- , unselectAllHovered(KIconLoader::global()->iconEffect()->apply(unselectAll, KIconLoader::Desktop, KIconLoader::ActiveState))
- , unselectAllDisabled(KIconLoader::global()->iconEffect()->apply(unselectAll, KIconLoader::Desktop, KIconLoader::DisabledState))
-{
-}
-
-DolphinCategoryDrawer::~DolphinCategoryDrawer()
-{
-}
-
-bool DolphinCategoryDrawer::allCategorySelected(const QString &category) const
-{
- const QModelIndexList list = view()->block(category);
- foreach (const QModelIndex &index, list) {
- if (!view()->selectionModel()->isSelected(index)) {
- return false;
- }
- }
- return true;
-}
-
-bool DolphinCategoryDrawer::someCategorySelected(const QString &category) const
-{
- const QModelIndexList list = view()->block(category);
- foreach (const QModelIndex &index, list) {
- if (view()->selectionModel()->isSelected(index)) {
- return true;
- }
- }
- return false;
-}
-
-void DolphinCategoryDrawer::drawCategory(const QModelIndex &index, int sortRole,
- const QStyleOption &option, QPainter *painter) const
-{
- Q_UNUSED(sortRole);
- painter->setRenderHint(QPainter::Antialiasing);
-
- if (!index.isValid()) {
- return;
- }
-
- const QString category = index.model()->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString();
- const QRect optRect = option.rect;
- QFont font(QApplication::font());
- font.setBold(true);
- const QFontMetrics fontMetrics = QFontMetrics(font);
-
- QColor outlineColor = option.palette.text().color();
- outlineColor.setAlphaF(0.35);
-
- //BEGIN: top left corner
- {
- painter->save();
- painter->setPen(outlineColor);
- const QPointF topLeft(optRect.topLeft());
- QRectF arc(topLeft, QSizeF(4, 4));
- arc.translate(0.5, 0.5);
- painter->drawArc(arc, 1440, 1440);
- painter->restore();
- }
- //END: top left corner
-
- //BEGIN: left vertical line
- {
- QPoint start(optRect.topLeft());
- start.ry() += 3;
- QPoint verticalGradBottom(optRect.topLeft());
- verticalGradBottom.ry() += fontMetrics.height() + 5;
- QLinearGradient gradient(start, verticalGradBottom);
- gradient.setColorAt(0, outlineColor);
- gradient.setColorAt(1, Qt::transparent);
- painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient);
- }
- //END: left vertical line
-
- //BEGIN: horizontal line
- {
- QPoint start(optRect.topLeft());
- start.rx() += 3;
- QPoint horizontalGradTop(optRect.topLeft());
- horizontalGradTop.rx() += optRect.width() - 6;
- painter->fillRect(QRect(start, QSize(optRect.width() - 6, 1)), outlineColor);
- }
- //END: horizontal line
-
- //BEGIN: top right corner
- {
- painter->save();
- painter->setPen(outlineColor);
- QPointF topRight(optRect.topRight());
- topRight.rx() -= 4;
- QRectF arc(topRight, QSizeF(4, 4));
- arc.translate(0.5, 0.5);
- painter->drawArc(arc, 0, 1440);
- painter->restore();
- }
- //END: top right corner
-
- //BEGIN: right vertical line
- {
- QPoint start(optRect.topRight());
- start.ry() += 3;
- QPoint verticalGradBottom(optRect.topRight());
- verticalGradBottom.ry() += fontMetrics.height() + 5;
- QLinearGradient gradient(start, verticalGradBottom);
- gradient.setColorAt(0, outlineColor);
- gradient.setColorAt(1, Qt::transparent);
- painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient);
- }
- //END: right vertical line
-
- const int iconSize = KIconLoader::global()->currentSize(KIconLoader::Small);
-
- //BEGIN: select/unselect all
- {
- if (this->category == category) {
- QRect iconAllRect(option.rect);
- iconAllRect.setTop(iconAllRect.top() + 4);
- iconAllRect.setLeft(iconAllRect.right() - 16 - 7);
- iconAllRect.setSize(QSize(iconSize, iconSize));
- if (!allCategorySelected(category)) {
- if (iconAllRect.contains(pos)) {
- painter->drawPixmap(iconAllRect, selectAllHovered);
- } else {
- painter->drawPixmap(iconAllRect, selectAll);
- }
- } else {
- painter->drawPixmap(iconAllRect, selectAllDisabled);
- }
- QRect iconNoneRect(option.rect);
- iconNoneRect.setTop(iconNoneRect.top() + 4);
- iconNoneRect.setLeft(iconNoneRect.right() - 16 * 2 - 7 * 2);
- iconNoneRect.setSize(QSize(iconSize, iconSize));
- if (someCategorySelected(category)) {
- if (iconNoneRect.contains(pos)) {
- painter->drawPixmap(iconNoneRect, unselectAllHovered);
- } else {
- painter->drawPixmap(iconNoneRect, unselectAll);
- }
- } else {
- painter->drawPixmap(iconNoneRect, unselectAllDisabled);
- }
- }
- }
- //END: select/unselect all
-
- //BEGIN: category information
- {
- bool paintIcon;
- QPixmap icon;
- switch (index.column()) {
- case KDirModel::Owner: {
- paintIcon = true;
- KUser user(category);
- const QString faceIconPath = user.faceIconPath();
- if (faceIconPath.isEmpty()) {
- icon = KIconLoader::global()->loadIcon("user-identity", KIconLoader::NoGroup, iconSize);
- } else {
- icon = QPixmap::fromImage(QImage(faceIconPath).scaledToHeight(iconSize, Qt::SmoothTransformation));
- }
- }
- break;
- case KDirModel::Type: {
- paintIcon = true;
- const KCategorizedSortFilterProxyModel *proxyModel = static_cast<const KCategorizedSortFilterProxyModel*>(index.model());
- const DolphinModel *model = static_cast<const DolphinModel*>(proxyModel->sourceModel());
- KFileItem item = model->itemForIndex(proxyModel->mapToSource(index));
- // This is the only way of getting the icon right. Others will fail on corner
- // cases like the item representing this group has been set a different icon,
- // so the group icon drawn is that one particularly. This way assures the drawn
- // icon is the one of the mimetype of the group itself. (ereslibre)
- icon = KIconLoader::global()->loadMimeTypeIcon(item.mimeTypePtr()->iconName(), KIconLoader::NoGroup, iconSize);
- }
- break;
- default:
- paintIcon = false;
- }
-
- if (paintIcon) {
- QRect iconRect(option.rect);
- iconRect.setTop(iconRect.top() + 4);
- iconRect.setLeft(iconRect.left() + 7);
- iconRect.setSize(QSize(iconSize, iconSize));
-
- painter->drawPixmap(iconRect, icon);
- }
-
- //BEGIN: text
- {
- QRect textRect(option.rect);
- textRect.setTop(textRect.top() + 7);
- textRect.setLeft(textRect.left() + 7 + (paintIcon ? (iconSize + 6) : 0));
- textRect.setHeight(qMax(fontMetrics.height(), iconSize));
- textRect.setRight(textRect.right() - 7);
- textRect.setBottom(textRect.bottom() - 5); // only one pixel separation here (no gradient)
-
- painter->save();
- painter->setFont(font);
- QColor penColor(option.palette.text().color());
- penColor.setAlphaF(0.6);
- painter->setPen(penColor);
- painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, category);
- painter->restore();
- }
- //END: text
- }
- //BEGIN: category information
-}
-
-int DolphinCategoryDrawer::categoryHeight(const QModelIndex &index, const QStyleOption &) const
-{
- int iconSize = KIconLoader::global()->currentSize(KIconLoader::Small);
- QFont font(QApplication::font());
- font.setBold(true);
- const QFontMetrics fontMetrics = QFontMetrics(font);
- int heightWithoutIcon = fontMetrics.height() + (iconSize / 4) * 2 + 1; /* 1 pixel-width gradient */
- bool paintIcon;
-
- switch (index.column()) {
- case KDirModel::Owner:
- case KDirModel::Type:
- paintIcon = true;
- break;
- default:
- paintIcon = false;
- }
-
- if (paintIcon) {
- return qMax(heightWithoutIcon + 5, iconSize + 1 /* 1 pixel-width gradient */
- + 5 /* top and bottom separation */);
- }
-
- return heightWithoutIcon + 5;
-}
-
-void DolphinCategoryDrawer::mouseButtonPressed(const QModelIndex &index, const QRect &blockRect, QMouseEvent *event)
-{
- if (!index.isValid()) {
- event->ignore();
- return;
- }
- const QString category = index.model()->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString();
- int iconSize = KIconLoader::global()->currentSize(KIconLoader::Small);
- if (this->category == category) {
- QRect iconAllRect(blockRect);
- iconAllRect.setTop(iconAllRect.top() + 4);
- iconAllRect.setLeft(iconAllRect.right() - 16 - 7);
- iconAllRect.setSize(QSize(iconSize, iconSize));
- if (iconAllRect.contains(pos)) {
- event->accept();
- hotSpotPressed = SelectAllHotSpot;
- categoryPressed = index;
- return;
- }
- QRect iconNoneRect(blockRect);
- iconNoneRect.setTop(iconNoneRect.top() + 4);
- iconNoneRect.setLeft(iconNoneRect.right() - 16 * 2 - 7 * 2);
- iconNoneRect.setSize(QSize(iconSize, iconSize));
- if (iconNoneRect.contains(pos)) {
- event->accept();
- hotSpotPressed = UnselectAllHotSpot;
- categoryPressed = index;
- return;
- }
- }
- event->ignore();
-}
-
-void DolphinCategoryDrawer::mouseButtonReleased(const QModelIndex &index, const QRect &blockRect, QMouseEvent *event)
-{
- if (!index.isValid() || hotSpotPressed == NoneHotSpot || categoryPressed != index) {
- event->ignore();
- return;
- }
- categoryPressed = QModelIndex();
- const QString category = index.model()->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString();
- int iconSize = KIconLoader::global()->currentSize(KIconLoader::Small);
- if (this->category == category) {
- QRect iconAllRect(blockRect);
- iconAllRect.setTop(iconAllRect.top() + 4);
- iconAllRect.setLeft(iconAllRect.right() - 16 - 7);
- iconAllRect.setSize(QSize(iconSize, iconSize));
- if (iconAllRect.contains(pos)) {
- if (hotSpotPressed == SelectAllHotSpot) {
- event->accept();
- emit actionRequested(SelectAll, index);
- } else {
- event->ignore();
- hotSpotPressed = NoneHotSpot;
- }
- return;
- }
- QRect iconNoneRect(blockRect);
- iconNoneRect.setTop(iconNoneRect.top() + 4);
- iconNoneRect.setLeft(iconNoneRect.right() - 16 * 2 - 7 * 2);
- iconNoneRect.setSize(QSize(iconSize, iconSize));
- if (iconNoneRect.contains(pos)) {
- if (hotSpotPressed == UnselectAllHotSpot) {
- event->accept();
- emit actionRequested(UnselectAll, index);
- } else {
- event->ignore();
- hotSpotPressed = NoneHotSpot;
- }
- return;
- }
- }
- event->ignore();
-}
-
-void DolphinCategoryDrawer::mouseMoved(const QModelIndex &index, const QRect &, QMouseEvent *event)
-{
- event->ignore();
- if (!index.isValid()) {
- return;
- }
- pos = event->pos();
- category = index.model()->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString();
-}
-
-void DolphinCategoryDrawer::mouseLeft(const QModelIndex &, const QRect &)
-{
- pos = QPoint();
- category.clear();
-}
+++ /dev/null
-/* This file is part of the KDE project
- * Copyright (C) 2007 Rafael Fernández López <ereslibre@kde.org>
- *
- * 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 DOLPHINCATEGORYDRAWER_H
-#define DOLPHINCATEGORYDRAWER_H
-
-#include <kcategorydrawer.h>
-
-#include <QStyleOption>
-#include <QModelIndex>
-
-#include <libdolphin_export.h>
-
-class LIBDOLPHINPRIVATE_EXPORT DolphinCategoryDrawer
- : public KCategoryDrawerV3
-{
-public:
- using KCategoryDrawerV2::mouseButtonPressed;
- using KCategoryDrawerV2::mouseButtonReleased;
-
- enum Action {
- SelectAll = 0,
- UnselectAll
- };
-
- DolphinCategoryDrawer(KCategorizedView *view);
-
- virtual ~DolphinCategoryDrawer();
-
- bool allCategorySelected(const QString &category) const;
-
- bool someCategorySelected(const QString &category) const;
-
- virtual void drawCategory(const QModelIndex &index, int sortRole,
- const QStyleOption &option, QPainter *painter) const;
-
- virtual int categoryHeight(const QModelIndex &index, const QStyleOption &option) const;
-
-protected:
- virtual void mouseButtonPressed(const QModelIndex &index, const QRect &blockRect, QMouseEvent *event);
-
- virtual void mouseButtonReleased(const QModelIndex &index, const QRect &blockRect, QMouseEvent *event);
-
- virtual void mouseMoved(const QModelIndex &index, const QRect &blockRect, QMouseEvent *event);
-
- virtual void mouseLeft(const QModelIndex &index,const QRect &blockRect);
-
-private:
- enum HotSpot {
- NoneHotSpot = 0,
- SelectAllHotSpot,
- UnselectAllHotSpot
- };
-
- HotSpot hotSpotPressed;
- QModelIndex categoryPressed;
-
- QPixmap selectAll;
- QPixmap selectAllHovered;
- QPixmap selectAllDisabled;
- QPixmap unselectAll;
- QPixmap unselectAllHovered;
- QPixmap unselectAllDisabled;
-
- QPoint pos;
- QString category;
-};
-
-#endif // DOLPHINCATEGORYDRAWER_H
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2007-2009 by Peter Penz <peter.penz19@gmail.com> *
- * *
- * 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 "dolphincolumnview.h"
-
-#include "dolphinmodel.h"
-#include "dolphincolumnviewcontainer.h"
-#include "dolphinviewcontroller.h"
-#include "dolphindirlister.h"
-#include "dolphinfileitemdelegate.h"
-#include "dolphinsortfilterproxymodel.h"
-#include "settings/dolphinsettings.h"
-#include "dolphinviewautoscroller.h"
-#include "dolphin_columnmodesettings.h"
-#include "dolphin_generalsettings.h"
-#include "draganddrophelper.h"
-#include "folderexpander.h"
-#include "tooltips/tooltipmanager.h"
-#include "viewextensionsfactory.h"
-#include "viewmodecontroller.h"
-#include "zoomlevelinfo.h"
-
-#include <KColorScheme>
-#include <KDirLister>
-#include <KFileItem>
-#include <KIO/PreviewJob>
-#include <KIcon>
-#include <KIconEffect>
-#include <KJob>
-#include <KLocale>
-#include <konqmimedata.h>
-
-#include <QApplication>
-#include <QClipboard>
-#include <QHeaderView>
-#include <QLabel>
-#include <QPainter>
-#include <QPoint>
-#include <QScrollBar>
-
-DolphinColumnView::DolphinColumnView(QWidget* parent,
- DolphinColumnViewContainer* container,
- const KUrl& url) :
- DolphinTreeView(parent),
- m_active(false),
- m_container(container),
- m_extensionsFactory(0),
- m_url(url),
- m_childUrl(),
- m_font(),
- m_decorationSize(),
- m_dirLister(0),
- m_dolphinModel(0),
- m_proxyModel(0),
- m_resizeWidget(0),
- m_resizeXOrigin(-1)
-{
- setMouseTracking(true);
- setAcceptDrops(true);
- setUniformRowHeights(true);
- setSelectionBehavior(SelectItems);
- setSelectionMode(QAbstractItemView::ExtendedSelection);
- setDragDropMode(QAbstractItemView::DragDrop);
- setDropIndicatorShown(false);
- setRootIsDecorated(false);
- setItemsExpandable(false);
- setEditTriggers(QAbstractItemView::NoEditTriggers);
- setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
- setVerticalScrollMode(QTreeView::ScrollPerPixel);
-
- m_resizeWidget = new QLabel(this);
- m_resizeWidget->setPixmap(KIcon("transform-move").pixmap(KIconLoader::SizeSmall));
- m_resizeWidget->setToolTip(i18nc("@info:tooltip", "Resize column"));
- setCornerWidget(m_resizeWidget);
- m_resizeWidget->installEventFilter(this);
-
- const ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
- Q_ASSERT(settings);
-
- if (settings->useSystemFont()) {
- m_font = KGlobalSettings::generalFont();
- } else {
- m_font = QFont(settings->fontFamily(),
- qRound(settings->fontSize()),
- settings->fontWeight(),
- settings->italicFont());
- m_font.setPointSizeF(settings->fontSize());
- }
-
- setMinimumWidth(settings->fontSize() * 10);
- setMaximumWidth(settings->columnWidth());
-
- connect(this, SIGNAL(viewportEntered()),
- m_container->m_dolphinViewController, SLOT(emitViewportEntered()));
- connect(this, SIGNAL(entered(const QModelIndex&)),
- this, SLOT(slotEntered(const QModelIndex&)));
-
- const DolphinView* dolphinView = m_container->m_dolphinViewController->view();
- connect(dolphinView, SIGNAL(showPreviewChanged()),
- this, SLOT(slotShowPreviewChanged()));
-
- m_dirLister = new DolphinDirLister();
- m_dirLister->setAutoUpdate(true);
- m_dirLister->setMainWindow(window());
- m_dirLister->setDelayedMimeTypes(true);
- const bool showHiddenFiles = m_container->m_dolphinViewController->view()->showHiddenFiles();
- m_dirLister->setShowingDotFiles(showHiddenFiles);
- connect(m_dirLister, SIGNAL(completed()), this, SLOT(slotDirListerCompleted()));
-
- m_dolphinModel = new DolphinModel(this);
- m_dolphinModel->setDirLister(m_dirLister);
- m_dolphinModel->setDropsAllowed(DolphinModel::DropOnDirectory);
-
- m_proxyModel = new DolphinSortFilterProxyModel(this);
- m_proxyModel->setSourceModel(m_dolphinModel);
- m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
-
- m_proxyModel->setSorting(dolphinView->sorting());
- m_proxyModel->setSortOrder(dolphinView->sortOrder());
- m_proxyModel->setSortFoldersFirst(dolphinView->sortFoldersFirst());
-
- setModel(m_proxyModel);
-
- connect(KGlobalSettings::self(), SIGNAL(kdisplayFontChanged()),
- this, SLOT(updateFont()));
-
- const ViewModeController* viewModeController = m_container->m_viewModeController;
- connect(viewModeController, SIGNAL(zoomLevelChanged(int)),
- this, SLOT(setZoomLevel(int)));
- const QString nameFilter = viewModeController->nameFilter();
- if (!nameFilter.isEmpty()) {
- m_proxyModel->setFilterFixedString(nameFilter);
- }
-
- updateDecorationSize(dolphinView->showPreview());
- updateBackground();
-
- DolphinViewController* dolphinViewController = m_container->m_dolphinViewController;
- m_extensionsFactory = new ViewExtensionsFactory(this, dolphinViewController, viewModeController);
- m_extensionsFactory->fileItemDelegate()->setMinimizedNameColumn(true);
-
- m_dirLister->openUrl(url, KDirLister::NoFlags);
-}
-
-DolphinColumnView::~DolphinColumnView()
-{
- delete m_proxyModel;
- m_proxyModel = 0;
- delete m_dolphinModel;
- m_dolphinModel = 0;
- m_dirLister = 0; // deleted by m_dolphinModel
-}
-
-
-void DolphinColumnView::setActive(bool active)
-{
- if (m_active != active) {
- m_active = active;
-
- if (active) {
- activate();
- } else {
- deactivate();
- }
- }
-}
-
-bool DolphinColumnView::isActive() const
-{
- return m_active;
-}
-
-void DolphinColumnView::setChildUrl(const KUrl& url)
-{
- m_childUrl = url;
-}
-
-KUrl DolphinColumnView::childUrl() const
-{
- return m_childUrl;
-}
-
-void DolphinColumnView::setUrl(const KUrl& url)
-{
- if (url != m_url) {
- m_url = url;
- m_dirLister->openUrl(url, KDirLister::NoFlags);
- }
-}
-
-KUrl DolphinColumnView::url() const
-{
- return m_url;
-}
-
-void DolphinColumnView::updateBackground()
-{
- // TODO: The alpha-value 150 is copied from DolphinView::setActive(). When
- // cleaning up the cut-indication of DolphinColumnView with the code from
- // DolphinView a common helper-class should be available which can be shared
- // by all view implementations -> no hardcoded value anymore
- const QPalette::ColorRole role = viewport()->backgroundRole();
- QColor color = viewport()->palette().color(role);
- color.setAlpha((m_active && m_container->m_active) ? 255 : 150);
-
- QPalette palette = viewport()->palette();
- palette.setColor(role, color);
- viewport()->setPalette(palette);
-
- update();
-}
-
-KFileItem DolphinColumnView::itemAt(const QPoint& pos) const
-{
- KFileItem item;
- const QModelIndex index = indexAt(pos);
- if (index.isValid() && (index.column() == DolphinModel::Name)) {
- const QModelIndex dolphinModelIndex = m_proxyModel->mapToSource(index);
- item = m_dolphinModel->itemForIndex(dolphinModelIndex);
- }
- return item;
-}
-
-void DolphinColumnView::setSelectionModel(QItemSelectionModel* model)
-{
- // If a change of the selection is done although the view is not active
- // (e. g. by the selection markers), the column must be activated. This
- // is done by listening to the current selectionChanged() signal.
- if (selectionModel()) {
- disconnect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
- this, SLOT(requestActivation()));
- }
-
- DolphinTreeView::setSelectionModel(model);
-
- connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
- this, SLOT(requestActivation()));
-}
-
-QStyleOptionViewItem DolphinColumnView::viewOptions() const
-{
- QStyleOptionViewItem viewOptions = DolphinTreeView::viewOptions();
- viewOptions.font = m_font;
- viewOptions.fontMetrics = QFontMetrics(m_font);
- viewOptions.decorationSize = m_decorationSize;
- viewOptions.showDecorationSelected = true;
- return viewOptions;
-}
-
-bool DolphinColumnView::event(QEvent* event)
-{
- if (event->type() == QEvent::Polish) {
- // Hide all columns except of the 'Name' column
- for (int i = DolphinModel::Name + 1; i < DolphinModel::ExtraColumnCount; ++i) {
- hideColumn(i);
- }
- header()->hide();
- }
-
- return DolphinTreeView::event(event);
-}
-
-void DolphinColumnView::startDrag(Qt::DropActions supportedActions)
-{
- DragAndDropHelper::instance().startDrag(this, supportedActions, m_container->m_dolphinViewController);
- DolphinTreeView::startDrag(supportedActions);
-}
-
-void DolphinColumnView::dragEnterEvent(QDragEnterEvent* event)
-{
- event->acceptProposedAction();
- requestActivation();
- DolphinTreeView::dragEnterEvent(event);
-}
-
-void DolphinColumnView::dragMoveEvent(QDragMoveEvent* event)
-{
- DolphinTreeView::dragMoveEvent(event);
- event->acceptProposedAction();
-}
-
-void DolphinColumnView::dropEvent(QDropEvent* event)
-{
- const QModelIndex index = indexAt(event->pos());
- m_container->m_dolphinViewController->setItemView(this);
- const QModelIndex dolphinModelIndex = m_proxyModel->mapToSource(index);
- const KFileItem item = m_dolphinModel->itemForIndex(dolphinModelIndex);
- m_container->m_dolphinViewController->indicateDroppedUrls(item, event);
- DolphinTreeView::dropEvent(event);
-}
-
-void DolphinColumnView::paintEvent(QPaintEvent* event)
-{
- if (!m_childUrl.isEmpty()) {
- // Indicate the shown URL of the next column by highlighting the shown folder item
- const QModelIndex dirIndex = m_dolphinModel->indexForUrl(m_childUrl);
- const QModelIndex proxyIndex = m_proxyModel->mapFromSource(dirIndex);
- if (proxyIndex.isValid() && !selectionModel()->isSelected(proxyIndex)) {
- QPainter painter(viewport());
-
- QStyleOptionViewItemV4 option;
- option.initFrom(this);
- option.rect = visualRect(proxyIndex);
- option.state = QStyle::State_Enabled | QStyle::State_HasFocus;
- option.viewItemPosition = QStyleOptionViewItemV4::OnlyOne;
- style()->drawPrimitive(QStyle::PE_FrameFocusRect, &option, &painter, this);
- }
- }
-
- DolphinTreeView::paintEvent(event);
-}
-
-void DolphinColumnView::mousePressEvent(QMouseEvent* event)
-{
- requestActivation();
- if (!indexAt(event->pos()).isValid() && (QApplication::mouseButtons() & Qt::MidButton)) {
- m_container->m_dolphinViewController->replaceUrlByClipboard();
- }
-
- DolphinTreeView::mousePressEvent(event);
-}
-
-void DolphinColumnView::keyPressEvent(QKeyEvent* event)
-{
- const bool hadSelection = selectionModel()->hasSelection();
- DolphinTreeView::keyPressEvent(event);
-
- DolphinViewController* controller = m_container->m_dolphinViewController;
- controller->handleKeyPressEvent(event);
- switch (event->key()) {
- case Qt::Key_Right: {
- // Special key handling for the column: A Key_Right should
- // open a new column for the currently selected folder.
- QModelIndex dolphinModelIndex = m_proxyModel->mapToSource(currentIndex());
-
- // If there is no selection we automatically move to the child url
- // instead of the first directory.
- // See BUG:263110
- if (!hadSelection && !childUrl().isEmpty()) {
- dolphinModelIndex = m_dolphinModel->indexForUrl(childUrl());
- }
-
- const KFileItem item = m_dolphinModel->itemForIndex(dolphinModelIndex);
- if (!item.isNull() && item.isDir()) {
- controller->emitItemTriggered(item);
- }
- break;
- }
-
- case Qt::Key_Escape:
- selectionModel()->setCurrentIndex(selectionModel()->currentIndex(),
- QItemSelectionModel::Current |
- QItemSelectionModel::Clear);
- break;
-
- default:
- break;
- }
-}
-
-void DolphinColumnView::contextMenuEvent(QContextMenuEvent* event)
-{
- requestActivation();
- DolphinTreeView::contextMenuEvent(event);
- m_container->m_dolphinViewController->triggerContextMenuRequest(event->pos());
-}
-
-void DolphinColumnView::wheelEvent(QWheelEvent* event)
-{
- const int step = m_decorationSize.height();
- verticalScrollBar()->setSingleStep(step);
- DolphinTreeView::wheelEvent(event);
-}
-
-void DolphinColumnView::leaveEvent(QEvent* event)
-{
- DolphinTreeView::leaveEvent(event);
- // if the mouse is above an item and moved very fast outside the widget,
- // no viewportEntered() signal might be emitted although the mouse has been moved
- // above the viewport
- m_container->m_dolphinViewController->emitViewportEntered();
-}
-
-void DolphinColumnView::currentChanged(const QModelIndex& current, const QModelIndex& previous)
-{
- DolphinTreeView::currentChanged(current, previous);
- m_extensionsFactory->handleCurrentIndexChange(current, previous);
-}
-
-QRect DolphinColumnView::visualRect(const QModelIndex& index) const
-{
- QRect rect = DolphinTreeView::visualRect(index);
-
- const QModelIndex dolphinModelIndex = m_proxyModel->mapToSource(index);
- const KFileItem item = m_dolphinModel->itemForIndex(dolphinModelIndex);
- if (!item.isNull()) {
- const int width = DolphinFileItemDelegate::nameColumnWidth(item.text(), viewOptions());
- rect.setWidth(width);
- }
-
- return rect;
-}
-
-bool DolphinColumnView::acceptsDrop(const QModelIndex& index) const
-{
- if (index.isValid() && (index.column() == DolphinModel::Name)) {
- // Accept drops above directories
- const QModelIndex dolphinModelIndex = m_proxyModel->mapToSource(index);
- const KFileItem item = m_dolphinModel->itemForIndex(dolphinModelIndex);
- return !item.isNull() && item.isDir();
- }
-
- return false;
-}
-
-bool DolphinColumnView::eventFilter(QObject* watched, QEvent* event)
-{
- if (watched == m_resizeWidget) {
- switch (event->type()) {
- case QEvent::MouseButtonPress: {
- // Initiate the resizing of the column
- QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
- m_resizeXOrigin = mouseEvent->globalX();
- m_resizeWidget->setMouseTracking(true);
- event->accept();
- return true;
- }
-
- case QEvent::MouseButtonDblClick: {
- // Reset the column width to the default value
- const ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
- setMaximumWidth(settings->columnWidth());
- m_container->layoutColumns();
- m_resizeWidget->setMouseTracking(false);
- m_resizeXOrigin = -1;
- event->accept();
- return true;
- }
-
- case QEvent::MouseMove: {
- // Resize the column and trigger a relayout of the container
- QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
- int requestedWidth = maximumWidth() - m_resizeXOrigin + mouseEvent->globalX();;
- if (requestedWidth < minimumWidth()) {
- requestedWidth = minimumWidth();
- }
- setMaximumWidth(requestedWidth);
-
- m_container->layoutColumns();
-
- m_resizeXOrigin = mouseEvent->globalX();
-
- event->accept();
- return true;
- }
-
- case QEvent::MouseButtonRelease: {
- // The resizing has been finished
- m_resizeWidget->setMouseTracking(false);
- m_resizeXOrigin = -1;
- event->accept();
- return true;
- }
-
- default:
- break;
- }
- }
- return DolphinTreeView::eventFilter(watched, event);
-}
-void DolphinColumnView::setZoomLevel(int level)
-{
- const int size = ZoomLevelInfo::iconSizeForZoomLevel(level);
- ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
-
- const bool showPreview = m_container->m_dolphinViewController->view()->showPreview();
- if (showPreview) {
- settings->setPreviewSize(size);
- } else {
- settings->setIconSize(size);
- }
-
- updateDecorationSize(showPreview);
-}
-
-void DolphinColumnView::slotEntered(const QModelIndex& index)
-{
- m_container->m_dolphinViewController->setItemView(this);
- m_container->m_dolphinViewController->emitItemEntered(index);
-}
-
-void DolphinColumnView::requestActivation()
-{
- m_container->m_dolphinViewController->requestActivation();
- if (!m_active) {
- m_container->requestActivation(this);
- selectionModel()->clear();
- }
-}
-
-void DolphinColumnView::updateFont()
-{
- const ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
- Q_ASSERT(settings);
-
- if (settings->useSystemFont()) {
- m_font = KGlobalSettings::generalFont();
- }
-}
-
-void DolphinColumnView::slotShowPreviewChanged()
-{
- const DolphinView* view = m_container->m_dolphinViewController->view();
- updateDecorationSize(view->showPreview());
-}
-
-void DolphinColumnView::slotDirListerCompleted()
-{
- if (!m_childUrl.isEmpty()) {
- return;
- }
-
- // Try to optimize the width of the column, so that no name gets clipped
- const int requiredWidth = sizeHintForColumn(DolphinModel::Name);
-
- const ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
- if (requiredWidth > settings->columnWidth()) {
- int frameAroundContents = 0;
- if (style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents)) {
- // TODO: Using 2 PM_DefaultFrameWidths are not sufficient. Check Qt-code
- // for other pixelmetrics that should be added...
- frameAroundContents = style()->pixelMetric(QStyle::PM_DefaultFrameWidth) * 4;
- }
-
- const int scrollBarWidth = style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, verticalScrollBar());
-
- setMaximumWidth(requiredWidth + frameAroundContents + scrollBarWidth);
- m_container->layoutColumns();
- if (m_active) {
- m_container->assureVisibleActiveColumn();
- }
- }
-}
-
-void DolphinColumnView::activate()
-{
- setFocus(Qt::OtherFocusReason);
-
- connect(this, SIGNAL(clicked(const QModelIndex&)),
- m_container->m_dolphinViewController, SLOT(requestTab(const QModelIndex&)));
- if (KGlobalSettings::singleClick()) {
- connect(this, SIGNAL(clicked(const QModelIndex&)),
- m_container->m_dolphinViewController, SLOT(triggerItem(const QModelIndex&)));
- } else {
- connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
- m_container->m_dolphinViewController, SLOT(triggerItem(const QModelIndex&)));
- }
-
- if (selectionModel() && selectionModel()->currentIndex().isValid()) {
- selectionModel()->setCurrentIndex(selectionModel()->currentIndex(), QItemSelectionModel::SelectCurrent);
- }
-
- updateBackground();
-}
-
-void DolphinColumnView::deactivate()
-{
- clearFocus();
-
- disconnect(this, SIGNAL(clicked(const QModelIndex&)),
- m_container->m_dolphinViewController, SLOT(requestTab(const QModelIndex&)));
- if (KGlobalSettings::singleClick()) {
- disconnect(this, SIGNAL(clicked(const QModelIndex&)),
- m_container->m_dolphinViewController, SLOT(triggerItem(const QModelIndex&)));
- } else {
- disconnect(this, SIGNAL(doubleClicked(const QModelIndex&)),
- m_container->m_dolphinViewController, SLOT(triggerItem(const QModelIndex&)));
- }
-
- // It is important to disconnect the connection to requestActivation() temporary, otherwise the internal
- // clearing of the selection would result in activating the column again.
- disconnect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
- this, SLOT(requestActivation()));
- const QModelIndex current = selectionModel()->currentIndex();
- selectionModel()->clear();
- selectionModel()->setCurrentIndex(current, QItemSelectionModel::NoUpdate);
- connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
- this, SLOT(requestActivation()));
-
- updateBackground();
-}
-
-void DolphinColumnView::updateDecorationSize(bool showPreview)
-{
- ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
- const int iconSize = showPreview ? settings->previewSize() : settings->iconSize();
- const QSize size(iconSize, iconSize);
- setIconSize(size);
-
- m_decorationSize = size;
-
- doItemsLayout();
-}
-
-#include "dolphincolumnview.moc"
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2007-2009 by Peter Penz <peter.penz19@gmail.com> *
- * *
- * 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 DOLPHINCOLUMNVIEW_H
-#define DOLPHINCOLUMNVIEW_H
-
-#include "dolphinview.h"
-#include "dolphintreeview.h"
-
-#include <QFont>
-#include <QSize>
-#include <QStyleOption>
-
-#include <KUrl>
-
-class DolphinColumnViewContainer;
-class DolphinModel;
-class DolphinSortFilterProxyModel;
-class DolphinDirLister;
-class KFileItem;
-class QLabel;
-class SelectionManager;
-class ViewExtensionsFactory;
-
-/**
- * Represents one column inside the DolphinColumnViewContainer.
- */
-class DolphinColumnView : public DolphinTreeView
-{
- Q_OBJECT
-
-public:
- DolphinColumnView(QWidget* parent,
- DolphinColumnViewContainer* container,
- const KUrl& url);
- virtual ~DolphinColumnView();
-
- /**
- * An active column is defined as column, which shows the same URL
- * as indicated by the URL navigator. The active column is usually
- * drawn in a lighter color. All operations are applied to this column.
- */
- void setActive(bool active);
- bool isActive() const;
-
- /**
- * Sets the directory URL of the child column that is shown next to
- * this column. This property is used for a visual indication
- * of the shown directory, it does not trigger a loading of the model.
- * When no url is selected and the user presses right, then child
- * url will be used as column.
- */
- void setChildUrl(const KUrl& url);
- KUrl childUrl() const;
-
- /** Sets the directory URL that is shown inside the column widget. */
- void setUrl(const KUrl& url);
-
- /** Returns the directory URL that is shown inside the column widget. */
- KUrl url() const;
-
- /**
- * Updates the background color dependent from the activation state
- * \a isViewActive of the column view.
- */
- void updateBackground();
-
- /**
- * Returns the item on the position \a pos. The KFileItem instance
- * is null if no item is below the position.
- */
- KFileItem itemAt(const QPoint& pos) const;
-
- virtual void setSelectionModel(QItemSelectionModel* model);
-
-protected:
- virtual QStyleOptionViewItem viewOptions() const;
- virtual bool event(QEvent* event);
- virtual void startDrag(Qt::DropActions supportedActions);
- virtual void dragEnterEvent(QDragEnterEvent* event);
- virtual void dragMoveEvent(QDragMoveEvent* event);
- virtual void dropEvent(QDropEvent* event);
- virtual void paintEvent(QPaintEvent* event);
- virtual void mousePressEvent(QMouseEvent* event);
- virtual void keyPressEvent(QKeyEvent* event);
- virtual void contextMenuEvent(QContextMenuEvent* event);
- virtual void wheelEvent(QWheelEvent* event);
- virtual void leaveEvent(QEvent* event);
- virtual void currentChanged(const QModelIndex& current, const QModelIndex& previous);
- virtual QRect visualRect(const QModelIndex& index) const;
- virtual bool acceptsDrop(const QModelIndex& index) const;
- virtual bool eventFilter(QObject* watched, QEvent* event);
-
-private slots:
- void setZoomLevel(int level);
-
- void slotEntered(const QModelIndex& index);
- void requestActivation();
- void updateFont();
-
- void slotShowPreviewChanged();
-
- void slotDirListerCompleted();
-
-private:
- /** Used by DolphinColumnView::setActive(). */
- void activate();
-
- /** Used by DolphinColumnView::setActive(). */
- void deactivate();
-
- void updateDecorationSize(bool showPreview);
-
-private:
- bool m_active;
- DolphinColumnViewContainer* m_container;
- SelectionManager* m_selectionManager;
- ViewExtensionsFactory* m_extensionsFactory;
- KUrl m_url; // URL of the directory that is shown
- KUrl m_childUrl; // URL of the next column that is shown
-
- QFont m_font;
- QSize m_decorationSize;
-
- DolphinDirLister* m_dirLister;
- DolphinModel* m_dolphinModel;
- DolphinSortFilterProxyModel* m_proxyModel;
-
- QLabel* m_resizeWidget;
- int m_resizeXOrigin;
-
- friend class DolphinColumnViewContainer;
-};
-
-#endif
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2007-2009 by Peter Penz <peter.penz19@gmail.com> *
- * *
- * 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 "dolphincolumnviewcontainer.h"
-
-#include "dolphin_columnmodesettings.h"
-
-#include "dolphincolumnview.h"
-#include "dolphinviewcontroller.h"
-#include "dolphinsortfilterproxymodel.h"
-#include "draganddrophelper.h"
-#include "settings/dolphinsettings.h"
-#include "viewmodecontroller.h"
-
-#include <QPoint>
-#include <QScrollBar>
-#include <QTimeLine>
-#include <QTimer>
-
-DolphinColumnViewContainer::DolphinColumnViewContainer(QWidget* parent,
- DolphinViewController* dolphinViewController,
- const ViewModeController* viewModeController) :
- QScrollArea(parent),
- m_dolphinViewController(dolphinViewController),
- m_viewModeController(viewModeController),
- m_active(false),
- m_index(-1),
- m_contentX(0),
- m_columns(),
- m_emptyViewport(0),
- m_animation(0),
- m_dragSource(0),
- m_activeUrlTimer(0),
- m_assureVisibleActiveColumnTimer(0)
-{
- Q_ASSERT(dolphinViewController);
- Q_ASSERT(viewModeController);
-
- setAcceptDrops(true);
- setFocusPolicy(Qt::NoFocus);
- setFrameShape(QFrame::NoFrame);
- setLayoutDirection(Qt::LeftToRight);
-
- connect(viewModeController, SIGNAL(activationChanged(bool)),
- this, SLOT(updateColumnsBackground(bool)));
-
- connect(horizontalScrollBar(), SIGNAL(valueChanged(int)),
- this, SLOT(moveContentHorizontally(int)));
-
- m_animation = new QTimeLine(500, this);
- connect(m_animation, SIGNAL(frameChanged(int)), horizontalScrollBar(), SLOT(setValue(int)));
-
- m_activeUrlTimer = new QTimer(this);
- m_activeUrlTimer->setSingleShot(true);
- m_activeUrlTimer->setInterval(200);
- connect(m_activeUrlTimer, SIGNAL(timeout()),
- this, SLOT(updateActiveUrl()));
-
- // Assuring that the active column gets fully visible is done with a small delay. This
- // prevents that for temporary activations an animation gets started (e. g. when clicking
- // on any folder of the parent column, the child column gets activated).
- m_assureVisibleActiveColumnTimer = new QTimer(this);
- m_assureVisibleActiveColumnTimer->setSingleShot(true);
- m_assureVisibleActiveColumnTimer->setInterval(200);
- connect(m_assureVisibleActiveColumnTimer, SIGNAL(timeout()),
- this, SLOT(slotAssureVisibleActiveColumn()));
-
- DolphinColumnView* column = new DolphinColumnView(viewport(), this, viewModeController->url());
- m_columns.append(column);
- requestActivation(column);
-
- m_emptyViewport = new QFrame(viewport());
- m_emptyViewport->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
-
- updateColumnsBackground(true);
-}
-
-DolphinColumnViewContainer::~DolphinColumnViewContainer()
-{
- delete m_dragSource;
- m_dragSource = 0;
-}
-
-KUrl DolphinColumnViewContainer::rootUrl() const
-{
- return m_columns[0]->url();
-}
-
-QAbstractItemView* DolphinColumnViewContainer::activeColumn() const
-{
- return m_columns[m_index];
-}
-
-void DolphinColumnViewContainer::showColumn(const KUrl& url)
-{
- if (!rootUrl().isParentOf(url)) {
- removeAllColumns();
- m_columns[0]->setUrl(url);
- return;
- }
-
- int columnIndex = 0;
- foreach (DolphinColumnView* column, m_columns) {
- if (column->url().equals(url, KUrl::CompareWithoutTrailingSlash)) {
- // the column represents already the requested URL, hence activate it
- requestActivation(column);
- layoutColumns();
- return;
- } else if (!column->url().isParentOf(url)) {
- // the column is no parent of the requested URL, hence
- // just delete all remaining columns
- if (columnIndex > 0) {
- QList<DolphinColumnView*>::iterator start = m_columns.begin() + columnIndex;
- QList<DolphinColumnView*>::iterator end = m_columns.end();
- for (QList<DolphinColumnView*>::iterator it = start; it != end; ++it) {
- deleteColumn(*it);
- }
- m_columns.erase(start, end);
-
- const int maxIndex = m_columns.count() - 1;
- Q_ASSERT(maxIndex >= 0);
- if (m_index > maxIndex) {
- m_index = maxIndex;
- }
- break;
- }
- }
- ++columnIndex;
- }
-
- // Create missing columns. Assuming that the path is "/home/peter/Temp/" and
- // the target path is "/home/peter/Temp/a/b/c/", then the columns "a", "b" and
- // "c" will be created.
- const int lastIndex = m_columns.count() - 1;
- Q_ASSERT(lastIndex >= 0);
-
- const KUrl& activeUrl = m_columns[lastIndex]->url();
- Q_ASSERT(activeUrl.isParentOf(url));
- Q_ASSERT(activeUrl != url);
-
- QString path = activeUrl.url(KUrl::AddTrailingSlash);
- const QString targetPath = url.url(KUrl::AddTrailingSlash);
-
- columnIndex = lastIndex;
- int slashIndex = path.count('/');
- bool hasSubPath = (slashIndex >= 0);
- while (hasSubPath) {
- const QString subPath = targetPath.section('/', slashIndex, slashIndex);
- if (subPath.isEmpty()) {
- hasSubPath = false;
- } else {
- path += subPath + '/';
- ++slashIndex;
-
- const KUrl childUrl = KUrl(path);
- m_columns[columnIndex]->setChildUrl(childUrl);
- columnIndex++;
-
- DolphinColumnView* column = new DolphinColumnView(viewport(), this, childUrl);
- m_columns.append(column);
-
- // Before invoking layoutColumns() the column must be set visible temporary.
- // To prevent a flickering the initial geometry is set to a hidden position.
- column->setGeometry(QRect(-1, -1, 1, 1));
- column->show();
- layoutColumns();
- }
- }
-
- requestActivation(m_columns[columnIndex]);
-}
-
-void DolphinColumnViewContainer::mousePressEvent(QMouseEvent* event)
-{
- m_dolphinViewController->requestActivation();
- QScrollArea::mousePressEvent(event);
-}
-
-void DolphinColumnViewContainer::keyPressEvent(QKeyEvent* event)
-{
- if (event->key() == Qt::Key_Left) {
- if (m_index > 0) {
- requestActivation(m_columns[m_index - 1]);
- }
- } else {
- QScrollArea::keyPressEvent(event);
- }
-}
-
-void DolphinColumnViewContainer::resizeEvent(QResizeEvent* event)
-{
- QScrollArea::resizeEvent(event);
- layoutColumns();
- assureVisibleActiveColumn();
-}
-
-void DolphinColumnViewContainer::wheelEvent(QWheelEvent* event)
-{
- // let Ctrl+wheel events propagate to the DolphinView for icon zooming
- if ((event->modifiers() & Qt::ControlModifier) == Qt::ControlModifier) {
- event->ignore();
- } else {
- QScrollArea::wheelEvent(event);
- }
-}
-
-void DolphinColumnViewContainer::moveContentHorizontally(int x)
-{
- m_contentX = isRightToLeft() ? +x : -x;
- layoutColumns();
-}
-
-void DolphinColumnViewContainer::updateColumnsBackground(bool active)
-{
- if (active == m_active) {
- return;
- }
-
- m_active = active;
-
- // dim the background of the viewport
- const QPalette::ColorRole role = viewport()->backgroundRole();
- QColor background = viewport()->palette().color(role);
- background.setAlpha(0); // make background transparent
-
- QPalette palette = viewport()->palette();
- palette.setColor(role, background);
- viewport()->setPalette(palette);
-
- foreach (DolphinColumnView* column, m_columns) {
- column->updateBackground();
- }
-}
-
-void DolphinColumnViewContainer::updateActiveUrl()
-{
- const KUrl activeUrl = m_columns[m_index]->url();
- m_dolphinViewController->requestUrlChange(activeUrl);
-}
-
-void DolphinColumnViewContainer::slotAssureVisibleActiveColumn()
-{
- const int viewportWidth = viewport()->width();
- const int x = activeColumn()->x();
-
- // When a column that is partly visible gets activated,
- // it is useful to also assure that the neighbor column is partly visible.
- // This allows the user to scroll to the first/last column without using the
- // scrollbar and drag & drop operations to invisible columns.
- const int neighborColumnGap = 3 * style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, verticalScrollBar());
-
- const int width = activeColumn()->maximumWidth();
- if (x + width > viewportWidth) {
- const int newContentX = m_contentX - x - width + viewportWidth;
- if (isRightToLeft()) {
- m_animation->setFrameRange(m_contentX, newContentX + neighborColumnGap);
- } else {
- m_animation->setFrameRange(-m_contentX, -newContentX + neighborColumnGap);
- }
- if (m_animation->state() != QTimeLine::Running) {
- m_animation->start();
- }
- } else if (x < 0) {
- const int newContentX = m_contentX - x;
- if (isRightToLeft()) {
- m_animation->setFrameRange(m_contentX, newContentX - neighborColumnGap);
- } else {
- m_animation->setFrameRange(-m_contentX, -newContentX - neighborColumnGap);
- }
- if (m_animation->state() != QTimeLine::Running) {
- m_animation->start();
- }
- }
-}
-
-void DolphinColumnViewContainer::assureVisibleActiveColumn()
-{
- m_assureVisibleActiveColumnTimer->start();
-}
-
-void DolphinColumnViewContainer::layoutColumns()
-{
- // Layout the position of the columns corresponding to their maximum width
- QRect emptyViewportRect;
- if (isRightToLeft()) {
- int columnWidth = m_columns[0]->maximumWidth();
- int x = viewport()->width() - columnWidth + m_contentX;
- foreach (DolphinColumnView* column, m_columns) {
- columnWidth = column->maximumWidth();
- column->setGeometry(QRect(x, 0, columnWidth, viewport()->height()));
- x -= columnWidth;
- }
- emptyViewportRect = QRect(0, 0, x + columnWidth, viewport()->height());
- } else {
- int x = m_contentX;
- foreach (DolphinColumnView* column, m_columns) {
- const int columnWidth = column->maximumWidth();
- column->setGeometry(QRect(x, 0, columnWidth, viewport()->height()));
- x += columnWidth;
- }
- emptyViewportRect = QRect(x, 0, viewport()->width() - x, viewport()->height());
- }
-
- // Show an empty viewport if the columns don't cover the whole viewport
- if (emptyViewportRect.isValid()) {
- m_emptyViewport->show();
- m_emptyViewport->setGeometry(emptyViewportRect);
- } else {
- m_emptyViewport->hide();
- }
-
- // Update the horizontal position indicator
- int contentWidth = 0;
- foreach (DolphinColumnView* column, m_columns) {
- contentWidth += column->maximumWidth();
- }
-
- const int scrollBarMax = contentWidth - viewport()->width();
- const bool updateScrollBar = (horizontalScrollBar()->pageStep() != contentWidth)
- || (horizontalScrollBar()->maximum() != scrollBarMax);
- if (updateScrollBar) {
- horizontalScrollBar()->setPageStep(contentWidth);
- horizontalScrollBar()->setRange(0, scrollBarMax);
- }
-}
-
-void DolphinColumnViewContainer::requestActivation(DolphinColumnView* column)
-{
- if (m_dolphinViewController->itemView() != column) {
- m_dolphinViewController->setItemView(column);
- }
- if (focusProxy() != column) {
- setFocusProxy(column);
- }
-
- if (!column->isActive()) {
- // Deactivate the currently active column
- if (m_index >= 0) {
- m_columns[m_index]->setActive(false);
- }
-
- // Get the index of the column that should get activated
- int index = 0;
- foreach (DolphinColumnView* currColumn, m_columns) {
- if (currColumn == column) {
- break;
- }
- ++index;
- }
-
- Q_ASSERT(index != m_index);
- Q_ASSERT(index < m_columns.count());
-
- // Activate the requested column
- m_index = index;
- m_columns[m_index]->setActive(true);
-
- m_activeUrlTimer->start(); // calls slot updateActiveUrl()
- }
-
- assureVisibleActiveColumn();
-}
-
-void DolphinColumnViewContainer::removeAllColumns()
-{
- QList<DolphinColumnView*>::iterator start = m_columns.begin() + 1;
- QList<DolphinColumnView*>::iterator end = m_columns.end();
- for (QList<DolphinColumnView*>::iterator it = start; it != end; ++it) {
- deleteColumn(*it);
- }
- m_columns.erase(start, end);
- m_index = 0;
- m_columns[0]->setActive(true);
- assureVisibleActiveColumn();
-}
-
-void DolphinColumnViewContainer::deleteColumn(DolphinColumnView* column)
-{
- if (!column) {
- return;
- }
-
- if (m_dolphinViewController->itemView() == column) {
- m_dolphinViewController->setItemView(0);
- }
- // deleteWhenNotDragSource(column) does not necessarily delete column,
- // and we want its preview generator destroyed immediately.
- column->hide();
- // Prevent automatic destruction of column when this DolphinColumnViewContainer
- // is destroyed.
- column->setParent(0);
- column->disconnect();
-
- if (DragAndDropHelper::instance().isDragSource(column)) {
- // The column is a drag source (the feature "Open folders
- // during drag operations" is used). Deleting the view
- // during an ongoing drag operation is not allowed, so
- // this will postponed.
- if (m_dragSource) {
- // the old stored view is obviously not the drag source anymore
- m_dragSource->deleteLater();
- m_dragSource = 0;
- }
- m_dragSource = column;
- } else {
- delete column;
- column = 0;
- }
-}
-
-#include "dolphincolumnviewcontainer.moc"
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2007-2009 by Peter Penz <peter.penz19@gmail.com> *
- * *
- * 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 DOLPHINCOLUMNVIEWCONTAINER_H
-#define DOLPHINCOLUMNVIEWCONTAINER_H
-
-#include "dolphinview.h"
-
-#include <KUrl>
-
-#include <QList>
-#include <QScrollArea>
-#include <QString>
-
-class DolphinColumnView;
-class DolphinViewController;
-class QFrame;
-class QTimeLine;
-class QTimer;
-
-/**
- * @brief Represents a container for columns represented as instances
- * of DolphinColumnView.
- *
- * @see DolphinColumnView
- */
-class DolphinColumnViewContainer : public QScrollArea
-{
- Q_OBJECT
-
-public:
- /**
- * @param parent Parent widget.
- * @param dolphinViewController Allows the DolphinColumnView to control the
- * DolphinView in a limited way.
- * @param viewModeController Controller that is used by the DolphinView
- * to control the DolphinColumnView. The DolphinColumnView
- * only has read access to the controller.
- * @param model Directory that is shown.
- */
- explicit DolphinColumnViewContainer(QWidget* parent,
- DolphinViewController* dolphinViewController,
- const ViewModeController* viewModeController);
- virtual ~DolphinColumnViewContainer();
-
- KUrl rootUrl() const;
-
- QAbstractItemView* activeColumn() const;
-
- /**
- * Shows the column which represents the URL \a url. If the column
- * is already shown, it gets activated, otherwise it will be created.
- */
- void showColumn(const KUrl& url);
-
-protected:
- virtual void mousePressEvent(QMouseEvent* event);
- virtual void keyPressEvent(QKeyEvent* event);
- virtual void resizeEvent(QResizeEvent* event);
- virtual void wheelEvent(QWheelEvent* event);
-
-private slots:
- /**
- * Moves the content of the columns view to represent
- * the scrollbar position \a x.
- */
- void moveContentHorizontally(int x);
-
- /**
- * Updates the background color of the columns to respect
- * the current activation state \a active.
- */
- void updateColumnsBackground(bool active);
-
- /**
- * Tells the Dolphin controller to update the active URL
- * to m_activeUrl. The slot is called asynchronously with a
- * small delay, as this prevents a flickering when a directory
- * from an inactive column gets selected.
- */
- void updateActiveUrl();
-
- /**
- * Invoked when m_assureVisibleActiveColumnTimer has been exceeded.
- * Assures that the currently active column is fully visible
- * by adjusting the horizontal position of the content.
- */
- void slotAssureVisibleActiveColumn();
-
-private:
- /**
- * Assures that the currently active column is fully visible
- * by adjusting the horizontal position of the content. The
- * adjustment is done with a small delay (see
- * slotAssureVisibleActiveColumn();
- */
- void assureVisibleActiveColumn();
-
- void layoutColumns();
-
- /**
- * Request the activation for the column \a column. It is assured
- * that the columns gets fully visible by adjusting the horizontal
- * position of the content.
- */
- void requestActivation(DolphinColumnView* column);
-
- /** Removes all columns except of the root column. */
- void removeAllColumns();
-
- /**
- * Deletes the column. If the itemview of the controller is set to the column,
- * the controllers itemview is set to 0.
- */
- void deleteColumn(DolphinColumnView* column);
-
-private:
- DolphinViewController* m_dolphinViewController;
- const ViewModeController* m_viewModeController;
- bool m_active;
- int m_index;
- int m_contentX;
- QList<DolphinColumnView*> m_columns;
- QFrame* m_emptyViewport;
- QTimeLine* m_animation;
- QAbstractItemView* m_dragSource;
-
- QTimer* m_activeUrlTimer;
- QTimer* m_assureVisibleActiveColumnTimer;
-
- friend class DolphinColumnView;
-};
-
-#endif
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2006 by Peter Penz (peter.penz@gmx.at) *
- * Copyright (C) 2008 by Simon St. James (kdedevel@etotheipiplusone.com) *
- * *
- * 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 "dolphindetailsview.h"
-
-#include "additionalinfoaccessor.h"
-#include "dolphinmodel.h"
-#include "dolphinviewcontroller.h"
-#include "dolphinfileitemdelegate.h"
-#include "settings/dolphinsettings.h"
-#include "dolphinsortfilterproxymodel.h"
-#include "dolphinviewautoscroller.h"
-#include "draganddrophelper.h"
-#include "viewextensionsfactory.h"
-#include "viewmodecontroller.h"
-#include "viewproperties.h"
-#include "zoomlevelinfo.h"
-
-#include "dolphin_detailsmodesettings.h"
-#include "dolphin_generalsettings.h"
-
-#include <KDirModel>
-#include <KDirLister>
-#include <KLocale>
-#include <KMenu>
-
-#include <QApplication>
-#include <QHeaderView>
-#include <QScrollBar>
-
-DolphinDetailsView::DolphinDetailsView(QWidget* parent,
- DolphinViewController* dolphinViewController,
- const ViewModeController* viewModeController,
- DolphinSortFilterProxyModel* proxyModel) :
- DolphinTreeView(parent),
- m_autoResize(true),
- m_dolphinViewController(dolphinViewController),
- m_extensionsFactory(0),
- m_expandableFoldersAction(0),
- m_expandedUrls(),
- m_font(),
- m_decorationSize()
-{
- const DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
- Q_ASSERT(settings);
- Q_ASSERT(dolphinViewController);
- Q_ASSERT(viewModeController);
-
- setLayoutDirection(Qt::LeftToRight);
- setAcceptDrops(true);
- setSortingEnabled(true);
- setSelectionBehavior(SelectItems);
- setDragDropMode(QAbstractItemView::DragDrop);
- setDropIndicatorShown(false);
- setAlternatingRowColors(true);
- setRootIsDecorated(settings->expandableFolders());
- setItemsExpandable(settings->expandableFolders());
- setEditTriggers(QAbstractItemView::NoEditTriggers);
- setModel(proxyModel);
-
- setMouseTracking(true);
-
- const ViewProperties props(viewModeController->url());
- setSortIndicatorSection(props.sorting());
- setSortIndicatorOrder(props.sortOrder());
-
- QHeaderView* headerView = header();
- connect(headerView, SIGNAL(sectionClicked(int)),
- this, SLOT(synchronizeSortingState(int)));
- headerView->setContextMenuPolicy(Qt::CustomContextMenu);
- connect(headerView, SIGNAL(customContextMenuRequested(const QPoint&)),
- this, SLOT(configureSettings(const QPoint&)));
- connect(headerView, SIGNAL(sectionResized(int, int, int)),
- this, SLOT(slotHeaderSectionResized(int, int, int)));
- connect(headerView, SIGNAL(sectionHandleDoubleClicked(int)),
- this, SLOT(disableAutoResizing()));
-
- connect(parent, SIGNAL(sortingChanged(DolphinView::Sorting)),
- this, SLOT(setSortIndicatorSection(DolphinView::Sorting)));
- connect(parent, SIGNAL(sortOrderChanged(Qt::SortOrder)),
- this, SLOT(setSortIndicatorOrder(Qt::SortOrder)));
-
- connect(this, SIGNAL(clicked(const QModelIndex&)),
- dolphinViewController, SLOT(requestTab(const QModelIndex&)));
- if (KGlobalSettings::singleClick()) {
- connect(this, SIGNAL(clicked(const QModelIndex&)),
- dolphinViewController, SLOT(triggerItem(const QModelIndex&)));
- } else {
- connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
- dolphinViewController, SLOT(triggerItem(const QModelIndex&)));
- }
-
- connect(this, SIGNAL(entered(const QModelIndex&)),
- this, SLOT(slotEntered(const QModelIndex&)));
- connect(this, SIGNAL(viewportEntered()),
- dolphinViewController, SLOT(emitViewportEntered()));
- connect(viewModeController, SIGNAL(zoomLevelChanged(int)),
- this, SLOT(setZoomLevel(int)));
- connect(dolphinViewController->view(), SIGNAL(additionalInfoChanged()),
- this, SLOT(updateColumnVisibility()));
- connect(viewModeController, SIGNAL(activationChanged(bool)),
- this, SLOT(slotActivationChanged(bool)));
-
- if (settings->useSystemFont()) {
- m_font = KGlobalSettings::generalFont();
- } else {
- m_font = QFont(settings->fontFamily(),
- qRound(settings->fontSize()),
- settings->fontWeight(),
- settings->italicFont());
- m_font.setPointSizeF(settings->fontSize());
- }
-
- setVerticalScrollMode(QTreeView::ScrollPerPixel);
- setHorizontalScrollMode(QTreeView::ScrollPerPixel);
-
- const DolphinView* view = dolphinViewController->view();
- connect(view, SIGNAL(showPreviewChanged()),
- this, SLOT(slotShowPreviewChanged()));
-
- viewport()->installEventFilter(this);
-
- connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)),
- this, SLOT(slotGlobalSettingsChanged(int)));
-
- m_expandableFoldersAction = new QAction(i18nc("@option:check", "Expandable Folders"), this);
- m_expandableFoldersAction->setCheckable(true);
- connect(m_expandableFoldersAction, SIGNAL(toggled(bool)),
- this, SLOT(setFoldersExpandable(bool)));
-
- connect(this, SIGNAL(expanded(const QModelIndex&)), this, SLOT(slotExpanded(const QModelIndex&)));
- connect(this, SIGNAL(collapsed(const QModelIndex&)), this, SLOT(slotCollapsed(const QModelIndex&)));
-
- updateDecorationSize(view->showPreview());
-
- m_extensionsFactory = new ViewExtensionsFactory(this, dolphinViewController, viewModeController);
- m_extensionsFactory->fileItemDelegate()->setMinimizedNameColumn(true);
-
- KDirLister *dirLister = qobject_cast<KDirModel*>(proxyModel->sourceModel())->dirLister();
- connect(dirLister, SIGNAL(newItems(KFileItemList)), this, SLOT(resizeColumns()));
-}
-
-DolphinDetailsView::~DolphinDetailsView()
-{
-}
-
-QSet<KUrl> DolphinDetailsView::expandedUrls() const
-{
- return m_expandedUrls;
-}
-
-bool DolphinDetailsView::event(QEvent* event)
-{
- if (event->type() == QEvent::Polish) {
- header()->setResizeMode(QHeaderView::Interactive);
- updateColumnVisibility();
- }
-
- return DolphinTreeView::event(event);
-}
-
-QStyleOptionViewItem DolphinDetailsView::viewOptions() const
-{
- QStyleOptionViewItem viewOptions = DolphinTreeView::viewOptions();
- viewOptions.font = m_font;
- viewOptions.fontMetrics = QFontMetrics(m_font);
- viewOptions.showDecorationSelected = true;
- viewOptions.decorationSize = m_decorationSize;
- return viewOptions;
-}
-
-void DolphinDetailsView::contextMenuEvent(QContextMenuEvent* event)
-{
- DolphinTreeView::contextMenuEvent(event);
-
- DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
- m_expandableFoldersAction->setChecked(settings->expandableFolders());
- m_dolphinViewController->triggerContextMenuRequest(event->pos(),
- QList<QAction*>() << m_expandableFoldersAction);
-}
-
-void DolphinDetailsView::mousePressEvent(QMouseEvent* event)
-{
- m_dolphinViewController->requestActivation();
-
- DolphinTreeView::mousePressEvent(event);
-
- const QModelIndex index = indexAt(event->pos());
- if (!index.isValid() || (index.column() != DolphinModel::Name)) {
- // The mouse press is done somewhere outside the filename column
- if (QApplication::mouseButtons() & Qt::MidButton) {
- m_dolphinViewController->replaceUrlByClipboard();
- }
- }
-}
-
-void DolphinDetailsView::startDrag(Qt::DropActions supportedActions)
-{
- DragAndDropHelper::instance().startDrag(this, supportedActions, m_dolphinViewController);
- DolphinTreeView::startDrag(supportedActions);
-}
-
-void DolphinDetailsView::dragEnterEvent(QDragEnterEvent* event)
-{
- event->acceptProposedAction();
- DolphinTreeView::dragEnterEvent(event);
-}
-
-void DolphinDetailsView::dragMoveEvent(QDragMoveEvent* event)
-{
- DolphinTreeView::dragMoveEvent(event);
- event->acceptProposedAction();
-}
-
-void DolphinDetailsView::dropEvent(QDropEvent* event)
-{
- const QModelIndex index = indexAt(event->pos());
- KFileItem item;
- if (index.isValid() && (index.column() == DolphinModel::Name)) {
- item = m_dolphinViewController->itemForIndex(index);
- }
- m_dolphinViewController->indicateDroppedUrls(item, event);
- DolphinTreeView::dropEvent(event);
-}
-
-void DolphinDetailsView::keyPressEvent(QKeyEvent* event)
-{
- DolphinTreeView::keyPressEvent(event);
- m_dolphinViewController->handleKeyPressEvent(event);
-}
-
-void DolphinDetailsView::resizeEvent(QResizeEvent* event)
-{
- DolphinTreeView::resizeEvent(event);
- if (m_autoResize) {
- resizeColumns();
- }
-}
-
-void DolphinDetailsView::wheelEvent(QWheelEvent* event)
-{
- const int step = m_decorationSize.height();
- verticalScrollBar()->setSingleStep(step);
- DolphinTreeView::wheelEvent(event);
-}
-
-void DolphinDetailsView::currentChanged(const QModelIndex& current, const QModelIndex& previous)
-{
- m_extensionsFactory->handleCurrentIndexChange(current, previous);
- DolphinTreeView::currentChanged(current, previous);
-
- // If folders are expanded, the width which is available for editing may have changed
- // because it depends on the level of the current item in the folder hierarchy.
- adjustMaximumSizeForEditing(current);
-}
-
-bool DolphinDetailsView::eventFilter(QObject* watched, QEvent* event)
-{
- if ((watched == viewport()) && (event->type() == QEvent::Leave)) {
- // If the mouse is above an item and moved very fast outside the widget,
- // no viewportEntered() signal might be emitted although the mouse has been moved
- // above the viewport.
- m_dolphinViewController->emitViewportEntered();
- }
-
- return DolphinTreeView::eventFilter(watched, event);
-}
-
-QRect DolphinDetailsView::visualRect(const QModelIndex& index) const
-{
- QRect rect = DolphinTreeView::visualRect(index);
- const KFileItem item = m_dolphinViewController->itemForIndex(index);
- if (!item.isNull()) {
- const int width = DolphinFileItemDelegate::nameColumnWidth(item.text(), viewOptions());
-
- if (width < rect.width()) {
- rect.setWidth(width);
- }
- }
-
- return rect;
-}
-
-bool DolphinDetailsView::acceptsDrop(const QModelIndex& index) const
-{
- if (index.isValid() && (index.column() == DolphinModel::Name)) {
- // Accept drops above directories
- const KFileItem item = m_dolphinViewController->itemForIndex(index);
- return !item.isNull() && item.isDir();
- }
-
- return false;
-}
-
-void DolphinDetailsView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
-{
- removeExpandedIndexes(parent, start, end);
- DolphinTreeView::rowsAboutToBeRemoved(parent, start, end);
-}
-
-void DolphinDetailsView::setSortIndicatorSection(DolphinView::Sorting sorting)
-{
- header()->setSortIndicator(sorting, header()->sortIndicatorOrder());
-}
-
-void DolphinDetailsView::setSortIndicatorOrder(Qt::SortOrder sortOrder)
-{
- header()->setSortIndicator(header()->sortIndicatorSection(), sortOrder);
-}
-
-void DolphinDetailsView::synchronizeSortingState(int column)
-{
- // The sorting has already been changed in QTreeView if this slot is
- // invoked, but Dolphin is not informed about this.
- DolphinView::Sorting sorting = DolphinSortFilterProxyModel::sortingForColumn(column);
- const Qt::SortOrder sortOrder = header()->sortIndicatorOrder();
- m_dolphinViewController->indicateSortingChange(sorting);
- m_dolphinViewController->indicateSortOrderChange(sortOrder);
-}
-
-void DolphinDetailsView::slotEntered(const QModelIndex& index)
-{
- if (index.column() == DolphinModel::Name) {
- m_dolphinViewController->emitItemEntered(index);
- } else {
- m_dolphinViewController->emitViewportEntered();
- }
-}
-
-void DolphinDetailsView::setZoomLevel(int level)
-{
- const int size = ZoomLevelInfo::iconSizeForZoomLevel(level);
- DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
-
- const bool showPreview = m_dolphinViewController->view()->showPreview();
- if (showPreview) {
- settings->setPreviewSize(size);
- } else {
- settings->setIconSize(size);
- }
-
- updateDecorationSize(showPreview);
-}
-
-void DolphinDetailsView::slotShowPreviewChanged()
-{
- const DolphinView* view = m_dolphinViewController->view();
- updateDecorationSize(view->showPreview());
-}
-
-void DolphinDetailsView::configureSettings(const QPoint& pos)
-{
- KMenu popup(this);
- popup.addTitle(i18nc("@title:menu", "Columns"));
-
- // Add checkbox items for each column
- QHeaderView* headerView = header();
- const int columns = model()->columnCount();
- for (int i = 0; i < columns; ++i) {
- const int logicalIndex = headerView->logicalIndex(i);
- const QString text = model()->headerData(logicalIndex, Qt::Horizontal).toString();
- if (!text.isEmpty()) {
- QAction* action = popup.addAction(text);
- action->setCheckable(true);
- action->setChecked(!headerView->isSectionHidden(logicalIndex));
- action->setData(logicalIndex);
- action->setEnabled(logicalIndex != DolphinModel::Name);
- }
- }
- popup.addSeparator();
-
- QAction* activatedAction = popup.exec(header()->mapToGlobal(pos));
- if (activatedAction) {
- const bool show = activatedAction->isChecked();
- const int columnIndex = activatedAction->data().toInt();
-
- KFileItemDelegate::InformationList list = m_dolphinViewController->view()->additionalInfo();
- const KFileItemDelegate::Information info = infoForColumn(columnIndex);
- if (show) {
- Q_ASSERT(!list.contains(info));
- list.append(info);
- } else {
- Q_ASSERT(list.contains(info));
- const int index = list.indexOf(info);
- list.removeAt(index);
- }
-
- m_dolphinViewController->indicateAdditionalInfoChange(list);
- setColumnHidden(columnIndex, !show);
- resizeColumns();
- }
-}
-
-void DolphinDetailsView::updateColumnVisibility()
-{
- QHeaderView* headerView = header();
- disconnect(headerView, SIGNAL(sectionMoved(int, int, int)),
- this, SLOT(saveColumnPositions()));
-
- const DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
- const QList<int> columnPositions = settings->columnPositions();
-
- const KFileItemDelegate::InformationList list = m_dolphinViewController->view()->additionalInfo();
- for (int i = DolphinModel::Name; i < DolphinModel::ExtraColumnCount; ++i) {
- const KFileItemDelegate::Information info = infoForColumn(i);
- const bool hide = !list.contains(info) && (i != DolphinModel::Name);
- if (isColumnHidden(i) != hide) {
- setColumnHidden(i, hide);
- }
-
- // If the list columnPositions has been written by an older Dolphin version,
- // its length might be smaller than DolphinModel::ExtraColumnCount. Therefore,
- // we have to check if item number i exists before accessing it.
- if (i < columnPositions.length()) {
- const int position = columnPositions[i];
-
- // The position might be outside the correct range if the list columnPositions
- // has been written by a newer Dolphin version with more columns.
- if (position < DolphinModel::ExtraColumnCount) {
- const int from = headerView->visualIndex(i);
- headerView->moveSection(from, position);
- }
- }
- }
-
- resizeColumns();
-
- connect(headerView, SIGNAL(sectionMoved(int, int, int)),
- this, SLOT(saveColumnPositions()));
-}
-
-void DolphinDetailsView::resizeColumns()
-{
- // Using the resize mode QHeaderView::ResizeToContents is too slow (it takes
- // around 3 seconds for each (!) resize operation when having > 10000 items).
- // This gets a problem especially when opening large directories, where several
- // resize operations are received for showing the currently available items during
- // loading (the application hangs around 20 seconds when loading > 10000 items).
-
- QHeaderView* headerView = header();
- const int rowCount = model()->rowCount();
- QFontMetrics fontMetrics(viewport()->font());
- const int horizontalGap = fontMetrics.height();
-
- // Define the maximum number of rows, where an exact (but expensive) calculation
- // of the widths is done.
- const int maxRowCount = 200;
-
- // Calculate the required with for each column and store it in columnWidth[]
- int columnWidth[DolphinModel::ExtraColumnCount];
-
- for (int column = 0; column < DolphinModel::ExtraColumnCount; ++column) {
- columnWidth[column] = 0;
- if (!isColumnHidden(column)) {
- // Calculate the required width for the current column and consider only
- // up to maxRowCount columns for performance reasons
- if (rowCount > 0) {
- const int count = qMin(rowCount, maxRowCount);
- for (int row = 0; row < count; ++row) {
- const QModelIndex index = model()->index(row, column);
- QString text;
- if (column == DolphinModel::Size) {
- // This is a workaround as KFileItemDelegate::sizeHint() does not
- // work in a way that is required for calculating the size.
- const QAbstractProxyModel* proxyModel = qobject_cast<const QAbstractProxyModel*>(model());
- const KDirModel* dirModel = qobject_cast<const KDirModel*>(proxyModel->sourceModel());
- const QModelIndex dirIndex = proxyModel->mapToSource(index);
- text = itemSizeString(dirIndex, dirModel->itemForIndex(dirIndex));
- } else {
- text = model()->data(index).toString();
- }
- const int width = fontMetrics.width(text) + horizontalGap;
- if (width > columnWidth[column]) {
- columnWidth[column] = width;
- }
- }
- }
-
- // Assure that the required width is sufficient for the header too
- const int logicalIndex = headerView->logicalIndex(column);
- const QString headline = model()->headerData(logicalIndex, Qt::Horizontal).toString();
- const int headlineWidth = fontMetrics.width(headline) + horizontalGap;
-
- columnWidth[column] = qMax(columnWidth[column], headlineWidth);
- }
- }
-
- // Resize all columns except of the name column
- int requiredWidth = 0;
- for (int column = KDirModel::Size; column < DolphinModel::ExtraColumnCount; ++column) {
- if (!isColumnHidden(column)) {
- requiredWidth += columnWidth[column];
- headerView->resizeSection(column, columnWidth[column]);
- }
- }
-
- // Resize the name column in a way that the whole available width is used
- columnWidth[KDirModel::Name] = viewport()->width() - requiredWidth;
-
- const int minNameWidth = 300;
- if (columnWidth[KDirModel::Name] < minNameWidth) {
- columnWidth[KDirModel::Name] = minNameWidth;
-
- if ((rowCount > 0) && (rowCount < maxRowCount)) {
- // Try to decrease the name column width without clipping any text
- const int nameWidth = sizeHintForColumn(DolphinModel::Name);
- if (nameWidth + requiredWidth <= viewport()->width()) {
- columnWidth[KDirModel::Name] = viewport()->width() - requiredWidth;
- } else if (nameWidth < minNameWidth) {
- columnWidth[KDirModel::Name] = nameWidth;
- }
- }
- }
-
- headerView->resizeSection(KDirModel::Name, columnWidth[KDirModel::Name]);
-}
-
-void DolphinDetailsView::saveColumnPositions()
-{
- QList<int> columnPositions;
- for (int i = DolphinModel::Name; i < DolphinModel::ExtraColumnCount; ++i) {
- columnPositions.append(header()->visualIndex(i));
- }
-
- DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
- settings->setColumnPositions(columnPositions);
-}
-
-void DolphinDetailsView::slotHeaderSectionResized(int logicalIndex, int oldSize, int newSize)
-{
- Q_UNUSED(logicalIndex);
- Q_UNUSED(oldSize);
- Q_UNUSED(newSize);
- // If the user changes the size of the headers, the autoresize feature should be
- // turned off. As there is no dedicated interface to find out whether the header
- // section has been resized by the user or by a resize event, another approach is used.
- // Attention: Take care when changing the if-condition to verify that there is no
- // regression in combination with bug 178630 (see fix in comment #8).
- if ((QApplication::mouseButtons() & Qt::LeftButton) && header()->underMouse()) {
- disableAutoResizing();
- }
-
- adjustMaximumSizeForEditing(currentIndex());
-}
-
-void DolphinDetailsView::slotActivationChanged(bool active)
-{
- setAlternatingRowColors(active);
-}
-
-void DolphinDetailsView::disableAutoResizing()
-{
- m_autoResize = false;
-}
-
-void DolphinDetailsView::requestActivation()
-{
- m_dolphinViewController->requestActivation();
-}
-
-void DolphinDetailsView::slotGlobalSettingsChanged(int category)
-{
- Q_UNUSED(category);
-
- const DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
- Q_ASSERT(settings);
- if (settings->useSystemFont()) {
- m_font = KGlobalSettings::generalFont();
- }
- // Disconnect then reconnect, since the settings have been changed, the connection requirements may have also.
- disconnect(this, SIGNAL(clicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex)));
- disconnect(this, SIGNAL(doubleClicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex)));
- if (KGlobalSettings::singleClick()) {
- connect(this, SIGNAL(clicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex)));
- } else {
- connect(this, SIGNAL(doubleClicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex)));
- }
-}
-
-
-void DolphinDetailsView::setFoldersExpandable(bool expandable)
-{
- if (!expandable) {
- // Collapse all expanded folders, as QTreeView::setItemsExpandable(false)
- // does not do this task
- const int rowCount = model()->rowCount();
- for (int row = 0; row < rowCount; ++row) {
- setExpanded(model()->index(row, 0), false);
- }
- }
- DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
- settings->setExpandableFolders(expandable);
- setRootIsDecorated(expandable);
- setItemsExpandable(expandable);
-
- // The width of the space which is available for editing has changed
- // because of the (dis)appearance of the expanding toggles
- adjustMaximumSizeForEditing(currentIndex());
-}
-
-void DolphinDetailsView::slotExpanded(const QModelIndex& index)
-{
- KFileItem item = m_dolphinViewController->itemForIndex(index);
- if (!item.isNull()) {
- m_expandedUrls.insert(item.url());
- }
-}
-
-void DolphinDetailsView::slotCollapsed(const QModelIndex& index)
-{
- KFileItem item = m_dolphinViewController->itemForIndex(index);
- if (!item.isNull()) {
- m_expandedUrls.remove(item.url());
- }
-}
-
-void DolphinDetailsView::removeExpandedIndexes(const QModelIndex& parent, int start, int end)
-{
- if (m_expandedUrls.isEmpty()) {
- return;
- }
-
- for (int row = start; row <= end; row++) {
- const QModelIndex index = model()->index(row, 0, parent);
- if (isExpanded(index)) {
- slotCollapsed(index);
- removeExpandedIndexes(index, 0, model()->rowCount(index) - 1);
- }
- }
-}
-
-void DolphinDetailsView::updateDecorationSize(bool showPreview)
-{
- DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings();
- const int iconSize = showPreview ? settings->previewSize() : settings->iconSize();
- setIconSize(QSize(iconSize, iconSize));
- m_decorationSize = QSize(iconSize, iconSize);
-
- if (m_extensionsFactory) {
- // The old maximumSize used by KFileItemDelegate is not valid any more after the icon size change.
- // It must be discarded before doItemsLayout() is called (see bug 234600).
- m_extensionsFactory->fileItemDelegate()->setMaximumSize(QSize());
- }
-
- doItemsLayout();
-
- // Calculate the new maximumSize for KFileItemDelegate after the icon size change.
- QModelIndex current = currentIndex();
- if (current.isValid()) {
- adjustMaximumSizeForEditing(current);
- }
-}
-
-KFileItemDelegate::Information DolphinDetailsView::infoForColumn(int columnIndex) const
-{
- return AdditionalInfoAccessor::instance().keyForColumn(columnIndex);
-}
-
-void DolphinDetailsView::adjustMaximumSizeForEditing(const QModelIndex& index)
-{
- // Make sure that the full width of the "Name" column is available for "Rename Inline".
- // Before we do that, we have to check if m_extensionsFactory has been initialised because
- // it is possible that we end up here before the constructor is finished (see bug 257035)
- if (m_extensionsFactory) {
- m_extensionsFactory->fileItemDelegate()->setMaximumSize(QTreeView::visualRect(index).size());
- }
-}
-
-QString DolphinDetailsView::itemSizeString(const QModelIndex& index, const KFileItem& item) const
-{
- // The following code has been copied from KFileItemDelegate::Private::itemSize()
- // Copyright (c) 2006-2007, 2008 Fredrik Höglund <fredrik@kde.org>
- // Ideally this should be handled by KFileItemDelegate::sizeHint().
- if (item.isFile()) {
- return KGlobal::locale()->formatByteSize(item.size());
- }
-
- // Return the number of items in the directory
- const QVariant value = index.data(KDirModel::ChildCountRole);
- const int count = value.type() == QVariant::Int ? value.toInt() : KDirModel::ChildCountUnknown;
-
- if (count == KDirModel::ChildCountUnknown) {
- return QString();
- }
-
- return i18ncp("Items in a folder", "1 item", "%1 items", count);
-}
-
-#include "dolphindetailsview.moc"
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2006-2010 by Peter Penz <peter.penz19@gmail.com> *
- * *
- * 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 DOLPHINDETAILSVIEW_H
-#define DOLPHINDETAILSVIEW_H
-
-#include "dolphintreeview.h"
-#include <QTreeView>
-#include <libdolphin_export.h>
-#include <views/dolphinview.h>
-
-class DolphinViewController;
-class DolphinSortFilterProxyModel;
-class ViewExtensionsFactory;
-
-/**
- * @brief Represents the details view which shows the name, size,
- * date, permissions, owner and group of an item.
- *
- * The width of the columns is automatically adjusted in a way
- * that full available width of the view is used by stretching the width
- * of the name column.
- */
-class LIBDOLPHINPRIVATE_EXPORT DolphinDetailsView : public DolphinTreeView
-{
- Q_OBJECT
-
-public:
- /**
- * @param parent Parent widget.
- * @param dolphinViewController Allows the DolphinDetailsView to control the
- * DolphinView in a limited way.
- * @param viewModeController Controller that is used by the DolphinView
- * to control the DolphinDetailsView. The DolphinDetailsView
- * only has read access to the controller.
- * @param model Directory that is shown.
- */
- explicit DolphinDetailsView(QWidget* parent,
- DolphinViewController* dolphinViewController,
- const ViewModeController* viewModeController,
- DolphinSortFilterProxyModel* model);
- virtual ~DolphinDetailsView();
-
- /**
- * Returns a set containing the URLs of all expanded items.
- */
- QSet<KUrl> expandedUrls() const;
-
-public:
- virtual QRect visualRect(const QModelIndex& index) const;
-
-protected:
- virtual bool event(QEvent* event);
- virtual QStyleOptionViewItem viewOptions() const;
- virtual void contextMenuEvent(QContextMenuEvent* event);
- virtual void mousePressEvent(QMouseEvent* event);
- virtual void startDrag(Qt::DropActions supportedActions);
- virtual void dragEnterEvent(QDragEnterEvent* event);
- virtual void dragMoveEvent(QDragMoveEvent* event);
- virtual void dropEvent(QDropEvent* event);
- virtual void keyPressEvent(QKeyEvent* event);
- virtual void resizeEvent(QResizeEvent* event);
- virtual void wheelEvent(QWheelEvent* event);
- virtual void currentChanged(const QModelIndex& current, const QModelIndex& previous);
- virtual bool eventFilter(QObject* watched, QEvent* event);
- virtual bool acceptsDrop(const QModelIndex& index) const;
-
-protected slots:
- virtual void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
-
-private slots:
- /**
- * Sets the sort indicator section of the header view
- * corresponding to \a sorting.
- */
- void setSortIndicatorSection(DolphinView::Sorting sorting);
-
- /**
- * Sets the sort indicator order of the header view
- * corresponding to \a sortOrder.
- */
- void setSortIndicatorOrder(Qt::SortOrder sortOrder);
-
- /**
- * Synchronizes the sorting state of the Dolphin menu 'View -> Sort'
- * with the current state of the details view.
- * @param column Index of the current sorting column.
- */
- void synchronizeSortingState(int column);
-
- /**
- * Is invoked when the mouse cursor has entered an item. The controller
- * gets informed to emit the itemEntered() signal if the mouse cursor
- * is above the name column. Otherwise the controller gets informed
- * to emit the itemViewportEntered() signal (all other columns should
- * behave as viewport area).
- */
- void slotEntered(const QModelIndex& index);
-
- void setZoomLevel(int level);
-
- void slotShowPreviewChanged();
-
- /**
- * Opens a context menu at the position \a pos and allows to
- * configure the visibility of the header columns and whether
- * expandable folders should be shown.
- */
- void configureSettings(const QPoint& pos);
-
- /**
- * Updates the visibilty state of columns and their order.
- */
- void updateColumnVisibility();
-
- /**
- * Resizes all columns in a way to use the whole available width of the view.
- */
- void resizeColumns();
-
- /**
- * Saves order of the columns as global setting.
- */
- void saveColumnPositions();
-
- /**
- * Disables the automatical resizing of columns, if the user has resized the columns
- * with the mouse.
- */
- void slotHeaderSectionResized(int logicalIndex, int oldSize, int newSize);
-
- /**
- * Changes the alternating row colors setting depending from
- * the activation state \a active.
- */
- void slotActivationChanged(bool active);
-
- /**
- * Disables the automatical resizing of the columns. Per default all columns
- * are resized to use the maximum available width of the view as good as possible.
- */
- void disableAutoResizing();
-
- void requestActivation();
-
- void slotGlobalSettingsChanged(int category);
-
- /**
- * If \a expandable is true, the details view acts as tree view.
- * The current expandable state is remembered in the settings.
- */
- void setFoldersExpandable(bool expandable);
-
- /**
- * These slots update the list of expanded items.
- */
- void slotExpanded(const QModelIndex& index);
- void slotCollapsed(const QModelIndex& index);
-
-private:
- /**
- * Removes the URLs corresponding to the children of \a index in the rows
- * between \a start and \a end inclusive from the set of expanded URLs.
- */
- void removeExpandedIndexes(const QModelIndex& parent, int start, int end);
-
- /**
- * Updates the size of the decoration dependent on the
- * icon size of the DetailsModeSettings. The controller
- * will get informed about possible zoom in/zoom out
- * operations.
- */
- void updateDecorationSize(bool showPreview);
-
- KFileItemDelegate::Information infoForColumn(int columnIndex) const;
-
- /**
- * Sets the maximum size available for editing in the delegate.
- */
- void adjustMaximumSizeForEditing(const QModelIndex& index);
-
- /**
- * Helper method for DolphinDetailsView::resizeColumns(): Returns the
- * string representation of the size-value for the given index.
- */
- QString itemSizeString(const QModelIndex& index, const KFileItem& item) const;
-
-private:
- bool m_autoResize; // if true, the columns are resized automatically to the available width
-
- DolphinViewController* m_dolphinViewController;
- ViewExtensionsFactory* m_extensionsFactory;
- QAction* m_expandableFoldersAction;
-
- // A set containing the URLs of all currently expanded folders.
- // We cannot use a QSet<QModelIndex> because a QModelIndex is not guaranteed to remain valid over time.
- // Also a QSet<QPersistentModelIndex> does not work as expected because it is not guaranteed that
- // subsequent expand/collapse events of the same file item will yield the same QPersistentModelIndex.
- QSet<KUrl> m_expandedUrls;
-
- QFont m_font;
- QSize m_decorationSize;
-
- // For unit tests
- friend class DolphinDetailsViewTest;
-};
-
-#endif
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2009 by Frank Reininghaus (frank78ac@googlemail.com) *
- * *
- * 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 "dolphindetailsviewexpander.h"
-
-#include "dolphindetailsview.h"
-#include "dolphinmodel.h"
-#include "dolphinsortfilterproxymodel.h"
-
-#include <KDirLister>
-#include <KDirModel>
-
-DolphinDetailsViewExpander::DolphinDetailsViewExpander(DolphinDetailsView* parent,
- const QSet<KUrl>& urlsToExpand) :
- QObject(parent),
- m_detailsView(parent),
- m_dirLister(0),
- m_dolphinModel(0),
- m_proxyModel(0)
-{
- Q_ASSERT(parent);
-
- m_proxyModel = qobject_cast<const DolphinSortFilterProxyModel*>(parent->model());
- Q_ASSERT(m_proxyModel);
-
- m_dolphinModel = qobject_cast<const DolphinModel*>(m_proxyModel->sourceModel());
- Q_ASSERT(m_dolphinModel);
-
- m_dirLister = m_dolphinModel->dirLister();
- Q_ASSERT(m_dirLister);
-
- // The URLs must be sorted. E.g. /home/user/ cannot be expanded before /home/
- // because it is not known to the dir model before.
- m_urlsToExpand = urlsToExpand.toList();
- qSort(m_urlsToExpand);
-
- // The dir lister must have completed the folder listing before a subfolder can be expanded.
- connect(m_dirLister, SIGNAL(completed()), this, SLOT(slotDirListerCompleted()));
-}
-
-DolphinDetailsViewExpander::~DolphinDetailsViewExpander()
-{
-}
-
-void DolphinDetailsViewExpander::stop()
-{
- disconnect(m_dirLister, SIGNAL(completed()), this, SLOT(slotDirListerCompleted()));
- deleteLater();
-}
-
-void DolphinDetailsViewExpander::slotDirListerCompleted()
-{
- QModelIndex dirIndex;
-
- while(!m_urlsToExpand.isEmpty() && !dirIndex.isValid()) {
- const KUrl url = m_urlsToExpand.takeFirst();
- dirIndex = m_dolphinModel->indexForUrl(url);
- }
-
- if(dirIndex.isValid()) {
- // A valid model index was found. Note that only one item is expanded in each call of this slot
- // because expanding any item will trigger KDirLister::openUrl(...) via KDirModel::fetchMore(...),
- // and we can only continue when the dir lister is done.
- const QModelIndex proxyIndex = m_proxyModel->mapFromSource(dirIndex);
- m_detailsView->expand(proxyIndex);
- }
- else {
- emit completed();
- stop();
- }
-}
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2009 by Frank Reininghaus (frank78ac@googlemail.com) *
- * *
- * 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 DOLPHINDETAILSVIEWEXPANDER_H
-#define DOLPHINDETAILSVIEWEXPANDER_H
-
-#include <QObject>
-#include <QSet>
-#include <QList>
-
-class DolphinDetailsView;
-class KUrl;
-class KDirLister;
-class DolphinModel;
-class DolphinSortFilterProxyModel;
-
-/**
- * @brief Expands a given set of subfolders in collaboration with the dir lister and the dir model.
- *
- * Note that only one subfolder can be expanded at a time. Each expansion triggers KDirLister::openUrl(...),
- * and further expansions can only be done the next time the dir lister emits its completed() signal.
- */
-class DolphinDetailsViewExpander : public QObject
-{
- Q_OBJECT
-
-public:
- explicit DolphinDetailsViewExpander(DolphinDetailsView* parent,
- const QSet<KUrl>& urlsToExpand);
-
- virtual ~DolphinDetailsViewExpander();
-
- /**
- * Stops the expansion and deletes the object via deleteLater().
- */
- void stop();
-
-private slots:
- /**
- * This slot is invoked every time the dir lister has completed a listing.
- * It expands the first URL from the list m_urlsToExpand that can be found in the dir model.
- * If the list is empty, stop() is called.
- */
- void slotDirListerCompleted();
-
-signals:
- /**
- * Is emitted when the expander has finished expanding URLs in the details view.
- */
- void completed();
-
-private:
- QList<KUrl> m_urlsToExpand;
-
- DolphinDetailsView* m_detailsView;
- const KDirLister* m_dirLister;
- const DolphinModel* m_dolphinModel;
- const DolphinSortFilterProxyModel* m_proxyModel;
-};
-
-#endif
#include <KLocale>
#include <KIO/JobClasses>
-DolphinDirLister::DolphinDirLister() :
- KDirLister()
+DolphinDirLister::DolphinDirLister(QObject* parent) :
+ KDirLister(parent)
{
setAutoErrorHandlingEnabled(false, 0);
}
Q_OBJECT
public:
- DolphinDirLister();
+ DolphinDirLister(QObject* parent = 0);
virtual ~DolphinDirLister();
signals:
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2008 by Peter Penz <peter.penz19@gmail.com> *
- * *
- * 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 "dolphinfileitemdelegate.h"
-
-#include "dolphinmodel.h"
-#include <KColorScheme>
-#include <KFileItem>
-#include <KGlobalSettings>
-#include <KIcon>
-#include <KIconLoader>
-#include <KStringHandler>
-
-#include <QAbstractItemModel>
-#include <QAbstractProxyModel>
-#include <QFontMetrics>
-#include <QPalette>
-#include <QPainter>
-#include <QStyleOptionViewItemV4>
-
-DolphinFileItemDelegate::DolphinFileItemDelegate(QObject* parent) :
- KFileItemDelegate(parent),
- m_hasMinimizedNameColumn(false),
- m_cachedSize(),
- m_cachedEmblems(),
- m_cachedInactiveTextColorDirty(true)
-{
- setJobTransfersVisible(true);
- connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), this, SLOT(handleDisplayPaletteChange()));
-}
-
-DolphinFileItemDelegate::~DolphinFileItemDelegate()
-{
-}
-
-void DolphinFileItemDelegate::paint(QPainter* painter,
- const QStyleOptionViewItem& option,
- const QModelIndex& index) const
-{
- const QAbstractProxyModel* proxyModel = static_cast<const QAbstractProxyModel*>(index.model());
- const DolphinModel* dolphinModel = static_cast<const DolphinModel*>(proxyModel->sourceModel());
- const bool isNameColumn = (index.column() == KDirModel::Name);
-
- QStyleOptionViewItemV4 opt(option);
- if (m_hasMinimizedNameColumn && isNameColumn) {
- adjustOptionWidth(opt, proxyModel, dolphinModel, index);
- }
-
- if (!isNameColumn) {
- // Use the inactive text color for all columns except the name column. This indicates for the user that
- // hovering other columns does not change the actions context.
- QPalette palette = opt.palette;
- if (m_cachedInactiveTextColorDirty) {
- m_cachedInactiveTextColor = KColorScheme(QPalette::Active).foreground(KColorScheme::InactiveText).color();
- m_cachedInactiveTextColorDirty = false;
- }
- palette.setColor(QPalette::Text, m_cachedInactiveTextColor);
- opt.palette = palette;
- }
-
- if (dolphinModel->hasVersionData() && isNameColumn) {
- // The currently shown items are under revision control. Show the current revision
- // state by adding an emblem and changing the text tintColor.
- const QModelIndex dirIndex = proxyModel->mapToSource(index);
- const QModelIndex revisionIndex = dolphinModel->index(dirIndex.row(), DolphinModel::Version, dirIndex.parent());
- const QVariant data = dolphinModel->data(revisionIndex, Qt::DecorationRole);
- const KVersionControlPlugin::VersionState state = static_cast<KVersionControlPlugin::VersionState>(data.toInt());
-
- adjustOptionTextColor(opt, state);
-
- KFileItemDelegate::paint(painter, opt, index);
-
- if (state != KVersionControlPlugin::UnversionedVersion) {
- const QRect rect = iconRect(option, index);
- const QPixmap emblem = emblemForState(state, rect.size());
- painter->drawPixmap(rect.x(), rect.y() + rect.height() - emblem.height(), emblem);
- }
- } else {
- KFileItemDelegate::paint(painter, opt, index);
- }
-}
-
-int DolphinFileItemDelegate::nameColumnWidth(const QString& name, const QStyleOptionViewItem& option)
-{
- QFontMetrics fontMetrics(option.font);
- int width = option.decorationSize.width() + fontMetrics.width(KStringHandler::preProcessWrap(name)) + 16;
-
- const int defaultWidth = option.rect.width();
- if ((defaultWidth > 0) && (defaultWidth < width)) {
- width = defaultWidth;
- }
- return width;
-}
-
-void DolphinFileItemDelegate::handleDisplayPaletteChange()
-{
- m_cachedInactiveTextColorDirty = true;
-}
-
-void DolphinFileItemDelegate::adjustOptionWidth(QStyleOptionViewItemV4& option,
- const QAbstractProxyModel* proxyModel,
- const DolphinModel* dolphinModel,
- const QModelIndex& index)
-{
- const QModelIndex dirIndex = proxyModel->mapToSource(index);
- const KFileItem item = dolphinModel->itemForIndex(dirIndex);
- if (!item.isNull()) {
- // symbolic links are displayed in an italic font
- if (item.isLink()) {
- option.font.setItalic(true);
- }
-
- const int width = nameColumnWidth(item.text(), option);
- option.rect.setWidth(width);
- }
-}
-
-void DolphinFileItemDelegate::adjustOptionTextColor(QStyleOptionViewItemV4& option,
- KVersionControlPlugin::VersionState state)
-{
- QColor tintColor;
-
- // Using hardcoded colors is generally a bad idea. In this case the colors just act
- // as tint colors and are mixed with the current set text color. The tint colors
- // have been optimized for the base colors of the corresponding Oxygen emblems.
- switch (state) {
- case KVersionControlPlugin::UpdateRequiredVersion: tintColor = Qt::yellow; break;
- case KVersionControlPlugin::LocallyModifiedUnstagedVersion: tintColor = Qt::darkGreen; break;
- case KVersionControlPlugin::LocallyModifiedVersion: tintColor = Qt::green; break;
- case KVersionControlPlugin::AddedVersion: tintColor = Qt::green; break;
- case KVersionControlPlugin::RemovedVersion: tintColor = Qt::darkRed; break;
- case KVersionControlPlugin::ConflictingVersion: tintColor = Qt::red; break;
- case KVersionControlPlugin::UnversionedVersion:
- case KVersionControlPlugin::NormalVersion:
- default:
- // use the default text color
- return;
- }
-
- QPalette palette = option.palette;
- const QColor textColor = palette.color(QPalette::Text);
- tintColor = QColor((tintColor.red() + textColor.red()) / 2,
- (tintColor.green() + textColor.green()) / 2,
- (tintColor.blue() + textColor.blue()) / 2,
- (tintColor.alpha() + textColor.alpha()) / 2);
- palette.setColor(QPalette::Text, tintColor);
- option.palette = palette;
-}
-
-QPixmap DolphinFileItemDelegate::emblemForState(KVersionControlPlugin::VersionState state, const QSize& size) const
-{
- Q_ASSERT(state <= KVersionControlPlugin::LocallyModifiedUnstagedVersion);
- if (m_cachedSize != size) {
- m_cachedSize = size;
-
- const int iconHeight = size.height();
- int emblemHeight = KIconLoader::SizeSmall;
- if (iconHeight >= KIconLoader::SizeEnormous) {
- emblemHeight = KIconLoader::SizeMedium;
- } else if (iconHeight >= KIconLoader::SizeLarge) {
- emblemHeight = KIconLoader::SizeSmallMedium;
- } else if (iconHeight >= KIconLoader::SizeMedium) {
- emblemHeight = KIconLoader::SizeSmall;
- } else {
- emblemHeight = KIconLoader::SizeSmall / 2;
- }
-
- const QSize emblemSize(emblemHeight, emblemHeight);
- for (int i = KVersionControlPlugin::NormalVersion; i <= KVersionControlPlugin::LocallyModifiedUnstagedVersion; ++i) {
- QString iconName;
- switch (i) {
- case KVersionControlPlugin::NormalVersion:
- iconName = "vcs-normal";
- break;
- case KVersionControlPlugin::UpdateRequiredVersion:
- iconName = "vcs-update-required";
- break;
- case KVersionControlPlugin::LocallyModifiedVersion:
- iconName = "vcs-locally-modified";
- break;
- case KVersionControlPlugin::LocallyModifiedUnstagedVersion:
- iconName = "vcs-locally-modified-unstaged";
- break;
- case KVersionControlPlugin::AddedVersion:
- iconName = "vcs-added";
- break;
- case KVersionControlPlugin::RemovedVersion:
- iconName = "vcs-removed";
- break;
- case KVersionControlPlugin::ConflictingVersion:
- iconName = "vcs-conflicting";
- break;
- case KVersionControlPlugin::UnversionedVersion:
- break;
- default:
- Q_ASSERT(false);
- break;
- }
-
- m_cachedEmblems[i] = KIcon(iconName).pixmap(emblemSize);
- }
- }
- return m_cachedEmblems[state];
-}
-
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2008 by Peter Penz <peter.penz19@gmail.com> *
- * *
- * 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 DOLPHINFILEITEMDELEGATE_H
-#define DOLPHINFILEITEMDELEGATE_H
-
-#include <KFileItemDelegate>
-#include <views/dolphinmodel.h>
-
-class QAbstractProxyModel;
-
-/**
- * Extends KFileItemDelegate by the ability to show the hover effect
- * and the selection in a minimized way for the name column of
- * the details view.
- *
- * Note that this is a workaround, as Qt does not support having custom
- * shapes within the visual rect of an item view. The visual part of
- * workaround is handled inside DolphinFileItemDelegate, the behavior
- * changes are handled in DolphinTreeView.
- */
-class DolphinFileItemDelegate : public KFileItemDelegate
-{
- Q_OBJECT
-public:
- explicit DolphinFileItemDelegate(QObject* parent = 0);
- virtual ~DolphinFileItemDelegate();
-
- /**
- * If \a minimized is true, the hover effect and the selection are
- * only drawn above the icon and text of an item. Per default
- * \a minimized is false, which means that the whole visual rect is
- * used like in KFileItemDelegate.
- */
- void setMinimizedNameColumn(bool minimized);
- bool hasMinimizedNameColumn() const;
-
- virtual void paint(QPainter* painter,
- const QStyleOptionViewItem& option,
- const QModelIndex& index) const;
-
- /**
- * Returns the minimized width of the name column for the name \a name. This method
- * is also used in DolphinDetailsView to handle the selection of items correctly.
- */
- static int nameColumnWidth(const QString& name, const QStyleOptionViewItem& option);
-
-private slots:
- void handleDisplayPaletteChange();
-
-private:
- static void adjustOptionWidth(QStyleOptionViewItemV4& option,
- const QAbstractProxyModel* proxyModel,
- const DolphinModel* dolphinModel,
- const QModelIndex& index);
-
- static void adjustOptionTextColor(QStyleOptionViewItemV4& option,
- KVersionControlPlugin::VersionState state);
-
- QPixmap emblemForState(KVersionControlPlugin::VersionState state, const QSize& size) const;
-
-private:
- bool m_hasMinimizedNameColumn;
- mutable QSize m_cachedSize;
- mutable QPixmap m_cachedEmblems[KVersionControlPlugin::LocallyModifiedUnstagedVersion + 1];
- mutable QColor m_cachedInactiveTextColor;
- mutable bool m_cachedInactiveTextColorDirty;
-};
-
-inline void DolphinFileItemDelegate::setMinimizedNameColumn(bool minimized)
-{
- m_hasMinimizedNameColumn = minimized;
-}
-
-inline bool DolphinFileItemDelegate::hasMinimizedNameColumn() const
-{
- return m_hasMinimizedNameColumn;
-}
-
-#endif
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2006-2009 by Peter Penz <peter.penz19@gmail.com> *
- * *
- * 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 "dolphiniconsview.h"
-
-#include "dolphincategorydrawer.h"
-#include "dolphinviewcontroller.h"
-#include "settings/dolphinsettings.h"
-#include "dolphinsortfilterproxymodel.h"
-#include "dolphin_iconsmodesettings.h"
-#include "dolphin_generalsettings.h"
-#include "draganddrophelper.h"
-#include "selectionmanager.h"
-#include "viewextensionsfactory.h"
-#include "viewmodecontroller.h"
-#include "zoomlevelinfo.h"
-
-#include <KCategorizedSortFilterProxyModel>
-#include <KDialog>
-#include <KFileItemDelegate>
-
-#include <QAbstractProxyModel>
-#include <QApplication>
-#include <QScrollBar>
-
-DolphinIconsView::DolphinIconsView(QWidget* parent,
- DolphinViewController* dolphinViewController,
- const ViewModeController* viewModeController,
- DolphinSortFilterProxyModel* proxyModel) :
- KCategorizedView(parent),
- m_dolphinViewController(dolphinViewController),
- m_categoryDrawer(new DolphinCategoryDrawer(this)),
- m_extensionsFactory(0),
- m_font(),
- m_decorationSize(),
- m_decorationPosition(QStyleOptionViewItem::Top),
- m_displayAlignment(Qt::AlignHCenter),
- m_itemSize(),
- m_dropRect()
-{
- Q_ASSERT(dolphinViewController);
- Q_ASSERT(viewModeController);
-
- setModel(proxyModel);
- setLayoutDirection(Qt::LeftToRight);
- setViewMode(QListView::IconMode);
- setResizeMode(QListView::Adjust);
- setMovement(QListView::Static);
- setDragEnabled(true);
- setEditTriggers(QAbstractItemView::NoEditTriggers);
- viewport()->setAcceptDrops(true);
-
- setMouseTracking(true);
-
- connect(this, SIGNAL(clicked(const QModelIndex&)),
- dolphinViewController, SLOT(requestTab(const QModelIndex&)));
- if (KGlobalSettings::singleClick()) {
- connect(this, SIGNAL(clicked(const QModelIndex&)),
- dolphinViewController, SLOT(triggerItem(const QModelIndex&)));
- } else {
- connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
- dolphinViewController, SLOT(triggerItem(const QModelIndex&)));
- }
-
- connect(this, SIGNAL(entered(const QModelIndex&)),
- dolphinViewController, SLOT(emitItemEntered(const QModelIndex&)));
- connect(this, SIGNAL(viewportEntered()),
- dolphinViewController, SLOT(emitViewportEntered()));
- connect(viewModeController, SIGNAL(zoomLevelChanged(int)),
- this, SLOT(setZoomLevel(int)));
-
- const DolphinView* view = dolphinViewController->view();
- connect(view, SIGNAL(showPreviewChanged()),
- this, SLOT(slotShowPreviewChanged()));
- connect(view, SIGNAL(additionalInfoChanged()),
- this, SLOT(slotAdditionalInfoChanged()));
-
- // apply the icons mode settings to the widget
- const IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings();
- Q_ASSERT(settings);
-
- if (settings->useSystemFont()) {
- m_font = KGlobalSettings::generalFont();
- } else {
- m_font = QFont(settings->fontFamily(),
- qRound(settings->fontSize()),
- settings->fontWeight(),
- settings->italicFont());
- m_font.setPointSizeF(settings->fontSize());
- }
-
- setWordWrap(settings->numberOfTextlines() > 1);
-
- if (settings->arrangement() == QListView::TopToBottom) {
- setFlow(QListView::LeftToRight);
- m_decorationPosition = QStyleOptionViewItem::Top;
- m_displayAlignment = Qt::AlignHCenter;
- } else {
- setFlow(QListView::TopToBottom);
- m_decorationPosition = QStyleOptionViewItem::Left;
- m_displayAlignment = Qt::AlignLeft | Qt::AlignVCenter;
- }
-
- connect(m_categoryDrawer, SIGNAL(actionRequested(int,QModelIndex)), this, SLOT(categoryDrawerActionRequested(int,QModelIndex)));
- setCategoryDrawer(m_categoryDrawer);
-
- connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)),
- this, SLOT(slotGlobalSettingsChanged(int)));
-
- updateGridSize(view->showPreview(), 0);
- m_extensionsFactory = new ViewExtensionsFactory(this, dolphinViewController, viewModeController);
-}
-
-DolphinIconsView::~DolphinIconsView()
-{
-}
-
-void DolphinIconsView::dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
-{
- KCategorizedView::dataChanged(topLeft, bottomRight);
-
- KCategorizedSortFilterProxyModel* proxyModel = dynamic_cast<KCategorizedSortFilterProxyModel*>(model());
- if (!proxyModel->isCategorizedModel()) {
- // bypass a QListView issue that items are not layout correctly if the decoration size of
- // an index changes
- scheduleDelayedItemsLayout();
- }
-}
-
-QStyleOptionViewItem DolphinIconsView::viewOptions() const
-{
- QStyleOptionViewItem viewOptions = KCategorizedView::viewOptions();
- viewOptions.font = m_font;
- viewOptions.fontMetrics = QFontMetrics(m_font);
- viewOptions.decorationPosition = m_decorationPosition;
- viewOptions.decorationSize = m_decorationSize;
- viewOptions.displayAlignment = m_displayAlignment;
- viewOptions.showDecorationSelected = true;
- return viewOptions;
-}
-
-void DolphinIconsView::contextMenuEvent(QContextMenuEvent* event)
-{
- KCategorizedView::contextMenuEvent(event);
- m_dolphinViewController->triggerContextMenuRequest(event->pos());
-}
-
-void DolphinIconsView::mousePressEvent(QMouseEvent* event)
-{
- m_dolphinViewController->requestActivation();
- const QModelIndex index = indexAt(event->pos());
- if (index.isValid() && (event->button() == Qt::LeftButton)) {
- // TODO: It should not be necessary to manually set the dragging state, but I could
- // not reproduce this issue with a Qt-only example yet to find the root cause.
- // Issue description: start Dolphin, split the view and drag an item from the
- // inactive view to the active view by a very fast mouse movement. Result:
- // the item gets selected instead of being dragged...
- setState(QAbstractItemView::DraggingState);
- }
-
- if (!index.isValid() && (QApplication::mouseButtons() & Qt::MidButton)) {
- m_dolphinViewController->replaceUrlByClipboard();
- }
-
- KCategorizedView::mousePressEvent(event);
-}
-
-void DolphinIconsView::startDrag(Qt::DropActions supportedActions)
-{
- DragAndDropHelper::instance().startDrag(this, supportedActions, m_dolphinViewController);
-}
-
-void DolphinIconsView::dragEnterEvent(QDragEnterEvent* event)
-{
- event->acceptProposedAction();
-}
-
-void DolphinIconsView::dragLeaveEvent(QDragLeaveEvent* event)
-{
- KCategorizedView::dragLeaveEvent(event);
- setDirtyRegion(m_dropRect);
-}
-
-void DolphinIconsView::dragMoveEvent(QDragMoveEvent* event)
-{
- KCategorizedView::dragMoveEvent(event);
-
- // TODO: remove this code when the issue #160611 is solved in Qt 4.4
- const QModelIndex index = indexAt(event->pos());
- setDirtyRegion(m_dropRect);
-
- m_dropRect.setSize(QSize()); // set as invalid
- if (index.isValid()) {
- const KFileItem item = m_dolphinViewController->itemForIndex(index);
- if (!item.isNull() && item.isDir()) {
- m_dropRect = visualRect(index);
- } else {
- m_dropRect.setSize(QSize()); // set as invalid
- }
- }
- event->acceptProposedAction();
-
- setDirtyRegion(m_dropRect);
-}
-
-void DolphinIconsView::dropEvent(QDropEvent* event)
-{
- const QModelIndex index = indexAt(event->pos());
- const KFileItem item = m_dolphinViewController->itemForIndex(index);
- m_dolphinViewController->indicateDroppedUrls(item, event);
- // don't call KCategorizedView::dropEvent(event), as it moves
- // the items which is not wanted
-}
-
-QModelIndex DolphinIconsView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
-{
- const QModelIndex oldCurrent = currentIndex();
-
- QModelIndex newCurrent = KCategorizedView::moveCursor(cursorAction, modifiers);
- if (newCurrent != oldCurrent) {
- return newCurrent;
- }
-
- // The cursor has not been moved by the base implementation. Provide a
- // wrap behavior, so that the cursor will go to the next item when reaching
- // the border.
- const IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings();
- if (settings->arrangement() == QListView::LeftToRight) {
- switch (cursorAction) {
- case MoveUp:
- if (newCurrent.row() == 0) {
- return newCurrent;
- }
- newCurrent = KCategorizedView::moveCursor(MoveLeft, modifiers);
- selectionModel()->setCurrentIndex(newCurrent, QItemSelectionModel::NoUpdate);
- newCurrent = KCategorizedView::moveCursor(MovePageDown, modifiers);
- break;
-
- case MoveDown:
- if (newCurrent.row() == (model()->rowCount() - 1)) {
- return newCurrent;
- }
- newCurrent = KCategorizedView::moveCursor(MovePageUp, modifiers);
- selectionModel()->setCurrentIndex(newCurrent, QItemSelectionModel::NoUpdate);
- newCurrent = KCategorizedView::moveCursor(MoveRight, modifiers);
- break;
-
- default:
- break;
- }
- } else {
- QModelIndex current = oldCurrent;
- switch (cursorAction) {
- case MoveLeft:
- if (newCurrent.row() == 0) {
- return newCurrent;
- }
- newCurrent = KCategorizedView::moveCursor(MoveUp, modifiers);
- do {
- selectionModel()->setCurrentIndex(newCurrent, QItemSelectionModel::NoUpdate);
- current = newCurrent;
- newCurrent = KCategorizedView::moveCursor(MoveRight, modifiers);
- } while (newCurrent != current);
- break;
-
- case MoveRight:
- if (newCurrent.row() == (model()->rowCount() - 1)) {
- return newCurrent;
- }
- do {
- selectionModel()->setCurrentIndex(newCurrent, QItemSelectionModel::NoUpdate);
- current = newCurrent;
- newCurrent = KCategorizedView::moveCursor(MoveLeft, modifiers);
- } while (newCurrent != current);
- newCurrent = KCategorizedView::moveCursor(MoveDown, modifiers);
- break;
-
- default:
- break;
- }
- }
-
- // Revert all changes of the current item to make sure that item selection works correctly
- selectionModel()->setCurrentIndex(oldCurrent, QItemSelectionModel::NoUpdate);
- return newCurrent;
-}
-
-void DolphinIconsView::keyPressEvent(QKeyEvent* event)
-{
- KCategorizedView::keyPressEvent(event);
- m_dolphinViewController->handleKeyPressEvent(event);
-}
-
-void DolphinIconsView::wheelEvent(QWheelEvent* event)
-{
- horizontalScrollBar()->setSingleStep(m_itemSize.width() / 5);
- verticalScrollBar()->setSingleStep(m_itemSize.height() / 5);
-
- KCategorizedView::wheelEvent(event);
- // if the icons are aligned left to right, the vertical wheel event should
- // be applied to the horizontal scrollbar
- const IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings();
- const bool scrollHorizontal = (event->orientation() == Qt::Vertical) &&
- (settings->arrangement() == QListView::LeftToRight);
- if (scrollHorizontal) {
- QWheelEvent horizEvent(event->pos(),
- event->delta(),
- event->buttons(),
- event->modifiers(),
- Qt::Horizontal);
- QApplication::sendEvent(horizontalScrollBar(), &horizEvent);
- }
-}
-
-void DolphinIconsView::showEvent(QShowEvent* event)
-{
- KFileItemDelegate* delegate = dynamic_cast<KFileItemDelegate*>(itemDelegate());
- delegate->setMaximumSize(m_itemSize);
-
- KCategorizedView::showEvent(event);
-}
-
-void DolphinIconsView::leaveEvent(QEvent* event)
-{
- KCategorizedView::leaveEvent(event);
- // if the mouse is above an item and moved very fast outside the widget,
- // no viewportEntered() signal might be emitted although the mouse has been moved
- // above the viewport
- m_dolphinViewController->emitViewportEntered();
-}
-
-void DolphinIconsView::currentChanged(const QModelIndex& current, const QModelIndex& previous)
-{
- KCategorizedView::currentChanged(current, previous);
- m_extensionsFactory->handleCurrentIndexChange(current, previous);
-}
-
-void DolphinIconsView::resizeEvent(QResizeEvent* event)
-{
- KCategorizedView::resizeEvent(event);
- const DolphinView* view = m_dolphinViewController->view();
- updateGridSize(view->showPreview(), view->additionalInfo().count());
-}
-
-void DolphinIconsView::slotShowPreviewChanged()
-{
- const DolphinView* view = m_dolphinViewController->view();
- updateGridSize(view->showPreview(), additionalInfoCount());
-}
-
-void DolphinIconsView::slotAdditionalInfoChanged()
-{
- const DolphinView* view = m_dolphinViewController->view();
- const bool showPreview = view->showPreview();
- updateGridSize(showPreview, view->additionalInfo().count());
-}
-
-void DolphinIconsView::setZoomLevel(int level)
-{
- IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings();
-
- const int oldIconSize = settings->iconSize();
- int newIconSize = oldIconSize;
-
- const bool showPreview = m_dolphinViewController->view()->showPreview();
- if (showPreview) {
- const int previewSize = ZoomLevelInfo::iconSizeForZoomLevel(level);
- settings->setPreviewSize(previewSize);
- } else {
- newIconSize = ZoomLevelInfo::iconSizeForZoomLevel(level);
- settings->setIconSize(newIconSize);
- }
-
- // increase also the grid size
- const int diff = newIconSize - oldIconSize;
- settings->setItemWidth(settings->itemWidth() + diff);
- settings->setItemHeight(settings->itemHeight() + diff);
-
- updateGridSize(showPreview, additionalInfoCount());
-}
-
-void DolphinIconsView::requestActivation()
-{
- m_dolphinViewController->requestActivation();
-}
-
-void DolphinIconsView::slotGlobalSettingsChanged(int category)
-{
- Q_UNUSED(category);
-
- const IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings();
- Q_ASSERT(settings);
- if (settings->useSystemFont()) {
- m_font = KGlobalSettings::generalFont();
- }
-
- disconnect(this, SIGNAL(clicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex)));
- disconnect(this, SIGNAL(doubleClicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex)));
- if (KGlobalSettings::singleClick()) {
- connect(this, SIGNAL(clicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex)));
- } else {
- connect(this, SIGNAL(doubleClicked(QModelIndex)), m_dolphinViewController, SLOT(triggerItem(QModelIndex)));
- }
-}
-
-void DolphinIconsView::categoryDrawerActionRequested(int action, const QModelIndex &index)
-{
- const QSortFilterProxyModel *model = dynamic_cast<const QSortFilterProxyModel*>(index.model());
- const QModelIndex topLeft = model->index(index.row(), modelColumn());
- QModelIndex bottomRight = topLeft;
- const QString category = model->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString();
- QModelIndex current = topLeft;
- while (true) {
- current = model->index(current.row() + 1, modelColumn());
- const QString curCategory = model->data(model->index(current.row(), index.column()), KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString();
- if (!current.isValid() || category != curCategory) {
- break;
- }
- bottomRight = current;
- }
- switch (action) {
- case DolphinCategoryDrawer::SelectAll:
- selectionModel()->select(QItemSelection(topLeft, bottomRight), QItemSelectionModel::Select);
- break;
- case DolphinCategoryDrawer::UnselectAll:
- selectionModel()->select(QItemSelection(topLeft, bottomRight), QItemSelectionModel::Deselect);
- break;
- default:
- break;
- }
-}
-
-void DolphinIconsView::updateGridSize(bool showPreview, int additionalInfoCount)
-{
- const IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings();
- Q_ASSERT(settings);
-
- int itemWidth = settings->itemWidth();
- int itemHeight = settings->itemHeight();
- int size = settings->iconSize();
-
- if (showPreview) {
- const int previewSize = settings->previewSize();
- const int diff = previewSize - size;
- itemWidth += diff;
- itemHeight += diff;
-
- size = previewSize;
- }
-
- Q_ASSERT(additionalInfoCount >= 0);
- itemHeight += additionalInfoCount * QFontMetrics(m_font).height();
-
- // Optimize the item size of the grid in a way to prevent large gaps on the
- // right border (= row arrangement) or the bottom border (= column arrangement).
- // There is no public API in QListView to find out the used width of the viewport
- // for the layout. The following calculation of 'contentWidth'/'contentHeight'
- // is based on QListViewPrivate::prepareItemsLayout() (Copyright (C) 2009 Nokia Corporation).
- int frameAroundContents = 0;
- if (style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents)) {
- frameAroundContents = style()->pixelMetric(QStyle::PM_DefaultFrameWidth) * 2;
- }
- const int spacing = settings->gridSpacing();
- if (settings->arrangement() == QListView::TopToBottom) {
- const int contentWidth = viewport()->width() - 1
- - frameAroundContents
- - style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, horizontalScrollBar());
- const int gridWidth = itemWidth + spacing * 2;
- const int horizItemCount = contentWidth / gridWidth;
- if (horizItemCount > 0) {
- itemWidth += (contentWidth - horizItemCount * gridWidth) / horizItemCount;
- }
-
- // The decoration width indirectly defines the maximum
- // width for the text wrapping. To use the maximum item width
- // for text wrapping, it is used as decoration width.
- m_decorationSize = QSize(itemWidth, size);
- setIconSize(QSize(itemWidth, size));
- } else {
- const int contentHeight = viewport()->height() - 1
- - frameAroundContents
- - style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, verticalScrollBar());
- const int gridHeight = itemHeight + spacing;
- const int vertItemCount = contentHeight / gridHeight;
- if (vertItemCount > 0) {
- itemHeight += (contentHeight - vertItemCount * gridHeight) / vertItemCount;
- }
-
- m_decorationSize = QSize(size, size);
- setIconSize(QSize(size, size));
- }
-
- m_itemSize = QSize(itemWidth, itemHeight);
- setGridSizeOwn(QSize(itemWidth + spacing * 2, itemHeight + spacing));
-
- KFileItemDelegate* delegate = dynamic_cast<KFileItemDelegate*>(itemDelegate());
- if (delegate) {
- delegate->setMaximumSize(m_itemSize);
- }
-}
-
-int DolphinIconsView::additionalInfoCount() const
-{
- const DolphinView* view = m_dolphinViewController->view();
- return view->additionalInfo().count();
-}
-
-#include "dolphiniconsview.moc"
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2006-2009 by Peter Penz <peter.penz19@gmail.com> *
- * *
- * 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 DOLPHINICONSVIEW_H
-#define DOLPHINICONSVIEW_H
-
-#include <KCategorizedView>
-
-#include <KFileItem>
-#include <KFileItemDelegate>
-
-#include <QFont>
-#include <QSize>
-#include <QStyleOption>
-
-#include <libdolphin_export.h>
-
-class DolphinViewController;
-class DolphinCategoryDrawer;
-class DolphinSortFilterProxyModel;
-class ViewExtensionsFactory;
-class ViewModeController;
-
-/**
- * @brief Represents the view, where each item is shown as an icon.
- *
- * It is also possible that instead of the icon a preview of the item
- * content is shown.
- */
-class LIBDOLPHINPRIVATE_EXPORT DolphinIconsView : public KCategorizedView
-{
- Q_OBJECT
-
-public:
- /**
- * @param parent Parent widget.
- * @param dolphinViewController Allows the DolphinIconsView to control the
- * DolphinView in a limited way.
- * @param viewModeController Controller that is used by the DolphinView
- * to control the DolphinIconsView. The DolphinIconsView
- * only has read access to the controller.
- * @param model Directory that is shown.
- */
- explicit DolphinIconsView(QWidget* parent,
- DolphinViewController* dolphinViewController,
- const ViewModeController* viewModeController,
- DolphinSortFilterProxyModel* proxyModel);
- virtual ~DolphinIconsView();
-
-protected slots:
- virtual void dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight);
-
-protected:
- virtual QStyleOptionViewItem viewOptions() const;
- virtual void contextMenuEvent(QContextMenuEvent* event);
- virtual void mousePressEvent(QMouseEvent* event);
- virtual void startDrag(Qt::DropActions supportedActions);
- virtual void dragEnterEvent(QDragEnterEvent* event);
- virtual void dragLeaveEvent(QDragLeaveEvent* event);
- virtual void dragMoveEvent(QDragMoveEvent* event);
- virtual void dropEvent(QDropEvent* event);
- virtual QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers);
- virtual void keyPressEvent(QKeyEvent* event);
- virtual void wheelEvent(QWheelEvent* event);
- virtual void showEvent(QShowEvent* event);
- virtual void leaveEvent(QEvent* event);
- virtual void currentChanged(const QModelIndex& current, const QModelIndex& previous);
- virtual void resizeEvent(QResizeEvent* event);
-
-private slots:
- void slotShowPreviewChanged();
- void slotAdditionalInfoChanged();
- void setZoomLevel(int level);
- void requestActivation();
- void slotGlobalSettingsChanged(int category);
- void categoryDrawerActionRequested(int action, const QModelIndex &index);
-
-private:
- /**
- * Updates the size of the grid depending on the state
- * of \a showPreview and \a additionalInfoCount.
- */
- void updateGridSize(bool showPreview, int additionalInfoCount);
-
- /**
- * Returns the number of additional information lines that should
- * be shown below the item name.
- */
- int additionalInfoCount() const;
-
-private:
- DolphinViewController* m_dolphinViewController;
- DolphinCategoryDrawer* m_categoryDrawer;
- ViewExtensionsFactory* m_extensionsFactory;
-
- QFont m_font;
- QSize m_decorationSize;
- QStyleOptionViewItem::Position m_decorationPosition;
- Qt::Alignment m_displayAlignment;
-
- QSize m_itemSize;
- QRect m_dropRect;
-};
-
-#endif
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 "dolphinitemlistcontainer.h"
+
+#include "dolphin_iconsmodesettings.h"
+#include "dolphin_detailsmodesettings.h"
+#include "dolphin_compactmodesettings.h"
+
+#include <kitemviews/kitemliststyleoption.h>
+#include <kitemviews/kfileitemlistview.h>
+#include <kitemviews/kfileitemmodel.h>
+#include <kitemviews/kitemlistcontroller.h>
+#include <kitemviews/kitemliststyleoption.h>
+
+#include <KDirLister>
+#include <KGlobalSettings>
+
+#include <views/viewmodecontroller.h>
+
+#include "zoomlevelinfo.h"
+
+
+DolphinItemListContainer::DolphinItemListContainer(KDirLister* dirLister,
+ QWidget* parent) :
+ KItemListContainer(parent),
+ m_zoomLevel(0),
+ m_fileItemListView(0)
+{
+ controller()->setModel(new KFileItemModel(dirLister, this));
+
+ m_fileItemListView = new KFileItemListView();
+ controller()->setView(m_fileItemListView);
+
+ KItemListStyleOption option;
+
+ // TODO:
+ option.font = parent->font();
+ option.fontMetrics = QFontMetrics(parent->font());
+
+ updateGridSize();
+/*
+ connect(this, SIGNAL(clicked(const QModelIndex&)),
+ dolphinViewController, SLOT(requestTab(const QModelIndex&)));*/
+/*
+ connect(this, SIGNAL(entered(const QModelIndex&)),
+ dolphinViewController, SLOT(emitItemEntered(const QModelIndex&)));
+ connect(this, SIGNAL(viewportEntered()),
+ dolphinViewController, SLOT(emitViewportEntered()));*/
+
+ // apply the icons mode settings to the widget
+ //const IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings();
+ //Q_ASSERT(settings);
+
+ /*if (settings->useSystemFont()) {
+ m_font = KGlobalSettings::generalFont();
+ } else {
+ m_font = QFont(settings->fontFamily(),
+ qRound(settings->fontSize()),
+ settings->fontWeight(),
+ settings->italicFont());
+ m_font.setPointSizeF(settings->fontSize());
+ }
+
+ setWordWrap(settings->numberOfTextlines() > 1);
+
+ if (settings->arrangement() == QListView::TopToBottom) {
+ setFlow(QListView::LeftToRight);
+ m_decorationPosition = QStyleOptionViewItem::Top;
+ m_displayAlignment = Qt::AlignHCenter;
+ } else {
+ setFlow(QListView::TopToBottom);
+ m_decorationPosition = QStyleOptionViewItem::Left;
+ m_displayAlignment = Qt::AlignLeft | Qt::AlignVCenter;
+ }
+
+ connect(m_categoryDrawer, SIGNAL(actionRequested(int,QModelIndex)), this, SLOT(categoryDrawerActionRequested(int,QModelIndex)));
+ setCategoryDrawer(m_categoryDrawer);
+
+ connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)),
+ this, SLOT(slotGlobalSettingsChanged(int)));*/
+
+ //updateGridSize(dolphinView->showPreview(), 0);
+ /*m_extensionsFactory = new ViewExtensionsFactory(this, dolphinViewController, viewModeController);*/
+}
+
+DolphinItemListContainer::~DolphinItemListContainer()
+{
+ IconsModeSettings::self()->writeConfig();
+ CompactModeSettings::self()->writeConfig();
+ DetailsModeSettings::self()->writeConfig();
+
+ KItemListView* view = controller()->view();
+ controller()->setView(0);
+ delete view;
+}
+
+void DolphinItemListContainer::setPreviewsShown(bool show)
+{
+ beginTransaction();
+ m_fileItemListView->setPreviewsShown(show);
+ updateGridSize();
+ endTransaction();
+}
+
+bool DolphinItemListContainer::previewsShown() const
+{
+ return m_fileItemListView->previewsShown();
+}
+
+void DolphinItemListContainer::setVisibleRoles(const QHash<QByteArray, int>& roles)
+{
+ m_fileItemListView->setVisibleRoles(roles);
+ updateGridSize();
+}
+
+QHash<QByteArray, int> DolphinItemListContainer::visibleRoles() const
+{
+ return m_fileItemListView->visibleRoles();
+}
+
+void DolphinItemListContainer::setZoomLevel(int level)
+{
+ if (level < ZoomLevelInfo::minimumLevel()) {
+ level = ZoomLevelInfo::minimumLevel();
+ } else if (level > ZoomLevelInfo::maximumLevel()) {
+ level = ZoomLevelInfo::maximumLevel();
+ }
+
+ if (level == m_zoomLevel) {
+ return;
+ }
+
+ m_zoomLevel = level;
+
+ if (previewsShown()) {
+ const int previewSize = ZoomLevelInfo::iconSizeForZoomLevel(level);
+
+ switch (itemLayout()) {
+ case KFileItemListView::IconsLayout: IconsModeSettings::setPreviewSize(previewSize); break;
+ case KFileItemListView::CompactLayout: CompactModeSettings::setPreviewSize(previewSize); break;
+ case KFileItemListView::DetailsLayout: DetailsModeSettings::setPreviewSize(previewSize); break;
+ default: Q_ASSERT(false); break;
+ }
+ } else {
+ const int iconSize = ZoomLevelInfo::iconSizeForZoomLevel(level);
+ switch (itemLayout()) {
+ case KFileItemListView::IconsLayout: IconsModeSettings::setIconSize(iconSize); break;
+ case KFileItemListView::CompactLayout: CompactModeSettings::setIconSize(iconSize); break;
+ case KFileItemListView::DetailsLayout: DetailsModeSettings::setIconSize(iconSize); break;
+ default: Q_ASSERT(false); break;
+ }
+ }
+
+ updateGridSize();
+}
+
+int DolphinItemListContainer::zoomLevel() const
+{
+ return m_zoomLevel;
+}
+
+void DolphinItemListContainer::setItemLayout(KFileItemListView::Layout layout)
+{
+ if (layout == itemLayout()) {
+ return;
+ }
+
+ beginTransaction();
+ m_fileItemListView->setItemLayout(layout);
+
+ switch (layout) {
+ case KFileItemListView::IconsLayout:
+ case KFileItemListView::DetailsLayout:
+ m_fileItemListView->setScrollOrientation(Qt::Vertical);
+ break;
+ case KFileItemListView::CompactLayout:
+ m_fileItemListView->setScrollOrientation(Qt::Horizontal);
+ break;
+ default:
+ Q_ASSERT(false);
+ break;
+ }
+
+ updateGridSize();
+ endTransaction();
+}
+
+KFileItemListView::Layout DolphinItemListContainer::itemLayout() const
+{
+ return m_fileItemListView->itemLayout();
+}
+
+void DolphinItemListContainer::beginTransaction()
+{
+ m_fileItemListView->beginTransaction();
+}
+
+void DolphinItemListContainer::endTransaction()
+{
+ m_fileItemListView->endTransaction();
+}
+
+void DolphinItemListContainer::updateGridSize()
+{
+ // Calculate the size of the icon
+ int iconSize;
+ if (previewsShown()) {
+ switch (itemLayout()) {
+ case KFileItemListView::IconsLayout: iconSize = IconsModeSettings::previewSize(); break;
+ case KFileItemListView::CompactLayout: iconSize = CompactModeSettings::previewSize(); break;
+ case KFileItemListView::DetailsLayout: iconSize = DetailsModeSettings::previewSize(); break;
+ default: Q_ASSERT(false); break;
+ }
+ } else {
+ switch (itemLayout()) {
+ case KFileItemListView::IconsLayout: iconSize = IconsModeSettings::iconSize(); break;
+ case KFileItemListView::CompactLayout: iconSize = CompactModeSettings::iconSize(); break;
+ case KFileItemListView::DetailsLayout: iconSize = DetailsModeSettings::iconSize(); break;
+ default: Q_ASSERT(false); break;
+ }
+ }
+
+ m_zoomLevel = ZoomLevelInfo::zoomLevelForIconSize(QSize(iconSize, iconSize));
+ KItemListStyleOption styleOption = m_fileItemListView->styleOption();
+
+ const int innerMargin = (iconSize >= KIconLoader::SizeSmallMedium) ? 4 : 2;
+
+ // Calculate the item-width and item-height
+ int itemWidth;
+ int itemHeight;
+ switch (itemLayout()) {
+ case KFileItemListView::IconsLayout: {
+ const int minItemWidth = 64;
+ itemWidth = minItemWidth + IconsModeSettings::textWidthIndex() * 64; // TODO:
+ if (itemWidth < iconSize + innerMargin * 2) {
+ itemWidth = iconSize + innerMargin * 2;
+ }
+ itemHeight = innerMargin * 2 + iconSize + styleOption.fontMetrics.height();
+ break;
+ }
+ case KFileItemListView::CompactLayout: {
+ itemWidth = innerMargin * 2;
+ const int textLinesCount = m_fileItemListView->visibleRoles().count();
+ itemHeight = innerMargin * 2 + qMax(iconSize, textLinesCount * styleOption.fontMetrics.height());
+ break;
+ }
+ case KFileItemListView::DetailsLayout: {
+ itemWidth = -1;
+ itemHeight = innerMargin * 2 + qMax(iconSize, styleOption.fontMetrics.height());
+ break;
+ }
+ default: Q_ASSERT(false); break;
+ }
+
+ // Apply the calculated values
+ styleOption.margin = innerMargin;
+ styleOption.iconSize = iconSize;
+ m_fileItemListView->setStyleOption(styleOption);
+ m_fileItemListView->setItemSize(QSizeF(itemWidth, itemHeight));
+}
+
+#include "dolphinitemlistcontainer.moc"
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
+ * *
+ * 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 DOLPHINITEMLISTCONTAINER_H
+#define DOLPHINITEMLISTCONTAINER_H
+
+#include <kitemviews/kfileitemlistview.h>
+#include <kitemviews/kitemlistcontainer.h>
+
+#include <libdolphin_export.h>
+
+class KDirLister;
+class KFileItemListView;
+
+/**
+ * @brief Extends KItemListContainer by Dolphin specific properties.
+ *
+ * The view and model for KFileItems are created automatically when
+ * instantating KItemListContainer.
+ *
+ * The Dolphin settings of the icons-, compact- and details-view are
+ * converted internally to properties that can be used to configure e.g.
+ * the item-size and visible roles of the KItemListView.
+ */
+class LIBDOLPHINPRIVATE_EXPORT DolphinItemListContainer : public KItemListContainer
+{
+ Q_OBJECT
+
+public:
+ DolphinItemListContainer(KDirLister* dirLister,
+ QWidget* parent = 0);
+
+ virtual ~DolphinItemListContainer();
+
+ void setPreviewsShown(bool show);
+ bool previewsShown() const;
+
+ /**
+ * Sets the visible roles to \p roles. The integer-value defines
+ * the order of the visible role: Smaller values are ordered first.
+ */
+ void setVisibleRoles(const QHash<QByteArray, int>& roles);
+ QHash<QByteArray, int> visibleRoles() const;
+
+ void setZoomLevel(int level);
+ int zoomLevel() const;
+
+ void setItemLayout(KFileItemListView::Layout layout);
+ KFileItemListView::Layout itemLayout() const;
+
+ void beginTransaction();
+ void endTransaction();
+
+private:
+ void updateGridSize();
+
+private:
+ int m_zoomLevel;
+ KFileItemListView* m_fileItemListView;
+};
+
+#endif
+++ /dev/null
-/**
- * This file is part of the KDE project
- * Copyright (C) 2007 Rafael Fernández López <ereslibre@kde.org>
- *
- * 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.
- */
-
-#include "dolphinmodel.h"
-
-#include "dolphinsortfilterproxymodel.h"
-
-#include <KCategorizedView>
-#include <KDateTime>
-#include <KDirModel>
-#include <KFileItem>
-#include <KIconLoader>
-#include <KLocale>
-#include <KUrl>
-#include <KUser>
-#include <KMimeType>
-#include <KStandardDirs>
-
-#include <QList>
-#include <QSortFilterProxyModel>
-#include <QPainter>
-#include <QPersistentModelIndex>
-#include <QDir>
-#include <QFileInfo>
-
-const char* const DolphinModel::m_others = I18N_NOOP2("@title:group Name", "Others");
-
-DolphinModel::DolphinModel(QObject* parent) :
- KDirModel(parent),
- m_hasVersionData(false),
- m_revisionHash()
-{
- setJobTransfersVisible(true);
-}
-
-DolphinModel::~DolphinModel()
-{
-}
-
-bool DolphinModel::setData(const QModelIndex& index, const QVariant& value, int role)
-{
- if ((index.column() == DolphinModel::Version) && (role == Qt::DecorationRole)) {
- // TODO: remove data again when items are deleted...
-
- const QPersistentModelIndex key = index;
- const KVersionControlPlugin::VersionState state = static_cast<KVersionControlPlugin::VersionState>(value.toInt());
- if (m_revisionHash.value(key, KVersionControlPlugin::UnversionedVersion) != state) {
- if (!m_hasVersionData) {
- connect(this, SIGNAL(rowsRemoved (const QModelIndex&, int, int)),
- this, SLOT(slotRowsRemoved(const QModelIndex&, int, int)));
- m_hasVersionData = true;
- }
-
- m_revisionHash.insert(key, state);
- emit dataChanged(index, index);
- return true;
- }
- }
-
- return KDirModel::setData(index, value, role);
-}
-
-QVariant DolphinModel::data(const QModelIndex& index, int role) const
-{
- switch (role) {
- case KCategorizedSortFilterProxyModel::CategoryDisplayRole:
- return displayRoleData(index);
-
- case KCategorizedSortFilterProxyModel::CategorySortRole:
- return sortRoleData(index);
-
- case Qt::DecorationRole:
- if (index.column() == DolphinModel::Version) {
- return m_revisionHash.value(index, KVersionControlPlugin::UnversionedVersion);
- }
- break;
-
- case Qt::DisplayRole:
- switch (index.column()) {
- case DolphinModel::LinkDest: {
- const KDirModel *dirModel = qobject_cast<const KDirModel*>(index.model());
- const KFileItem item = dirModel->itemForIndex(index);
- return item.linkDest();
- }
-
- case DolphinModel::LocalPathOrUrl:
- const KDirModel *dirModel = qobject_cast<const KDirModel*>(index.model());
- const KFileItem item = dirModel->itemForIndex(index);
- const KUrl url = item.mostLocalUrl();
- if (url.protocol() == QLatin1String("trash")) {
- const KIO::UDSEntry udsEntry = item.entry();
- return udsEntry.stringValue(KIO::UDSEntry::UDS_EXTRA);
- }
- return url.directory();
- }
- break;
-
- default:
- break;
- }
-
- return KDirModel::data(index, role);
-}
-
-QVariant DolphinModel::headerData(int section, Qt::Orientation orientation, int role) const
-{
- if ((orientation == Qt::Horizontal) && (role == Qt::DisplayRole)) {
- switch (section) {
- case DolphinModel::LinkDest:
- return i18nc("@title::column", "Link Destination");
- case DolphinModel::LocalPathOrUrl:
- return i18nc("@title::column", "Path");
- default:
- return KDirModel::headerData(section, orientation, role);
- }
- }
- return QVariant();
-}
-
-int DolphinModel::columnCount(const QModelIndex& parent) const
-{
- return KDirModel::columnCount(parent) + (ExtraColumnCount - ColumnCount);
-}
-
-void DolphinModel::clearVersionData()
-{
- m_revisionHash.clear();
- m_hasVersionData = false;
-}
-
-bool DolphinModel::hasVersionData() const
-{
- return m_hasVersionData;
-}
-
-void DolphinModel::slotRowsRemoved(const QModelIndex& parent, int start, int end)
-{
- if (m_hasVersionData) {
- const int column = parent.column();
- for (int row = start; row <= end; ++row) {
- m_revisionHash.remove(parent.child(row, column));
- }
- }
-}
-
-QVariant DolphinModel::displayRoleData(const QModelIndex& index) const
-{
- QString retString;
-
- if (!index.isValid()) {
- return retString;
- }
-
- const KDirModel *dirModel = qobject_cast<const KDirModel*>(index.model());
- KFileItem item = dirModel->itemForIndex(index);
-
- switch (index.column()) {
- case KDirModel::Name: {
- // KDirModel checks columns to know to which role are
- // we talking about
- const QModelIndex nameIndex = index.model()->index(index.row(), KDirModel::Name, index.parent());
- if (!nameIndex.isValid()) {
- return retString;
- }
- const QVariant data = nameIndex.model()->data(nameIndex, Qt::DisplayRole);
- const QString name = data.toString();
- if (!name.isEmpty()) {
- if (!item.isHidden() && name.at(0).isLetter())
- retString = name.at(0).toUpper();
- else if (item.isHidden()) {
- if (name.at(0) == '.') {
- if (name.size() > 1 && name.at(1).isLetter()) {
- retString = name.at(1).toUpper();
- } else {
- retString = i18nc("@title:group Name", m_others);
- }
- } else {
- retString = name.at(0).toUpper();
- }
- } else {
- bool validCategory = false;
-
- const QString str(name.toUpper());
- const QChar* currA = str.unicode();
- while (!currA->isNull() && !validCategory) {
- if (currA->isLetter()) {
- validCategory = true;
- } else if (currA->isDigit()) {
- return i18nc("@title:group Name", m_others);
- } else {
- ++currA;
- }
- }
-
- retString = validCategory ? *currA : i18nc("@title:group Name", m_others);
- }
- }
- break;
- }
-
- case KDirModel::Size: {
- const KIO::filesize_t fileSize = !item.isNull() ? item.size() : ~0U;
- if (!item.isNull() && item.isDir()) {
- retString = i18nc("@title:group Size", "Folders");
- } else if (fileSize < 5242880) {
- retString = i18nc("@title:group Size", "Small");
- } else if (fileSize < 10485760) {
- retString = i18nc("@title:group Size", "Medium");
- } else {
- retString = i18nc("@title:group Size", "Big");
- }
- break;
- }
-
- case KDirModel::ModifiedTime: {
- KDateTime modifiedTime = item.time(KFileItem::ModificationTime);
- modifiedTime = modifiedTime.toLocalZone();
-
- const QDate currentDate = KDateTime::currentLocalDateTime().date();
- const QDate modifiedDate = modifiedTime.date();
-
- const int daysDistance = modifiedDate.daysTo(currentDate);
-
- int yearForCurrentWeek = 0;
- int currentWeek = currentDate.weekNumber(&yearForCurrentWeek);
- if (yearForCurrentWeek == currentDate.year() + 1) {
- currentWeek = 53;
- }
-
- int yearForModifiedWeek = 0;
- int modifiedWeek = modifiedDate.weekNumber(&yearForModifiedWeek);
- if (yearForModifiedWeek == modifiedDate.year() + 1) {
- modifiedWeek = 53;
- }
-
- if (currentDate.year() == modifiedDate.year() && currentDate.month() == modifiedDate.month()) {
- if (modifiedWeek > currentWeek) {
- // use case: modified date = 2010-01-01, current date = 2010-01-22
- // modified week = 53, current week = 3
- modifiedWeek = 0;
- }
- switch (currentWeek - modifiedWeek) {
- case 0:
- switch (daysDistance) {
- case 0: retString = i18nc("@title:group Date", "Today"); break;
- case 1: retString = i18nc("@title:group Date", "Yesterday"); break;
- default: retString = modifiedTime.toString(i18nc("@title:group The week day name: %A", "%A"));
- }
- break;
- case 1:
- retString = i18nc("@title:group Date", "Last Week");
- break;
- case 2:
- retString = i18nc("@title:group Date", "Two Weeks Ago");
- break;
- case 3:
- retString = i18nc("@title:group Date", "Three Weeks Ago");
- break;
- case 4:
- case 5:
- retString = i18nc("@title:group Date", "Earlier this Month");
- break;
- default:
- Q_ASSERT(false);
- }
- } else {
- const QDate lastMonthDate = currentDate.addMonths(-1);
- if (lastMonthDate.year() == modifiedDate.year() && lastMonthDate.month() == modifiedDate.month()) {
- if (daysDistance == 1) {
- retString = modifiedTime.toString(i18nc("@title:group Date: %B is full month name in current locale, and %Y is full year number", "Yesterday (%B, %Y)"));
- } else if (daysDistance <= 7) {
- retString = modifiedTime.toString(i18nc("@title:group The week day name: %A, %B is full month name in current locale, and %Y is full year number", "%A (%B, %Y)"));
- } else if (daysDistance <= 7 * 2) {
- retString = modifiedTime.toString(i18nc("@title:group Date: %B is full month name in current locale, and %Y is full year number", "Last Week (%B, %Y)"));
- } else if (daysDistance <= 7 * 3) {
- retString = modifiedTime.toString(i18nc("@title:group Date: %B is full month name in current locale, and %Y is full year number", "Two Weeks Ago (%B, %Y)"));
- } else if (daysDistance <= 7 * 4) {
- retString = modifiedTime.toString(i18nc("@title:group Date: %B is full month name in current locale, and %Y is full year number", "Three Weeks Ago (%B, %Y)"));
- } else {
- retString = modifiedTime.toString(i18nc("@title:group Date: %B is full month name in current locale, and %Y is full year number", "Earlier on %B, %Y"));
- }
- } else {
- retString = modifiedTime.toString(i18nc("@title:group The month and year: %B is full month name in current locale, and %Y is full year number", "%B, %Y"));
- }
- }
- break;
- }
-
- case KDirModel::Permissions: {
- QString user;
- QString group;
- QString others;
-
- QFileInfo info(item.url().pathOrUrl());
-
- // set user string
- if (info.permission(QFile::ReadUser)) {
- user = i18nc("@item:intext Access permission, concatenated", "Read, ");
- }
- if (info.permission(QFile::WriteUser)) {
- user += i18nc("@item:intext Access permission, concatenated", "Write, ");
- }
- if (info.permission(QFile::ExeUser)) {
- user += i18nc("@item:intext Access permission, concatenated", "Execute, ");
- }
- user = user.isEmpty() ? i18nc("@item:intext Access permission, concatenated", "Forbidden") : user.mid(0, user.count() - 2);
-
- // set group string
- if (info.permission(QFile::ReadGroup)) {
- group = i18nc("@item:intext Access permission, concatenated", "Read, ");
- }
- if (info.permission(QFile::WriteGroup)) {
- group += i18nc("@item:intext Access permission, concatenated", "Write, ");
- }
- if (info.permission(QFile::ExeGroup)) {
- group += i18nc("@item:intext Access permission, concatenated", "Execute, ");
- }
- group = group.isEmpty() ? i18nc("@item:intext Access permission, concatenated", "Forbidden") : group.mid(0, group.count() - 2);
-
- // set permission string
- if (info.permission(QFile::ReadOther)) {
- others = i18nc("@item:intext Access permission, concatenated", "Read, ");
- }
- if (info.permission(QFile::WriteOther)) {
- others += i18nc("@item:intext Access permission, concatenated", "Write, ");
- }
- if (info.permission(QFile::ExeOther)) {
- others += i18nc("@item:intext Access permission, concatenated", "Execute, ");
- }
- others = others.isEmpty() ? i18nc("@item:intext Access permission, concatenated", "Forbidden") : others.mid(0, others.count() - 2);
-
- retString = i18nc("@title:group Files and folders by permissions", "(User: %1) (Group: %2) (Others: %3)", user, group, others);
- break;
- }
-
- case KDirModel::Owner:
- retString = item.user();
- break;
-
- case KDirModel::Group:
- retString = item.group();
- break;
-
- case KDirModel::Type:
- retString = item.mimeComment();
- break;
-
- case DolphinModel::Version:
- retString = "test";
- break;
- }
-
- return retString;
-}
-
-QVariant DolphinModel::sortRoleData(const QModelIndex& index) const
-{
- QVariant retVariant;
-
- if (!index.isValid()) {
- return retVariant;
- }
-
- const KDirModel *dirModel = qobject_cast<const KDirModel*>(index.model());
- KFileItem item = dirModel->itemForIndex(index);
-
- switch (index.column()) {
- case KDirModel::Name: {
- retVariant = data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole);
- if (retVariant == i18nc("@title:group Name", m_others)) {
- // assure that the "Others" group is always the last categorization
- retVariant = QString('Z').append(QChar::ReplacementCharacter);
- }
- break;
- }
-
- case KDirModel::Size: {
- const KIO::filesize_t fileSize = !item.isNull() ? item.size() : ~0U;
- if (item.isDir()) {
- retVariant = 0;
- } else if (fileSize < 5242880) {
- retVariant = 1;
- } else if (fileSize < 10485760) {
- retVariant = 2;
- } else {
- retVariant = 3;
- }
- break;
- }
-
- case KDirModel::ModifiedTime: {
- KDateTime modifiedTime = item.time(KFileItem::ModificationTime);
- modifiedTime = modifiedTime.toLocalZone();
-
- const QDate currentDate = KDateTime::currentLocalDateTime().date();
- const QDate modifiedDate = modifiedTime.date();
-
- retVariant = -modifiedDate.daysTo(currentDate);
- break;
- }
-
- case KDirModel::Permissions: {
- QFileInfo info(item.url().pathOrUrl());
-
- retVariant = -KDirSortFilterProxyModel::pointsForPermissions(info);
- break;
- }
-
- case KDirModel::Owner:
- retVariant = item.user();
- break;
-
- case KDirModel::Group:
- retVariant = item.group();
- break;
-
- case KDirModel::Type:
- if (item.isDir()) {
- // when sorting we want folders to be placed first
- retVariant = QString(); // krazy:exclude=nullstrassign
- } else {
- retVariant = item.mimeComment();
- }
- break;
-
- default:
- break;
- }
-
- return retVariant;
-}
+++ /dev/null
-/*
- * This file is part of the KDE project
- * Copyright (C) 2007 Rafael Fernández López <ereslibre@kde.org>
- *
- * 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 DOLPHINMODEL_H
-#define DOLPHINMODEL_H
-
-#include <KDirModel>
-#include <kversioncontrolplugin.h>
-#include <libdolphin_export.h>
-
-#include <QHash>
-#include <QPersistentModelIndex>
-
-class LIBDOLPHINPRIVATE_EXPORT DolphinModel : public KDirModel
-{
- Q_OBJECT
-
-public:
- enum AdditionalColumns {
- LinkDest = KDirModel::ColumnCount,
- LocalPathOrUrl,
- // Assure that invisible columns are added as last entries:
- Version,
- ExtraColumnCount // Mandatory last entry
- };
-
- DolphinModel(QObject* parent = 0);
- virtual ~DolphinModel();
-
- virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
- virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
- virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
- virtual int columnCount(const QModelIndex& parent = QModelIndex()) const;
-
- void clearVersionData();
- bool hasVersionData() const;
-
-private slots:
- void slotRowsRemoved(const QModelIndex& parent, int start, int end);
-
-private:
- QVariant displayRoleData(const QModelIndex& index) const;
- QVariant sortRoleData(const QModelIndex& index) const;
-
-private:
- bool m_hasVersionData;
- QHash<QPersistentModelIndex, KVersionControlPlugin::VersionState> m_revisionHash;
-
- static const char* const m_others;
-};
-
-#endif // DOLPHINMODEL_H
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2006-2010 by Peter Penz <peter.penz19@gmail.com> *
- * Copyright (C) 2006 by Dominic Battre <dominic@battre.de> *
- * Copyright (C) 2006 by Martin Pool <mbp@canonical.com> *
- * Copyright (C) 2007 by Rafael Fernández López <ereslibre@kde.org> *
- * *
- * 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 "dolphinsortfilterproxymodel.h"
-
-DolphinSortFilterProxyModel::DolphinSortFilterProxyModel(QObject* parent) :
- KDirSortFilterProxyModel(parent),
- m_sorting(DolphinView::SortByName),
- m_sortOrder(Qt::AscendingOrder)
-{
-}
-
-DolphinSortFilterProxyModel::~DolphinSortFilterProxyModel()
-{
-}
-
-void DolphinSortFilterProxyModel::setSorting(DolphinView::Sorting sorting)
-{
- m_sorting = sorting;
- KDirSortFilterProxyModel::sort(static_cast<int>(m_sorting), m_sortOrder);
-}
-
-void DolphinSortFilterProxyModel::setSortOrder(Qt::SortOrder sortOrder)
-{
- m_sortOrder = sortOrder;
- KDirSortFilterProxyModel::sort(static_cast<int>(m_sorting), m_sortOrder);
-}
-
-void DolphinSortFilterProxyModel::setSortFoldersFirst(bool foldersFirst)
-{
- if (foldersFirst != sortFoldersFirst()) {
- KDirSortFilterProxyModel::setSortFoldersFirst(foldersFirst);
-
- // We need to make sure that the files and folders are really resorted.
- // Without the following two lines, QSortFilterProxyModel::sort(int column, Qt::SortOrder order)
- // would do nothing because neither the column nor the sort order have changed.
- // TODO: remove this hack if we find a better way to force the ProxyModel to re-sort the data.
- const Qt::SortOrder tmpSortOrder = (m_sortOrder == Qt::AscendingOrder ? Qt::DescendingOrder : Qt::AscendingOrder);
- KDirSortFilterProxyModel::sort(static_cast<int>(m_sorting), tmpSortOrder);
-
- // Now comes the real sorting with the old column and sort order
- KDirSortFilterProxyModel::sort(static_cast<int>(m_sorting), m_sortOrder);
- }
-}
-
-void DolphinSortFilterProxyModel::sort(int column, Qt::SortOrder sortOrder)
-{
- m_sorting = sortingForColumn(column);
- m_sortOrder = sortOrder;
-
- emit sortingRoleChanged();
- KDirSortFilterProxyModel::sort(static_cast<int>(m_sorting), sortOrder);
-}
-
-DolphinView::Sorting DolphinSortFilterProxyModel::sortingForColumn(int column)
-{
- Q_ASSERT(column >= 0);
- Q_ASSERT(column <= DolphinView::MaxSortingEnum);
- return static_cast<DolphinView::Sorting>(column);
-}
-
-#include "dolphinsortfilterproxymodel.moc"
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2006-2010 by Peter Penz <peter.penz19@gmail.com> *
- * *
- * 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 DOLPHINSORTFILTERPROXYMODEL_H
-#define DOLPHINSORTFILTERPROXYMODEL_H
-
-#include <views/dolphinview.h>
-#include <kdirsortfilterproxymodel.h>
-#include <libdolphin_export.h>
-
-/**
- * @brief Acts as proxy model for DolphinModel to sort and filter
- * KFileItems.
- *
- * Per default a natural sorting is done. This means that items like:
- * - item_10.png
- * - item_1.png
- * - item_2.png
- * are sorted like
- * - item_1.png
- * - item_2.png
- * - item_10.png
- */
-class LIBDOLPHINPRIVATE_EXPORT DolphinSortFilterProxyModel : public KDirSortFilterProxyModel
-{
- Q_OBJECT
-
-public:
- DolphinSortFilterProxyModel(QObject* parent = 0);
- virtual ~DolphinSortFilterProxyModel();
-
- void setSorting(DolphinView::Sorting sorting);
- DolphinView::Sorting sorting() const;
-
- void setSortOrder(Qt::SortOrder sortOrder);
- Qt::SortOrder sortOrder() const;
-
- void setSortFoldersFirst(bool foldersFirst);
-
- /** @reimplemented */
- virtual void sort(int column,
- Qt::SortOrder order = Qt::AscendingOrder);
-
- /**
- * Helper method to get the DolphinView::Sorting type for a given
- * column \a column. If the column is smaller 0 or greater than the
- * available columns, DolphinView::SortByName is returned.
- */
- static DolphinView::Sorting sortingForColumn(int column);
-
-signals:
- void sortingRoleChanged();
-
-private:
- DolphinView::Sorting m_sorting:16;
- Qt::SortOrder m_sortOrder:16;
-};
-
-inline DolphinView::Sorting DolphinSortFilterProxyModel::sorting() const
-{
- return m_sorting;
-}
-
-inline Qt::SortOrder DolphinSortFilterProxyModel::sortOrder() const
-{
- return m_sortOrder;
-}
-
-#endif
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2010 by Peter Penz <peter.penz19@gmail.com> *
- * Copyright (C) 2008 by Simon St. James <kdedevel@etotheipiplusone.com> *
- * *
- * 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 "dolphintreeview.h"
-
-#include "dolphinmodel.h"
-
-#include <QApplication>
-#include <QEvent>
-#include <QHeaderView>
-#include <QMouseEvent>
-#include <QPainter>
-#include <QScrollBar>
-
-DolphinTreeView::DolphinTreeView(QWidget* parent) :
- QTreeView(parent),
- m_expandingTogglePressed(false),
- m_useDefaultIndexAt(true),
- m_ignoreScrollTo(false),
- m_dropRect(),
- m_band()
-{
- setUniformRowHeights(true);
-}
-
-DolphinTreeView::~DolphinTreeView()
-{
-}
-
-void DolphinTreeView::keyboardSearch(const QString & search)
-{
- const QModelIndex oldCurrent = currentIndex();
- QTreeView::keyboardSearch(search);
- if (currentIndex() != oldCurrent) {
- // The current index has changed, but it is not selected yet.
- // To select it, we call setCurrentIndex(...).
- setCurrentIndex(currentIndex());
- }
-}
-
-QRegion DolphinTreeView::visualRegionForSelection(const QItemSelection& selection) const
-{
- // We have to make sure that the visualRect of each model index is inside the region.
- // QTreeView::visualRegionForSelection does not do it right because it assumes implicitly
- // that all visualRects have the same width, which is in general not the case here.
- QRegion selectionRegion;
- const QModelIndexList indexes = selection.indexes();
-
- foreach(const QModelIndex& index, indexes) {
- selectionRegion += visualRect(index);
- }
-
- return selectionRegion;
-}
-
-bool DolphinTreeView::acceptsDrop(const QModelIndex& index) const
-{
- Q_UNUSED(index);
- return false;
-}
-
-bool DolphinTreeView::event(QEvent* event)
-{
- switch (event->type()) {
- case QEvent::Polish:
- m_useDefaultIndexAt = false;
- break;
- default:
- break;
- }
- return QTreeView::event(event);
-}
-
-void DolphinTreeView::mousePressEvent(QMouseEvent* event)
-{
- const QModelIndex current = currentIndex();
- QTreeView::mousePressEvent(event);
-
- m_expandingTogglePressed = isAboveExpandingToggle(event->pos());
-
- const QModelIndex index = indexAt(event->pos());
- const bool updateState = index.isValid() &&
- (index.column() == DolphinModel::Name) &&
- (event->button() == Qt::LeftButton);
- if (updateState) {
- setState(QAbstractItemView::DraggingState);
- }
-
- if (!index.isValid() || (index.column() != DolphinModel::Name)) {
- const Qt::KeyboardModifiers mod = QApplication::keyboardModifiers();
- if (!m_expandingTogglePressed && !(mod & Qt::ShiftModifier) && !(mod & Qt::ControlModifier)) {
- clearSelection();
- }
-
- // Restore the current index, other columns are handled as viewport area.
- // setCurrentIndex(...) implicitly calls scrollTo(...), which we want to ignore.
- m_ignoreScrollTo = true;
- selectionModel()->setCurrentIndex(current, QItemSelectionModel::Current);
- m_ignoreScrollTo = false;
-
- if ((event->button() == Qt::LeftButton) && !m_expandingTogglePressed) {
- // Inform Qt about what we are doing - otherwise it starts dragging items around!
- setState(DragSelectingState);
- m_band.show = true;
- // Incremental update data will not be useful - start from scratch.
- m_band.ignoreOldInfo = true;
- const QPoint scrollPos(horizontalScrollBar()->value(), verticalScrollBar()->value());
- m_band.origin = event->pos() + scrollPos;
- m_band.destination = m_band.origin;
- m_band.originalSelection = selectionModel()->selection();
- }
- }
-}
-
-void DolphinTreeView::mouseMoveEvent(QMouseEvent* event)
-{
- if (m_expandingTogglePressed) {
- // Per default QTreeView starts either a selection or a drag operation when dragging
- // the expanding toggle button (Qt-issue - see TODO comment in DolphinIconsView::mousePressEvent()).
- // Turn off this behavior in Dolphin to stay predictable:
- setState(QAbstractItemView::NoState);
- return;
- }
-
- if (m_band.show) {
- const QPoint mousePos = event->pos();
- const QModelIndex index = indexAt(mousePos);
- if (!index.isValid()) {
- // The destination of the selection rectangle is above the viewport. In this
- // case QTreeView does no selection at all, which is not the wanted behavior
- // in Dolphin. Select all items within the elastic band rectangle.
- updateElasticBandSelection();
- }
-
- // TODO: Enable QTreeView::mouseMoveEvent(event) again, as soon
- // as the Qt-issue #199631 has been fixed.
- // QTreeView::mouseMoveEvent(event);
- QAbstractItemView::mouseMoveEvent(event);
- updateElasticBand();
- } else {
- // TODO: Enable QTreeView::mouseMoveEvent(event) again, as soon
- // as the Qt-issue #199631 has been fixed.
- // QTreeView::mouseMoveEvent(event);
- QAbstractItemView::mouseMoveEvent(event);
- }
-}
-
-void DolphinTreeView::mouseReleaseEvent(QMouseEvent* event)
-{
- if (!m_expandingTogglePressed) {
- const QModelIndex index = indexAt(event->pos());
- if (index.isValid() && (index.column() == DolphinModel::Name)) {
- QTreeView::mouseReleaseEvent(event);
- } else {
- // don't change the current index if the cursor is released
- // above any other column than the name column, as the other
- // columns act as viewport
- const QModelIndex current = currentIndex();
- QTreeView::mouseReleaseEvent(event);
- selectionModel()->setCurrentIndex(current, QItemSelectionModel::Current);
- }
- }
- m_expandingTogglePressed = false;
-
- if (m_band.show) {
- setState(NoState);
- updateElasticBand();
- m_band.show = false;
- }
-}
-
-void DolphinTreeView::startDrag(Qt::DropActions supportedActions)
-{
- Q_UNUSED(supportedActions);
- m_band.show = false;
-}
-
-void DolphinTreeView::dragEnterEvent(QDragEnterEvent* event)
-{
- Q_UNUSED(event);
- if (m_band.show) {
- updateElasticBand();
- m_band.show = false;
- }
-}
-
-void DolphinTreeView::dragMoveEvent(QDragMoveEvent* event)
-{
- QTreeView::dragMoveEvent(event);
-
- setDirtyRegion(m_dropRect);
-
- const QModelIndex index = indexAt(event->pos());
- if (acceptsDrop(index)) {
- m_dropRect = visualRect(index);
- } else {
- m_dropRect.setSize(QSize()); // set invalid
- }
- setDirtyRegion(m_dropRect);
-}
-
-void DolphinTreeView::dragLeaveEvent(QDragLeaveEvent* event)
-{
- QTreeView::dragLeaveEvent(event);
- setDirtyRegion(m_dropRect);
-}
-
-void DolphinTreeView::paintEvent(QPaintEvent* event)
-{
- QTreeView::paintEvent(event);
- if (m_band.show) {
- // The following code has been taken from QListView
- // and adapted to DolphinDetailsView.
- // (C) 1992-2007 Trolltech ASA
- QStyleOptionRubberBand opt;
- opt.initFrom(this);
- opt.shape = QRubberBand::Rectangle;
- opt.opaque = false;
- opt.rect = elasticBandRect();
-
- QPainter painter(viewport());
- painter.save();
- style()->drawControl(QStyle::CE_RubberBand, &opt, &painter);
- painter.restore();
- }
-}
-
-QModelIndex DolphinTreeView::indexAt(const QPoint& point) const
-{
- // The blank portion of the name column counts as empty space
- const QModelIndex index = QTreeView::indexAt(point);
- const bool isAboveEmptySpace = !m_useDefaultIndexAt &&
- (index.column() == KDirModel::Name) &&
- !visualRect(index).contains(point);
- return isAboveEmptySpace ? QModelIndex() : index;
-}
-
-void DolphinTreeView::setSelection(const QRect& rect, QItemSelectionModel::SelectionFlags command)
-{
- // We must override setSelection() as Qt calls it internally and when this happens
- // we must ensure that the default indexAt() is used.
- if (!m_band.show) {
- m_useDefaultIndexAt = true;
- QTreeView::setSelection(rect, command);
- m_useDefaultIndexAt = false;
- } else {
- // Use our own elastic band selection algorithm
- updateElasticBandSelection();
- }
-}
-
-
-void DolphinTreeView::scrollTo(const QModelIndex & index, ScrollHint hint)
-{
- if (!m_ignoreScrollTo) {
- QTreeView::scrollTo(index, hint);
- }
-}
-
-void DolphinTreeView::updateElasticBandSelection()
-{
- if (!m_band.show) {
- return;
- }
-
- // Ensure the elastic band itself is up-to-date, in
- // case we are being called due to e.g. a drag event.
- updateElasticBand();
-
- // Clip horizontally to the name column, as some filenames will be
- // longer than the column. We don't clip vertically as origin
- // may be above or below the current viewport area.
- const int nameColumnX = header()->sectionPosition(DolphinModel::Name);
- const int nameColumnWidth = header()->sectionSize(DolphinModel::Name);
- QRect selRect = elasticBandRect().normalized();
- QRect nameColumnArea(nameColumnX, selRect.y(), nameColumnWidth, selRect.height());
- selRect = nameColumnArea.intersect(selRect).normalized();
- // Get the last elastic band rectangle, expressed in viewpoint coordinates.
- const QPoint scrollPos(horizontalScrollBar()->value(), verticalScrollBar()->value());
- QRect oldSelRect = QRect(m_band.lastSelectionOrigin - scrollPos, m_band.lastSelectionDestination - scrollPos).normalized();
-
- if (selRect.isNull()) {
- selectionModel()->select(m_band.originalSelection, QItemSelectionModel::ClearAndSelect);
- m_band.ignoreOldInfo = true;
- return;
- }
-
- if (!m_band.ignoreOldInfo) {
- // Do some quick checks to see if we can rule out the need to
- // update the selection.
- Q_ASSERT(uniformRowHeights());
- QModelIndex dummyIndex = model()->index(0, 0);
- if (!dummyIndex.isValid()) {
- // No items in the model presumably.
- return;
- }
-
- // If the elastic band does not cover the same rows as before, we'll
- // need to re-check, and also invalidate the old item distances.
- const int rowHeight = QTreeView::rowHeight(dummyIndex);
- const bool coveringSameRows =
- (selRect.top() / rowHeight == oldSelRect.top() / rowHeight) &&
- (selRect.bottom() / rowHeight == oldSelRect.bottom() / rowHeight);
- if (coveringSameRows) {
- // Covering the same rows, but have we moved far enough horizontally
- // that we might have (de)selected some other items?
- const bool itemSelectionChanged =
- ((selRect.left() > oldSelRect.left()) &&
- (selRect.left() > m_band.insideNearestLeftEdge)) ||
- ((selRect.left() < oldSelRect.left()) &&
- (selRect.left() <= m_band.outsideNearestLeftEdge)) ||
- ((selRect.right() < oldSelRect.right()) &&
- (selRect.left() >= m_band.insideNearestRightEdge)) ||
- ((selRect.right() > oldSelRect.right()) &&
- (selRect.right() >= m_band.outsideNearestRightEdge));
-
- if (!itemSelectionChanged) {
- return;
- }
- }
- } else {
- // This is the only piece of optimization data that needs to be explicitly
- // discarded.
- m_band.lastSelectionOrigin = QPoint();
- m_band.lastSelectionDestination = QPoint();
- oldSelRect = selRect;
- }
-
- // Do the selection from scratch. Force a update of the horizontal distances info.
- m_band.insideNearestLeftEdge = nameColumnX + nameColumnWidth + 1;
- m_band.insideNearestRightEdge = nameColumnX - 1;
- m_band.outsideNearestLeftEdge = nameColumnX - 1;
- m_band.outsideNearestRightEdge = nameColumnX + nameColumnWidth + 1;
-
- // Include the old selection rect as well, so we can deselect
- // items that were inside it but not in the new selRect.
- const QRect boundingRect = selRect.united(oldSelRect).normalized();
- if (boundingRect.isNull()) {
- return;
- }
-
- // Get the index of the item in this row in the name column.
- // TODO - would this still work if the columns could be re-ordered?
- QModelIndex startIndex = QTreeView::indexAt(boundingRect.topLeft());
- if (startIndex.parent().isValid()) {
- startIndex = startIndex.parent().child(startIndex.row(), KDirModel::Name);
- } else {
- startIndex = model()->index(startIndex.row(), KDirModel::Name);
- }
- if (!startIndex.isValid()) {
- selectionModel()->select(m_band.originalSelection, QItemSelectionModel::ClearAndSelect);
- m_band.ignoreOldInfo = true;
- return;
- }
-
- // Go through all indexes between the top and bottom of boundingRect, and
- // update the selection.
- const int verticalCutoff = boundingRect.bottom();
- QModelIndex currIndex = startIndex;
- QModelIndex lastIndex;
- bool allItemsInBoundDone = false;
-
- // Calling selectionModel()->select(...) for each item that needs to be
- // toggled is slow as each call emits selectionChanged(...) so store them
- // and do the selection toggle in one batch.
- QItemSelection itemsToToggle;
- // QItemSelection's deal with continuous ranges of indexes better than
- // single indexes, so try to portion items that need to be toggled into ranges.
- bool formingToggleIndexRange = false;
- QModelIndex toggleIndexRangeBegin = QModelIndex();
-
- do {
- QRect currIndexRect = visualRect(currIndex);
-
- // Update some optimization info as we go.
- const int cr = currIndexRect.right();
- const int cl = currIndexRect.left();
- const int sl = selRect.left();
- const int sr = selRect.right();
- // "The right edge of the name is outside of the rect but nearer than m_outsideNearestLeft", etc
- if ((cr < sl && cr > m_band.outsideNearestLeftEdge)) {
- m_band.outsideNearestLeftEdge = cr;
- }
- if ((cl > sr && cl < m_band.outsideNearestRightEdge)) {
- m_band.outsideNearestRightEdge = cl;
- }
- if ((cl >= sl && cl <= sr && cl > m_band.insideNearestRightEdge)) {
- m_band.insideNearestRightEdge = cl;
- }
- if ((cr >= sl && cr <= sr && cr < m_band.insideNearestLeftEdge)) {
- m_band.insideNearestLeftEdge = cr;
- }
-
- bool currentlySelected = selectionModel()->isSelected(currIndex);
- bool originallySelected = m_band.originalSelection.contains(currIndex);
- bool intersectsSelectedRect = currIndexRect.intersects(selRect);
- bool shouldBeSelected = (intersectsSelectedRect && !originallySelected) || (!intersectsSelectedRect && originallySelected);
- bool needToToggleItem = (currentlySelected && !shouldBeSelected) || (!currentlySelected && shouldBeSelected);
- if (needToToggleItem && !formingToggleIndexRange) {
- toggleIndexRangeBegin = currIndex;
- formingToggleIndexRange = true;
- }
-
- // NOTE: indexBelow actually walks up and down expanded trees for us.
- QModelIndex nextIndex = indexBelow(currIndex);
- allItemsInBoundDone = !nextIndex.isValid() || currIndexRect.top() > verticalCutoff;
-
- const bool commitToggleIndexRange = formingToggleIndexRange &&
- (!needToToggleItem ||
- allItemsInBoundDone ||
- currIndex.parent() != toggleIndexRangeBegin.parent());
- if (commitToggleIndexRange) {
- formingToggleIndexRange = false;
- // If this is the last item in the bounds and it is also the beginning of a range,
- // don't toggle lastIndex - it will already have been dealt with.
- if (!allItemsInBoundDone || toggleIndexRangeBegin != currIndex) {
- itemsToToggle.select(toggleIndexRangeBegin, lastIndex);
- }
- // Need to start a new range immediately with currIndex?
- if (needToToggleItem) {
- toggleIndexRangeBegin = currIndex;
- formingToggleIndexRange = true;
- }
- if (allItemsInBoundDone && needToToggleItem) {
- // Toggle the very last item in the bounds.
- itemsToToggle.select(currIndex, currIndex);
- }
- }
-
- // Next item
- lastIndex = currIndex;
- currIndex = nextIndex;
- } while (!allItemsInBoundDone);
-
-
- selectionModel()->select(itemsToToggle, QItemSelectionModel::Toggle);
-
- m_band.lastSelectionOrigin = m_band.origin;
- m_band.lastSelectionDestination = m_band.destination;
- m_band.ignoreOldInfo = false;
-}
-
-void DolphinTreeView::updateElasticBand()
-{
- if (m_band.show) {
- QRect dirtyRegion(elasticBandRect());
- const QPoint scrollPos(horizontalScrollBar()->value(), verticalScrollBar()->value());
- m_band.destination = viewport()->mapFromGlobal(QCursor::pos()) + scrollPos;
- // Going above the (logical) top-left of the view causes complications during selection;
- // we may as well prevent it.
- if (m_band.destination.y() < 0) {
- m_band.destination.setY(0);
- }
- if (m_band.destination.x() < 0) {
- m_band.destination.setX(0);
- }
- dirtyRegion = dirtyRegion.united(elasticBandRect());
- setDirtyRegion(dirtyRegion);
- }
-}
-
-QRect DolphinTreeView::elasticBandRect() const
-{
- const QPoint scrollPos(horizontalScrollBar()->value(), verticalScrollBar()->value());
-
- const QPoint topLeft = m_band.origin - scrollPos;
- const QPoint bottomRight = m_band.destination - scrollPos;
- return QRect(topLeft, bottomRight).normalized();
-}
-
-bool DolphinTreeView::isAboveExpandingToggle(const QPoint& pos) const
-{
- // QTreeView offers no public API to get the information whether an index has an
- // expanding toggle and what boundaries the toggle has. The following approach
- // also assumes a toggle for file items.
- if (itemsExpandable()) {
- const QModelIndex index = QTreeView::indexAt(pos);
- if (index.isValid() && (index.column() == KDirModel::Name)) {
- QRect rect = visualRect(index);
- const int toggleSize = rect.height();
- if (isRightToLeft()) {
- rect.moveRight(rect.right());
- } else {
- rect.moveLeft(rect.x() - toggleSize);
- }
- rect.setWidth(toggleSize);
-
- QStyleOption opt;
- opt.initFrom(this);
- opt.rect = rect;
- rect = style()->subElementRect(QStyle::SE_TreeViewDisclosureItem, &opt, this);
-
- return rect.contains(pos);
- }
- }
- return false;
-}
-
-DolphinTreeView::ElasticBand::ElasticBand() :
- show(false),
- origin(),
- destination(),
- lastSelectionOrigin(),
- lastSelectionDestination(),
- ignoreOldInfo(true),
- outsideNearestLeftEdge(0),
- outsideNearestRightEdge(0),
- insideNearestLeftEdge(0),
- insideNearestRightEdge(0)
-{
-}
-
-#include "dolphintreeview.moc"
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2010 by Peter Penz <peter.penz19@gmail.com> *
- * Copyright (C) 2008 by Simon St. James <kdedevel@etotheipiplusone.com> *
- * *
- * 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 DOLPHINTREEVIEW_H
-#define DOLPHINTREEVIEW_H
-
-#include <QTreeView>
-#include <libdolphin_export.h>
-
-/**
- * @brief Extends QTreeView by a custom selection- and hover-mechanism.
- *
- * QTreeView does not respect the width of a cell for the hover-feedback
- * and when selecting items. DolphinTreeView improves this by respecting the
- * content-width of the first column. The selection-mechanism also
- * respects the content-width.
- */
-class LIBDOLPHINPRIVATE_EXPORT DolphinTreeView : public QTreeView
-{
- Q_OBJECT
-
-public:
- explicit DolphinTreeView(QWidget* parent = 0);
- virtual ~DolphinTreeView();
-
- virtual QModelIndex indexAt (const QPoint& point) const;
- virtual void keyboardSearch(const QString & search);
- virtual QRegion visualRegionForSelection(const QItemSelection& selection) const;
-
-protected:
- /**
- * @return True, if the item with the index \p index accepts a drop. In this
- * case a visual feedback for the user is given during dragging. Per
- * default false is returned.
- */
- virtual bool acceptsDrop(const QModelIndex& index) const;
-
- virtual bool event(QEvent* event);
- virtual void mousePressEvent(QMouseEvent* event);
- virtual void mouseMoveEvent(QMouseEvent* event);
- virtual void mouseReleaseEvent(QMouseEvent* event);
- virtual void startDrag(Qt::DropActions supportedActions);
- virtual void dragEnterEvent(QDragEnterEvent* event);
- virtual void dragMoveEvent(QDragMoveEvent* event);
- virtual void dragLeaveEvent(QDragLeaveEvent* event);
- virtual void paintEvent(QPaintEvent* event);
- virtual void setSelection(const QRect& rect, QItemSelectionModel::SelectionFlags command);
- virtual void scrollTo(const QModelIndex& index, ScrollHint hint = EnsureVisible);
-
-private slots:
- /**
- * If the elastic band is currently shown, update the elastic band based on
- * the current mouse position and ensure that the selection is the set of items
- * intersecting it.
- */
- void updateElasticBandSelection();
-
- /**
- * Updates the destination \a destination from
- * the elastic band to the current mouse position and triggers
- * an update.
- */
- void updateElasticBand();
-
- /**
- * Returns the rectangle for the elastic band dependent from the
- * origin \a origin, the current destination
- * \a destination and the viewport position.
- */
- QRect elasticBandRect() const;
-
-private:
- /**
- * Returns true, if \a pos is within the expanding toggle of a tree.
- */
- bool isAboveExpandingToggle(const QPoint& pos) const;
-
-private:
- bool m_expandingTogglePressed;
- bool m_useDefaultIndexAt; // true, if QTreeView::indexAt() should be used
- bool m_ignoreScrollTo; // true if calls to scrollTo(...) should do nothing.
-
- QRect m_dropRect;
-
- struct ElasticBand
- {
- ElasticBand();
-
- // Elastic band origin and destination coordinates are relative to t
- // he origin of the view, not the viewport.
- bool show;
- QPoint origin;
- QPoint destination;
-
- // Optimization mechanisms for use with elastic band selection.
- // Basically, allow "incremental" updates to the selection based
- // on the last elastic band shape.
- QPoint lastSelectionOrigin;
- QPoint lastSelectionDestination;
-
- // If true, compute the set of selected elements from scratch (slower)
- bool ignoreOldInfo;
-
- // Edges of the filenames that are closest to the edges of oldSelectionRect.
- // Used to decide whether horizontal changes in the elastic band are likely
- // to require us to re-check which items are selected.
- int outsideNearestLeftEdge;
- int outsideNearestRightEdge;
- int insideNearestLeftEdge;
- int insideNearestRightEdge;
- // The set of items that were selected at the time this band was shown.
- // NOTE: Unless CTRL was pressed when the band was created, this is always empty.
- QItemSelection originalSelection;
- } m_band;
-};
-
-#endif
#include <KFileItem>
#include <KFileItemListProperties>
#include <KLocale>
+#include <kitemviews/kfileitemmodel.h>
+#include <kitemviews/kfileitemlistview.h>
+#include <kitemviews/kitemlistview.h>
+#include <kitemviews/kitemlistcontroller.h>
#include <KIO/DeleteJob>
#include <KIO/NetAccess>
#include <KIO/PreviewJob>
#include "additionalinfoaccessor.h"
#include "dolphindirlister.h"
-#include "dolphinmodel.h"
-#include "dolphincolumnviewcontainer.h"
-#include "dolphinviewcontroller.h"
-#include "dolphindetailsview.h"
-#include "dolphinfileitemdelegate.h"
#include "dolphinnewfilemenuobserver.h"
-#include "dolphinsortfilterproxymodel.h"
#include "dolphin_detailsmodesettings.h"
-#include "dolphiniconsview.h"
#include "dolphin_generalsettings.h"
-#include "draganddrophelper.h"
#include "renamedialog.h"
#include "settings/dolphinsettings.h"
#include "viewmodecontroller.h"
#include "viewproperties.h"
#include "zoomlevelinfo.h"
-#include "dolphindetailsviewexpander.h"
+
+// TODO:
+#include "dolphinitemlistcontainer.h"
+
+namespace {
+ const int MaxModeEnum = DolphinView::CompactView;
+ const int MaxSortingEnum = DolphinView::SortByPath;
+};
DolphinView::DolphinView(const KUrl& url, QWidget* parent) :
QWidget(parent),
m_active(true),
- m_showPreview(false),
- m_storedCategorizedSorting(false),
m_tabsForFiles(false),
- m_isContextMenuOpen(false),
m_assureVisibleCurrentIndex(false),
m_expanderActive(false),
m_isFolderWritable(true),
+ m_url(url),
m_mode(DolphinView::IconsView),
+ m_additionalInfoList(),
m_topLayout(0),
- m_dolphinViewController(0),
- m_viewModeController(0),
- m_viewAccessor(),
+ m_dirLister(0),
+ m_container(0),
m_selectionChangedTimer(0),
m_activeItemUrl(),
m_restoredContentsPosition(),
m_topLayout->setSpacing(0);
m_topLayout->setMargin(0);
- m_dolphinViewController = new DolphinViewController(this);
+ //m_dolphinViewController = new DolphinViewController(this);
- m_viewModeController = new ViewModeController(this);
- m_viewModeController->setUrl(url);
+ //m_viewModeController = new ViewModeController(this);
+ //m_viewModeController->setUrl(url);
- connect(m_viewModeController, SIGNAL(urlChanged(const KUrl&)),
+ /*connect(m_viewModeController, SIGNAL(urlChanged(const KUrl&)),
this, SIGNAL(urlChanged(const KUrl&)));
connect(m_dolphinViewController, SIGNAL(requestContextMenu(const QPoint&, const QList<QAction*>&)),
this, SLOT(updateSortOrder(Qt::SortOrder)));
connect(m_dolphinViewController, SIGNAL(sortFoldersFirstChanged(bool)),
this, SLOT(updateSortFoldersFirst(bool)));
- connect(m_dolphinViewController, SIGNAL(additionalInfoChanged(const KFileItemDelegate::InformationList&)),
- this, SLOT(updateAdditionalInfo(const KFileItemDelegate::InformationList&)));
- connect(m_dolphinViewController, SIGNAL(itemTriggered(const KFileItem&)),
- this, SLOT(triggerItem(const KFileItem&)));
- connect(m_dolphinViewController, SIGNAL(tabRequested(const KUrl&)),
- this, SIGNAL(tabRequested(const KUrl&)));
- connect(m_dolphinViewController, SIGNAL(activated()),
+ connect(m_dolphinViewController, SIGNAL(additionalInfoChanged(const QList<DolphinView::AdditionalInfo>&)),
+ this, SLOT(updateAdditionalInfo(const QList<DolphinView::AdditionalInfo>&)));*/
+ //connect(m_dolphinViewController, SIGNAL(itemTriggered(const KFileItem&)),
+ // this, SLOT(triggerItem(const KFileItem&)));
+ //connect(m_dolphinViewController, SIGNAL(tabRequested(const KUrl&)),
+ // this, SIGNAL(tabRequested(const KUrl&)));
+ /*connect(m_dolphinViewController, SIGNAL(activated()),
this, SLOT(activate()));
connect(m_dolphinViewController, SIGNAL(itemEntered(const KFileItem&)),
this, SLOT(showHoverInformation(const KFileItem&)));
connect(m_dolphinViewController, SIGNAL(viewportEntered()),
this, SLOT(clearHoverInformation()));
connect(m_dolphinViewController, SIGNAL(urlChangeRequested(KUrl)),
- this, SLOT(slotUrlChangeRequested(KUrl)));
+ this, SLOT(slotUrlChangeRequested(KUrl)));*/
// When a new item has been created by the "Create New..." menu, the item should
// get selected and it must be assured that the item will get visible. As the
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(completed()), this, SLOT(slotDirListerCompleted()));
+ connect(m_dirLister, SIGNAL(refreshItems(const QList<QPair<KFileItem,KFileItem>>&)),
+ 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(const QString&)), this, SIGNAL(infoMessage(const QString&)));
+ connect(m_dirLister, SIGNAL(errorMessage(const QString&)), this, SIGNAL(infoMessage(const QString&)));
+ connect(m_dirLister, SIGNAL(percent(int)), this, SIGNAL(pathLoadingProgress(int)));
+ connect(m_dirLister, SIGNAL(urlIsFileError(const KUrl&)), this, SIGNAL(urlIsFileError(const KUrl&)));
+ connect(m_dirLister, SIGNAL(itemsDeleted(const KFileItemList&)), this, SIGNAL(itemCountChanged()));
+
+ m_container = new DolphinItemListContainer(m_dirLister, this);
+ QHash<QByteArray, int> visibleRoles;
+ visibleRoles.insert("name", 0);
+ m_container->setVisibleRoles(visibleRoles);
+
+ KItemListController* controller = m_container->controller();
+ connect(controller, SIGNAL(itemClicked(int, Qt::MouseButton)),
+ this, SLOT(slotItemClicked(int, Qt::MouseButton)));
+ connect(controller, SIGNAL(itemExpansionToggleClicked(int)), this, SLOT(slotItemExpansionToggleClicked(int)));
+
applyViewProperties();
- m_topLayout->addWidget(m_viewAccessor.layoutTarget());
+ m_topLayout->addWidget(m_container);
+
+ loadDirectory(url);
}
DolphinView::~DolphinView()
KUrl DolphinView::url() const
{
- return m_viewModeController->url();
-}
-
-KUrl DolphinView::rootUrl() const
-{
- const KUrl viewUrl = url();
- const KUrl root = m_viewAccessor.rootUrl();
- if (root.isEmpty() || !root.isParentOf(viewUrl)) {
- return viewUrl;
- }
- return root;
+ return m_url;
}
void DolphinView::setActive(bool active)
color.setAlpha(150);
}
- QWidget* viewport = m_viewAccessor.itemView()->viewport();
- QPalette palette;
- palette.setColor(viewport->backgroundRole(), color);
- viewport->setPalette(palette);
+ /*QAbstractItemView* view = m_viewAccessor.itemView();
+ QWidget* viewport = view ? view->viewport() : 0;
+ if (viewport) {
+ QPalette palette;
+ palette.setColor(viewport->backgroundRole(), color);
+ viewport->setPalette(palette);
+ }*/
update();
if (active) {
- m_viewAccessor.itemView()->setFocus();
+ //if (view) {
+ // view->setFocus();
+ //}
emit activated();
emitSelectionChangedSignal();
emit writeStateChanged(m_isFolderWritable);
}
- m_viewModeController->indicateActivationChange(active);
+ //m_viewModeController->indicateActivationChange(active);
}
bool DolphinView::isActive() const
void DolphinView::setMode(Mode mode)
{
- if (mode == m_mode) {
- return; // the wished mode is already set
- }
+ if (mode != m_mode) {
+ ViewProperties props(url());
+ props.setViewMode(mode);
+ props.save();
- const int oldZoomLevel = m_viewModeController->zoomLevel();
- m_mode = mode;
-
- // remember the currently selected items, so that they will
- // be restored after reloading the directory
- m_selectedItems = selectedItems();
-
- const bool hasFocus = m_viewAccessor.itemView()->hasFocus();
- deleteView();
-
- const KUrl viewPropsUrl = rootUrl();
- ViewProperties props(viewPropsUrl);
- props.setViewMode(m_mode);
- createView();
-
- if (hasFocus) {
- m_viewAccessor.itemView()->setFocus();
- }
-
- // the file item delegate has been recreated, apply the current
- // additional information manually
- const KFileItemDelegate::InformationList infoList = props.additionalInfo();
- m_viewAccessor.itemDelegate()->setShowInformation(infoList);
- emit additionalInfoChanged();
-
- // Not all view modes support categorized sorting. Adjust the sorting model
- // if changing the view mode results in a change of the categorized sorting
- // capabilities.
- m_storedCategorizedSorting = props.categorizedSorting();
- const bool categorized = m_storedCategorizedSorting && supportsCategorizedSorting();
- if (categorized != m_viewAccessor.proxyModel()->isCategorizedModel()) {
- m_viewAccessor.proxyModel()->setCategorizedModel(categorized);
- emit categorizedSortingChanged();
+ applyViewProperties();
}
-
- emit modeChanged();
-
- updateZoomLevel(oldZoomLevel);
- loadDirectory(viewPropsUrl);
}
DolphinView::Mode DolphinView::mode() const
return m_mode;
}
-bool DolphinView::showPreview() const
+bool DolphinView::previewsShown() const
{
- return m_showPreview;
+ return m_container->previewsShown();
}
-bool DolphinView::showHiddenFiles() const
+bool DolphinView::hiddenFilesShown() const
{
- return m_viewAccessor.dirLister()->showingDotFiles();
+ return m_dirLister->showingDotFiles();
}
bool DolphinView::categorizedSorting() const
{
- // If all view modes would support categorized sorting, returning
- // m_viewAccessor.proxyModel()->isCategorizedModel() would be the way to go. As
- // currently only the icons view supports caterized sorting, we remember
- // the stored view properties state in m_storedCategorizedSorting and
- // return this state. The application takes care to disable the corresponding
- // checkbox by checking DolphinView::supportsCategorizedSorting() to indicate
- // that this setting is not applied to the current view mode.
- return m_storedCategorizedSorting;
-}
-
-bool DolphinView::supportsCategorizedSorting() const
-{
- return m_viewAccessor.supportsCategorizedSorting();
-}
-
-KFileItem DolphinView::rootItem() const
-{
- return m_viewAccessor.dirLister()->rootItem();
+ return false; //m_storedCategorizedSorting;
}
KFileItemList DolphinView::items() const
{
- return m_viewAccessor.dirLister()->items();
+ return m_dirLister->items();
}
KFileItemList DolphinView::selectedItems() const
{
- KFileItemList itemList;
+ return KFileItemList();
+/* KFileItemList itemList;
const QAbstractItemView* view = m_viewAccessor.itemView();
if (!view) {
return itemList;
}
}
- return itemList;
+ return itemList;*/
}
int DolphinView::selectedItemsCount() const
{
- const QAbstractItemView* view = m_viewAccessor.itemView();
+ return 0;
+ /*const QAbstractItemView* view = m_viewAccessor.itemView();
if (!view) {
return 0;
}
- return view->selectionModel()->selectedIndexes().count();
+ return view->selectionModel()->selectedIndexes().count();*/
}
void DolphinView::markUrlsAsSelected(const QList<KUrl>& urls)
void DolphinView::setItemSelectionEnabled(const QRegExp& pattern, bool enabled)
{
- const QItemSelection matchingIndexes = childrenMatchingPattern(QModelIndex(), pattern);
+ Q_UNUSED(pattern);
+ Q_UNUSED(enabled);
+ /*const QItemSelection matchingIndexes = childrenMatchingPattern(QModelIndex(), pattern);
const QItemSelectionModel::SelectionFlags command = enabled
? QItemSelectionModel::Select
: QItemSelectionModel::Deselect;
- m_viewAccessor.itemView()->selectionModel()->select(matchingIndexes, command);
+ m_viewAccessor.itemView()->selectionModel()->select(matchingIndexes, command);*/
}
void DolphinView::setZoomLevel(int level)
{
- if (level < ZoomLevelInfo::minimumLevel()) {
- level = ZoomLevelInfo::minimumLevel();
- } else if (level > ZoomLevelInfo::maximumLevel()) {
- level = ZoomLevelInfo::maximumLevel();
- }
-
- if (level != zoomLevel()) {
- m_viewModeController->setZoomLevel(level);
- emit zoomLevelChanged(level);
+ const int oldZoomLevel = zoomLevel();
+ m_container->setZoomLevel(level);
+ if (zoomLevel() != oldZoomLevel) {
+ emit zoomLevelChanged(zoomLevel(), oldZoomLevel);
}
}
int DolphinView::zoomLevel() const
{
- return m_viewModeController->zoomLevel();
+ return m_container->zoomLevel();
}
void DolphinView::setSorting(Sorting sorting)
DolphinView::Sorting DolphinView::sorting() const
{
- return m_viewAccessor.proxyModel()->sorting();
+ return DolphinView::SortByName;
+ //return m_viewAccessor.proxyModel()->sorting();
}
void DolphinView::setSortOrder(Qt::SortOrder order)
Qt::SortOrder DolphinView::sortOrder() const
{
- return m_viewAccessor.proxyModel()->sortOrder();
+ return Qt::AscendingOrder; // m_viewAccessor.proxyModel()->sortOrder();
}
void DolphinView::setSortFoldersFirst(bool foldersFirst)
bool DolphinView::sortFoldersFirst() const
{
- return m_viewAccessor.proxyModel()->sortFoldersFirst();
+ return true; // m_viewAccessor.proxyModel()->sortFoldersFirst();
}
-void DolphinView::setAdditionalInfo(KFileItemDelegate::InformationList info)
+void DolphinView::setAdditionalInfoList(const QList<AdditionalInfo>& info)
{
- const KUrl viewPropsUrl = rootUrl();
- ViewProperties props(viewPropsUrl);
- props.setAdditionalInfo(info);
- m_viewAccessor.itemDelegate()->setShowInformation(info);
+ const QList<AdditionalInfo> previousList = info;
- emit additionalInfoChanged();
+ ViewProperties props(url());
+ props.setAdditionalInfoList(info);
- if (m_viewAccessor.reloadOnAdditionalInfoChange()) {
- loadDirectory(viewPropsUrl);
- }
+ m_additionalInfoList = info;
+ applyAdditionalInfoListToView();
+
+ emit additionalInfoListChanged(m_additionalInfoList, previousList);
}
-KFileItemDelegate::InformationList DolphinView::additionalInfo() const
+QList<DolphinView::AdditionalInfo> DolphinView::additionalInfoList() const
{
- return m_viewAccessor.itemDelegate()->showInformation();
+ return m_additionalInfoList;
}
void DolphinView::reload()
void DolphinView::stopLoading()
{
- m_viewAccessor.dirLister()->stop();
+ m_dirLister->stop();
}
void DolphinView::refresh()
{
const bool oldActivationState = m_active;
- const int oldZoomLevel = m_viewModeController->zoomLevel();
+ const int oldZoomLevel = zoomLevel();
m_active = true;
- createView();
applyViewProperties();
reload();
void DolphinView::setNameFilter(const QString& nameFilter)
{
- m_viewModeController->setNameFilter(nameFilter);
+ Q_UNUSED(nameFilter);
+ //m_viewModeController->setNameFilter(nameFilter);
}
QString DolphinView::nameFilter() const
{
- return m_viewModeController->nameFilter();
+ return QString(); //m_viewModeController->nameFilter();
}
void DolphinView::calculateItemCount(int& fileCount,
int& folderCount,
KIO::filesize_t& totalFileSize) const
{
- foreach (const KFileItem& item, m_viewAccessor.dirLister()->items()) {
+ foreach (const KFileItem& item, m_dirLister->items()) {
if (item.isDir()) {
++folderCount;
} else {
QList<QAction*> DolphinView::versionControlActions(const KFileItemList& items) const
{
- return m_dolphinViewController->versionControlActions(items);
+ Q_UNUSED(items);
+ return QList<QAction*>(); //m_dolphinViewController->versionControlActions(items);
}
void DolphinView::setUrl(const KUrl& url)
{
- if (m_viewModeController->url() == url) {
+ if (url == m_url) {
return;
}
- const bool hadSelection = hasSelection();
-
- // The selection model and directory lister might change in the case of the column view:
- disconnectViewAccessor();
+ emit urlAboutToBeChanged(url);
+ const bool hadSelection = hasSelection();
m_newFileNames.clear();
+ m_url = url;
- m_viewModeController->setUrl(url); // emits urlChanged, which we forward
- m_viewAccessor.prepareUrlChange(url);
+ // It is important to clear the items from the model before
+ // applying the view properties, otherwise expensive operations
+ // might be done on the existing items although they get cleared
+ // anyhow afterwards by loadDirectory().
+ fileItemModel()->clear();
applyViewProperties();
-
- // When changing the URL there is no need to keep the version
- // data of the previous URL.
- m_viewAccessor.dirModel()->clearVersionData();
-
- // Reconnect to the (probably) new selection model and directory lister
- connectViewAccessor();
loadDirectory(url);
+ emit urlChanged(url);
if (hadSelection || hasSelection()) {
emitSelectionChangedSignal();
}
void DolphinView::selectAll()
{
- m_viewAccessor.itemView()->selectAll();
+ //m_viewAccessor.itemView()->selectAll();
}
void DolphinView::invertSelection()
{
- // Implementation note: Using selectionModel->select(selection, QItemSelectionModel::Toggle) does not
+/* // Implementation note: Using selectionModel->select(selection, QItemSelectionModel::Toggle) does not
// work, as QItemSelectionModel::hasSelection() provides invalid values in this case. This might be a Qt-issue -
// when changing the implementation with an updated Qt-version don't forget to run the Dolphin-unit-tests that
// verify this usecase.
QItemSelectionModel* selectionModel = m_viewAccessor.itemView()->selectionModel();
selectionModel->select(invertedSelection, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current);
+ */
}
void DolphinView::clearSelection()
{
- m_viewAccessor.itemView()->clearSelection();
+ //m_viewAccessor.itemView()->clearSelection();
}
void DolphinView::renameSelectedItems()
return;
}
- if ((itemCount == 1) && DolphinSettings::instance().generalSettings()->renameInline()) {
+ /*if ((itemCount == 1) && DolphinSettings::instance().generalSettings()->renameInline()) {
const QModelIndex dirIndex = m_viewAccessor.dirModel()->indexForItem(items.first());
const QModelIndex proxyIndex = m_viewAccessor.proxyModel()->mapFromSource(dirIndex);
m_viewAccessor.itemView()->edit(proxyIndex);
- } else {
+ } else {*/
RenameDialog* dialog = new RenameDialog(this, items);
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->show();
dialog->raise();
dialog->activateWindow();
- }
+ //}
// assure that the current index remains visible when KDirLister
// will notify the view about changed items
}
}
-void DolphinView::setShowPreview(bool show)
+void DolphinView::setPreviewsShown(bool show)
{
- if (m_showPreview == show) {
+ if (previewsShown() == show) {
return;
}
- const KUrl viewPropsUrl = rootUrl();
- ViewProperties props(viewPropsUrl);
- props.setShowPreview(show);
-
- m_showPreview = show;
- const int oldZoomLevel = m_viewModeController->zoomLevel();
- emit showPreviewChanged();
+ ViewProperties props(url());
+ props.setPreviewsShown(show);
- // Enabling or disabling the preview might change the icon size of the view.
- // As the view does not emit a signal when the icon size has been changed,
- // the used zoom level of the controller must be adjusted manually:
- updateZoomLevel(oldZoomLevel);
+ m_container->setPreviewsShown(show);
+ emit previewsShownChanged(show);
}
-void DolphinView::setShowHiddenFiles(bool show)
+void DolphinView::setHiddenFilesShown(bool show)
{
- if (m_viewAccessor.dirLister()->showingDotFiles() == show) {
+ if (m_dirLister->showingDotFiles() == show) {
return;
}
m_selectedItems = selectedItems();
- const KUrl viewPropsUrl = rootUrl();
- ViewProperties props(viewPropsUrl);
- props.setShowHiddenFiles(show);
+ ViewProperties props(url());
+ props.setHiddenFilesShown(show);
- m_viewAccessor.dirLister()->setShowingDotFiles(show);
- emit showHiddenFilesChanged();
+ m_dirLister->setShowingDotFiles(show);
+ m_dirLister->emitChanges();
+ emit hiddenFilesShownChanged(show);
}
void DolphinView::setCategorizedSorting(bool categorized)
return;
}
- // setCategorizedSorting(true) may only get invoked
- // if the view supports categorized sorting
- Q_ASSERT(!categorized || supportsCategorizedSorting());
-
- ViewProperties props(rootUrl());
+ ViewProperties props(url());
props.setCategorizedSorting(categorized);
props.save();
- m_storedCategorizedSorting = categorized;
- m_viewAccessor.proxyModel()->setCategorizedModel(categorized);
+ //m_viewAccessor.proxyModel()->setCategorizedModel(categorized);
- emit categorizedSortingChanged();
+ emit categorizedSortingChanged(categorized);
}
void DolphinView::mouseReleaseEvent(QMouseEvent* event)
setActive(true);
}
-bool DolphinView::eventFilter(QObject* watched, QEvent* event)
+void DolphinView::contextMenuEvent(QContextMenuEvent* event)
{
- switch (event->type()) {
- case QEvent::FocusIn:
- if (watched == m_viewAccessor.itemView()) {
- m_dolphinViewController->requestActivation();
- }
- break;
-
- case QEvent::DragEnter:
- if (watched == m_viewAccessor.itemView()->viewport()) {
- setActive(true);
- }
- break;
-
- case QEvent::KeyPress:
- if (watched == m_viewAccessor.itemView()) {
- // clear the selection when Escape has been pressed
- QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
- if (keyEvent->key() == Qt::Key_Escape) {
- clearSelection();
- }
- }
- break;
-
- case QEvent::Wheel:
- if (watched == m_viewAccessor.itemView()->viewport()) {
- // Ctrl+wheel events should cause icon zooming, but not if the left mouse button is pressed
- // (the user is probably trying to scroll during a selection in that case)
- QWheelEvent* wheelEvent = static_cast<QWheelEvent*>(event);
- if (wheelEvent->modifiers() & Qt::ControlModifier && !(wheelEvent->buttons() & Qt::LeftButton)) {
- const int delta = wheelEvent->delta();
- const int level = zoomLevel();
- if (delta > 0) {
- setZoomLevel(level + 1);
- } else if (delta < 0) {
- setZoomLevel(level - 1);
- }
- return true;
- }
- }
- break;
-
- default:
- break;
- }
-
- return QWidget::eventFilter(watched, event);
-}
+ Q_UNUSED(event);
-void DolphinView::showEvent(QShowEvent* event)
-{
- QWidget::showEvent(event);
- if (!event->spontaneous()) {
- loadDirectory(url());
+ const QPoint pos = m_container->mapFromGlobal(QCursor::pos());
+ const KItemListView* view = m_container->controller()->view();
+ if (view->itemAt(pos) < 0) {
+ // Only open the context-menu if the cursor is above the viewport
+ // (the context-menu for items is handled in slotItemClicked())
+ requestContextMenu(KFileItem(), url(), QList<QAction*>());
}
}
setActive(true);
}
-void DolphinView::triggerItem(const KFileItem& item)
+void DolphinView::slotItemClicked(int index, Qt::MouseButton button)
{
- const Qt::KeyboardModifiers modifier = QApplication::keyboardModifiers();
- if ((modifier & Qt::ShiftModifier) || (modifier & Qt::ControlModifier)) {
- // items are selected by the user, hence don't trigger the
- // item specified by 'index'
- return;
- }
+ const KFileItem item = fileItemModel()->fileItem(index);
- // TODO: the m_isContextMenuOpen check is a workaround for Qt-issue 207192
- if (item.isNull() || m_isContextMenuOpen) {
- return;
+ if (button & Qt::LeftButton) {
+ emit itemTriggered(item); // caught by DolphinViewContainer or DolphinPart
+ } else if (button & Qt::MidButton) {
+ if (item.isDir() || isTabsForFilesEnabled()) {
+ emit tabRequested(item.url());
+ }
+ } else if (button & Qt::RightButton) {
+ // TODO: attach customActions for the details-view
+ emit requestContextMenu(item, url(), QList<QAction*>());
}
+}
- emit itemTriggered(item); // caught by DolphinViewContainer or DolphinPart
+void DolphinView::slotItemExpansionToggleClicked(int index)
+{
+ KFileItemModel* model = fileItemModel();
+ const bool expanded = model->isExpanded(index);
+ model->setExpanded(index, !expanded);
}
void DolphinView::slotSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected)
void DolphinView::openContextMenu(const QPoint& pos,
const QList<QAction*>& customActions)
{
+ Q_UNUSED(pos);
KFileItem item;
- const QModelIndex index = m_viewAccessor.itemView()->indexAt(pos);
+ /*QAbstractItemView* view = m_viewAccessor.itemView();
+ QModelIndex index;
+ if (view) {
+ index = view->indexAt(pos);
+ }
+
if (index.isValid() && (index.column() == DolphinModel::Name)) {
const QModelIndex dolphinModelIndex = m_viewAccessor.proxyModel()->mapToSource(index);
item = m_viewAccessor.dirModel()->itemForIndex(dolphinModelIndex);
- }
+ }*/
- m_isContextMenuOpen = true; // TODO: workaround for Qt-issue 207192
emit requestContextMenu(item, url(), customActions);
- m_isContextMenuOpen = false;
}
void DolphinView::dropUrls(const KFileItem& destItem,
const KUrl& destPath,
QDropEvent* event)
{
+ Q_UNUSED(destItem);
+ Q_UNUSED(destPath);
addNewFileNames(event->mimeData());
- DragAndDropHelper::instance().dropUrls(destItem, destPath, event, this);
+ //DragAndDropHelper::instance().dropUrls(destItem, destPath, event, this);
}
void DolphinView::updateSorting(DolphinView::Sorting sorting)
{
- ViewProperties props(rootUrl());
+ ViewProperties props(url());
props.setSorting(sorting);
- m_viewAccessor.proxyModel()->setSorting(sorting);
+ KItemModelBase* model = m_container->controller()->model();
+ model->setSortRole(sortRoleForSorting(sorting));
emit sortingChanged(sorting);
}
void DolphinView::updateSortOrder(Qt::SortOrder order)
{
- ViewProperties props(rootUrl());
+ ViewProperties props(url());
props.setSortOrder(order);
- m_viewAccessor.proxyModel()->setSortOrder(order);
+ //m_viewAccessor.proxyModel()->setSortOrder(order);
emit sortOrderChanged(order);
}
void DolphinView::updateSortFoldersFirst(bool foldersFirst)
{
- ViewProperties props(rootUrl());
+ ViewProperties props(url());
props.setSortFoldersFirst(foldersFirst);
- m_viewAccessor.proxyModel()->setSortFoldersFirst(foldersFirst);
+ //m_viewAccessor.proxyModel()->setSortFoldersFirst(foldersFirst);
emit sortFoldersFirstChanged(foldersFirst);
}
-void DolphinView::updateAdditionalInfo(const KFileItemDelegate::InformationList& info)
-{
- ViewProperties props(rootUrl());
- props.setAdditionalInfo(info);
- props.save();
-
- m_viewAccessor.itemDelegate()->setShowInformation(info);
-
- emit additionalInfoChanged();
-}
-
-void DolphinView::updateAdditionalInfoActions(KActionCollection* collection)
-{
- const AdditionalInfoAccessor& infoAccessor = AdditionalInfoAccessor::instance();
-
- const KFileItemDelegate::InformationList checkedInfo = m_viewAccessor.itemDelegate()->showInformation();
- const KFileItemDelegate::InformationList infoKeys = infoAccessor.keys();
-
- const bool enable = (m_mode == DolphinView::DetailsView) ||
- (m_mode == DolphinView::IconsView);
-
- foreach (const KFileItemDelegate::Information& info, infoKeys) {
- const QString name = infoAccessor.actionCollectionName(info, AdditionalInfoAccessor::AdditionalInfoType);
- QAction* action = collection->action(name);
- Q_ASSERT(action);
- action->setEnabled(enable);
- action->setChecked(checkedInfo.contains(info));
- }
-}
-
QPair<bool, QString> DolphinView::pasteInfo() const
{
return KonqOperations::pasteInfo(url());
bool DolphinView::itemsExpandable() const
{
- return m_viewAccessor.itemsExpandable();
+ return false; //m_viewAccessor.itemsExpandable();
}
void DolphinView::restoreState(QDataStream& stream)
// Restore the URL of the current item that had the keyboard focus
stream >> m_activeItemUrl;
- // Restore the root URL
- KUrl rootUrl;
- stream >> rootUrl;
- m_viewAccessor.setRootUrl(rootUrl);
-
// Restore the view position
stream >> m_restoredContentsPosition;
// Restore expanded folders (only relevant for the details view - will be ignored by the view in other view modes)
QSet<KUrl> urlsToExpand;
stream >> urlsToExpand;
- const DolphinDetailsViewExpander* expander = m_viewAccessor.setExpandedUrls(urlsToExpand);
+ /*const DolphinDetailsViewExpander* expander = m_viewAccessor.setExpandedUrls(urlsToExpand);
if (expander) {
m_expanderActive = true;
connect (expander, SIGNAL(completed()), this, SLOT(slotLoadingCompleted()));
}
else {
m_expanderActive = false;
- }
+ }*/
}
void DolphinView::saveState(QDataStream& stream)
{
// Save the URL of the current item that has the keyboard focus
- KFileItem currentItem;
- const QAbstractItemView* view = m_viewAccessor.itemView();
-
- if (view) {
- const QModelIndex proxyIndex = view->currentIndex();
- const QModelIndex dirModelIndex = m_viewAccessor.proxyModel()->mapToSource(proxyIndex);
- currentItem = m_viewAccessor.dirModel()->itemForIndex(dirModelIndex);
- }
KUrl currentItemUrl;
- if (!currentItem.isNull()) {
- currentItemUrl = currentItem.url();
- }
+ //if (!currentItem.isNull()) {
+ // currentItemUrl = currentItem.url();
+ //}
stream << currentItemUrl;
- // Save the root URL
- stream << m_viewAccessor.rootUrl();
-
// Save view position
- const int x = view->horizontalScrollBar()->value();
- const int y = view->verticalScrollBar()->value();
+ const qreal x = m_container->horizontalScrollBar()->value();
+ const qreal y = m_container->verticalScrollBar()->value();
stream << QPoint(x, y);
+ kDebug() << "saving view state" << QPoint(x, y);
// Save expanded folders (only relevant for the details view - the set will be empty in other view modes)
- stream << m_viewAccessor.expandedUrls();
+ //stream << m_viewAccessor.expandedUrls();
}
bool DolphinView::hasSelection() const
{
- const QAbstractItemView* view = m_viewAccessor.itemView();
- return view && view->selectionModel()->hasSelection();
+ //const QAbstractItemView* view = m_viewAccessor.itemView();
+ //return view && view->selectionModel()->hasSelection();
+ return false;
+}
+
+KFileItem DolphinView::rootItem() const
+{
+ return m_dirLister->rootItem();
}
void DolphinView::observeCreatedItem(const KUrl& url)
{
m_createdItemUrl = url;
- connect(m_viewAccessor.dirModel(), SIGNAL(rowsInserted(const QModelIndex&, int, int)),
- this, SLOT(selectAndScrollToCreatedItem()));
+ //connect(m_dirModel, SIGNAL(rowsInserted(const QModelIndex&, int, int)),
+ // this, SLOT(selectAndScrollToCreatedItem()));
}
void DolphinView::selectAndScrollToCreatedItem()
{
- const QModelIndex dirIndex = m_viewAccessor.dirModel()->indexForUrl(m_createdItemUrl);
+ /*const QModelIndex dirIndex = m_viewAccessor.dirModel()->indexForUrl(m_createdItemUrl);
if (dirIndex.isValid()) {
const QModelIndex proxyIndex = m_viewAccessor.proxyModel()->mapFromSource(dirIndex);
- m_viewAccessor.itemView()->setCurrentIndex(proxyIndex);
+ QAbstractItemView* view = m_viewAccessor.itemView();
+ if (view) {
+ view->setCurrentIndex(proxyIndex);
+ }
}
disconnect(m_viewAccessor.dirModel(), SIGNAL(rowsInserted(const QModelIndex&, int, int)),
- this, SLOT(selectAndScrollToCreatedItem()));
+ this, SLOT(selectAndScrollToCreatedItem()));*/
m_createdItemUrl = KUrl();
}
{
if (oldUrl.equals(url(), KUrl::CompareWithoutTrailingSlash)) {
emit redirection(oldUrl, newUrl);
- m_viewModeController->redirectToUrl(newUrl); // #186947
+ m_url = newUrl; // #186947
}
}
const int y = m_restoredContentsPosition.y();
m_restoredContentsPosition = QPoint();
- QAbstractItemView* view = m_viewAccessor.itemView();
- Q_ASSERT(view);
- view->horizontalScrollBar()->setValue(x);
- view->verticalScrollBar()->setValue(y);
+ m_container->horizontalScrollBar()->setValue(x);
+ m_container->verticalScrollBar()->setValue(y);
}
}
-void DolphinView::slotUrlChangeRequested(const KUrl& url)
+/*void DolphinView::slotUrlChangeRequested(const KUrl& url)
{
m_viewModeController->setUrl(url);
updateWritableState();
-}
+}*/
void DolphinView::showHoverInformation(const KFileItem& item)
{
if (!m_newFileNames.isEmpty()) {
// select all newly added items created by a paste operation or
// a drag & drop operation, and clear the previous selection
- m_viewAccessor.itemView()->clearSelection();
- const int rowCount = m_viewAccessor.proxyModel()->rowCount();
- QItemSelection selection;
- for (int row = 0; row < rowCount; ++row) {
- const QModelIndex proxyIndex = m_viewAccessor.proxyModel()->index(row, 0);
- const QModelIndex dirIndex = m_viewAccessor.proxyModel()->mapToSource(proxyIndex);
- const KUrl url = m_viewAccessor.dirModel()->itemForIndex(dirIndex).url();
- if (m_newFileNames.contains(url.fileName())) {
- selection.merge(QItemSelection(proxyIndex, proxyIndex), QItemSelectionModel::Select);
+ /*QAbstractItemView* view = m_viewAccessor.itemView();
+ if (view) {
+ view->clearSelection();
+ const int rowCount = m_viewAccessor.proxyModel()->rowCount();
+ QItemSelection selection;
+ for (int row = 0; row < rowCount; ++row) {
+ const QModelIndex proxyIndex = m_viewAccessor.proxyModel()->index(row, 0);
+ const QModelIndex dirIndex = m_viewAccessor.proxyModel()->mapToSource(proxyIndex);
+ const KUrl url = m_viewAccessor.dirModel()->itemForIndex(dirIndex).url();
+ if (m_newFileNames.contains(url.fileName())) {
+ selection.merge(QItemSelection(proxyIndex, proxyIndex), QItemSelectionModel::Select);
+ }
}
- }
- m_viewAccessor.itemView()->selectionModel()->select(selection, QItemSelectionModel::Select);
+ view->selectionModel()->select(selection, QItemSelectionModel::Select);
+ }*/
m_newFileNames.clear();
}
if (!m_activeItemUrl.isEmpty()) {
// assure that the current item remains visible
- const QModelIndex dirIndex = m_viewAccessor.dirModel()->indexForUrl(m_activeItemUrl);
+ /*const QModelIndex dirIndex = m_viewAccessor.dirModel()->indexForUrl(m_activeItemUrl);
if (dirIndex.isValid()) {
const QModelIndex proxyIndex = m_viewAccessor.proxyModel()->mapFromSource(dirIndex);
QAbstractItemView* view = m_viewAccessor.itemView();
- const bool clearSelection = !hasSelection();
- view->setCurrentIndex(proxyIndex);
- if (clearSelection) {
- view->clearSelection();
+ if (view) {
+ const bool clearSelection = !hasSelection();
+ view->setCurrentIndex(proxyIndex);
+ if (clearSelection) {
+ view->clearSelection();
+ }
}
m_activeItemUrl.clear();
- }
+ }*/
}
if (!m_selectedItems.isEmpty()) {
- const KUrl& baseUrl = url();
+ /*const KUrl& baseUrl = url();
KUrl url;
QItemSelection newSelection;
foreach(const KFileItem& item, m_selectedItems) {
newSelection.select(index, index);
}
}
- m_viewAccessor.itemView()->selectionModel()->select(newSelection,
+ QAbstractItemView* view = m_viewAccessor.itemView();
+ if (view) {
+ view->selectionModel()->select(newSelection,
QItemSelectionModel::ClearAndSelect
| QItemSelectionModel::Current);
+ }*/
m_selectedItems.clear();
}
// Restore the contents position. This has to be done using a Qt::QueuedConnection
// because the view might not be in its final state yet.
- QMetaObject::invokeMethod(this, "restoreContentsPosition", Qt::QueuedConnection);
+ QTimer::singleShot(0, this, SLOT(restoreContentsPosition()));
emit finishedPathLoading(url());
}
{
if (m_assureVisibleCurrentIndex) {
m_assureVisibleCurrentIndex = false;
- m_viewAccessor.itemView()->scrollTo(m_viewAccessor.itemView()->currentIndex());
+ //QAbstractItemView* view = m_viewAccessor.itemView();
+ //if (view) {
+ // m_viewAccessor.itemView()->scrollTo(m_viewAccessor.itemView()->currentIndex());
+ //}
}
}
+KFileItemModel* DolphinView::fileItemModel() const
+{
+ return static_cast<KFileItemModel*>(m_container->controller()->model());
+}
+
void DolphinView::loadDirectory(const KUrl& url, bool reload)
{
if (!url.isValid()) {
return;
}
- KDirLister* dirLister = m_viewAccessor.dirLister();
- dirLister->openUrl(url, reload ? KDirLister::Reload : KDirLister::NoFlags);
+ m_dirLister->openUrl(url, reload ? KDirLister::Reload : KDirLister::NoFlags);
}
void DolphinView::applyViewProperties()
{
- const ViewProperties props(rootUrl());
+ m_container->beginTransaction();
+
+ const ViewProperties props(url());
const Mode mode = props.viewMode();
if (m_mode != mode) {
- const int oldZoomLevel = m_viewModeController->zoomLevel();
-
+ const Mode previousMode = m_mode;
m_mode = mode;
- createView();
- emit modeChanged();
- updateZoomLevel(oldZoomLevel);
- }
- if (!m_viewAccessor.itemView()) {
- createView();
- }
+ // Changing the mode might result in changing
+ // the zoom level. Remember the old zoom level so
+ // that zoomLevelChanged() can get emitted.
+ const int oldZoomLevel = m_container->zoomLevel();
+
+ switch (m_mode) {
+ case IconsView: m_container->setItemLayout(KFileItemListView::IconsLayout); break;
+ case CompactView: m_container->setItemLayout(KFileItemListView::CompactLayout); break;
+ case DetailsView: m_container->setItemLayout(KFileItemListView::DetailsLayout); break;
+ default: Q_ASSERT(false); break;
+ }
+
+ emit modeChanged(m_mode, previousMode);
- Q_ASSERT(m_viewAccessor.itemView());
- Q_ASSERT(m_viewAccessor.itemDelegate());
+ if (m_container->zoomLevel() != oldZoomLevel) {
+ emit zoomLevelChanged(m_container->zoomLevel(), oldZoomLevel);
+ }
+ }
- const bool showHiddenFiles = props.showHiddenFiles();
- if (showHiddenFiles != m_viewAccessor.dirLister()->showingDotFiles()) {
- m_viewAccessor.dirLister()->setShowingDotFiles(showHiddenFiles);
- emit showHiddenFilesChanged();
+ const bool hiddenFilesShown = props.hiddenFilesShown();
+ if (hiddenFilesShown != m_dirLister->showingDotFiles()) {
+ m_dirLister->setShowingDotFiles(hiddenFilesShown);
+ m_dirLister->emitChanges();
+ emit hiddenFilesShownChanged(hiddenFilesShown);
}
- m_storedCategorizedSorting = props.categorizedSorting();
+/* m_storedCategorizedSorting = props.categorizedSorting();
const bool categorized = m_storedCategorizedSorting && supportsCategorizedSorting();
if (categorized != m_viewAccessor.proxyModel()->isCategorizedModel()) {
m_viewAccessor.proxyModel()->setCategorizedModel(categorized);
emit categorizedSortingChanged();
- }
+ }*/
const DolphinView::Sorting sorting = props.sorting();
- if (sorting != m_viewAccessor.proxyModel()->sorting()) {
- m_viewAccessor.proxyModel()->setSorting(sorting);
+ KItemModelBase* model = m_container->controller()->model();
+ const QByteArray newSortRole = sortRoleForSorting(sorting);
+ if (newSortRole != model->sortRole()) {
+ model->setSortRole(newSortRole);
emit sortingChanged(sorting);
}
-
+/*
const Qt::SortOrder sortOrder = props.sortOrder();
if (sortOrder != m_viewAccessor.proxyModel()->sortOrder()) {
m_viewAccessor.proxyModel()->setSortOrder(sortOrder);
m_viewAccessor.proxyModel()->setSortFoldersFirst(sortFoldersFirst);
emit sortFoldersFirstChanged(sortFoldersFirst);
}
-
- KFileItemDelegate::InformationList info = props.additionalInfo();
- if (info != m_viewAccessor.itemDelegate()->showInformation()) {
- m_viewAccessor.itemDelegate()->setShowInformation(info);
- emit additionalInfoChanged();
- }
-
- const bool showPreview = props.showPreview();
- if (showPreview != m_showPreview) {
- m_showPreview = showPreview;
- const int oldZoomLevel = m_viewModeController->zoomLevel();
- emit showPreviewChanged();
-
- // Enabling or disabling the preview might change the icon size of the view.
- // As the view does not emit a signal when the icon size has been changed,
- // the used zoom level of the controller must be adjusted manually:
- updateZoomLevel(oldZoomLevel);
+*/
+ const QList<DolphinView::AdditionalInfo> infoList = props.additionalInfoList();
+ if (infoList != m_additionalInfoList) {
+ const QList<DolphinView::AdditionalInfo> previousList = m_additionalInfoList;
+ m_additionalInfoList = infoList;
+ applyAdditionalInfoListToView();
+ emit additionalInfoListChanged(m_additionalInfoList, previousList);
}
-}
-
-void DolphinView::createView()
-{
- deleteView();
-
- Q_ASSERT(!m_viewAccessor.itemView());
- Q_ASSERT(!m_dolphinViewController->itemView());
- m_viewAccessor.createView(this, m_dolphinViewController, m_viewModeController, m_mode);
- QAbstractItemView* view = m_viewAccessor.itemView();
- Q_ASSERT(view);
- view->installEventFilter(this);
- view->viewport()->installEventFilter(this);
+ const bool previewsShown = props.previewsShown();
+ if (previewsShown != m_container->previewsShown()) {
+ const int oldZoomLevel = zoomLevel();
- m_dolphinViewController->setItemView(view);
+ m_container->setPreviewsShown(previewsShown);
+ emit previewsShownChanged(previewsShown);
- const int zoomLevel = ZoomLevelInfo::zoomLevelForIconSize(view->iconSize());
- m_viewModeController->setZoomLevel(zoomLevel);
-
- connectViewAccessor();
+ // Changing the preview-state might result in a changed zoom-level
+ if (oldZoomLevel != zoomLevel()) {
+ emit zoomLevelChanged(zoomLevel(), oldZoomLevel);
+ }
+ }
- setFocusProxy(m_viewAccessor.layoutTarget());
- m_topLayout->insertWidget(1, m_viewAccessor.layoutTarget());
+ m_container->endTransaction();
}
-void DolphinView::deleteView()
+void DolphinView::applyAdditionalInfoListToView()
{
- QAbstractItemView* view = m_viewAccessor.itemView();
- Q_ASSERT(!m_dolphinViewController->itemView() || (m_dolphinViewController->itemView() == view));
- m_dolphinViewController->setItemView(0);
-
- if (view) {
- disconnectViewAccessor();
-
- if (hasFocus()) {
- // It's important to set the keyboard focus to the parent
- // before deleting the view: Otherwise when having a split
- // view the other view will get the focus and will request
- // an activation (see DolphinView::eventFilter()).
- setFocusProxy(0);
- setFocus();
- }
+ const AdditionalInfoAccessor& infoAccessor = AdditionalInfoAccessor::instance();
- m_viewModeController->disconnect(view);
+ QHash<QByteArray, int> visibleRoles;
+ visibleRoles.insert("name", 0);
- m_viewAccessor.deleteView();
+ int index = 1;
+ foreach (AdditionalInfo info, m_additionalInfoList) {
+ visibleRoles.insert(infoAccessor.role(info), index);
+ ++index;
}
+
+ m_container->setVisibleRoles(visibleRoles);
}
void DolphinView::pasteToUrl(const KUrl& url)
void DolphinView::updateZoomLevel(int oldZoomLevel)
{
- const int newZoomLevel = ZoomLevelInfo::zoomLevelForIconSize(m_viewAccessor.itemView()->iconSize());
+ Q_UNUSED(oldZoomLevel);
+ /* const int newZoomLevel = ZoomLevelInfo::zoomLevelForIconSize(m_viewAccessor.itemView()->iconSize());
if (oldZoomLevel != newZoomLevel) {
m_viewModeController->setZoomLevel(newZoomLevel);
emit zoomLevelChanged(newZoomLevel);
- }
+ }*/
}
KUrl::List DolphinView::simplifiedSelectedUrls() const
{
+ Q_ASSERT(false); // TODO
KUrl::List urls;
-
+/*
const KFileItemList items = selectedItems();
foreach (const KFileItem &item, items) {
urls.append(item.url());
if (itemsExpandable()) {
urls = KDirModel::simplifiedUrlList(urls);
- }
+ }*/
return urls;
}
QMimeData* DolphinView::selectionMimeData() const
{
- const QAbstractItemView* view = m_viewAccessor.itemView();
+ /*const QAbstractItemView* view = m_viewAccessor.itemView();
Q_ASSERT((view) && (view->selectionModel()));
const QItemSelection selection = m_viewAccessor.proxyModel()->mapSelectionToSource(view->selectionModel()->selection());
- return m_viewAccessor.dirModel()->mimeData(selection.indexes());
+ return m_viewAccessor.dirModel()->mimeData(selection.indexes());*/
+ return 0;
}
void DolphinView::addNewFileNames(const QMimeData* mimeData)
QItemSelection DolphinView::childrenMatchingPattern(const QModelIndex& parent, const QRegExp& pattern) const
{
+ Q_UNUSED(parent);
+ Q_UNUSED(pattern);
QItemSelection matchingIndexes;
- const DolphinSortFilterProxyModel* proxyModel = m_viewAccessor.proxyModel();
+ /*const DolphinSortFilterProxyModel* proxyModel = m_viewAccessor.proxyModel();
const DolphinModel* dolphinModel = m_viewAccessor.dirModel();
const int rowCount = proxyModel->rowCount(parent);
if (proxyModel->hasChildren(index)) {
matchingIndexes += childrenMatchingPattern(index, pattern);
}
- }
+ }*/
return matchingIndexes;
}
-void DolphinView::connectViewAccessor()
-{
- KDirLister* dirLister = m_viewAccessor.dirLister();
- connect(dirLister, SIGNAL(redirection(KUrl,KUrl)), this, SLOT(slotRedirection(KUrl,KUrl)));
- connect(dirLister, SIGNAL(started(KUrl)), this, SLOT(slotDirListerStarted(KUrl)));
- connect(dirLister, SIGNAL(completed()), this, SLOT(slotDirListerCompleted()));
- connect(dirLister, SIGNAL(refreshItems(const QList<QPair<KFileItem,KFileItem>>&)),
- this, SLOT(slotRefreshItems()));
-
- connect(dirLister, SIGNAL(clear()), this, SIGNAL(itemCountChanged()));
- connect(dirLister, SIGNAL(newItems(KFileItemList)), this, SIGNAL(itemCountChanged()));
- connect(dirLister, SIGNAL(infoMessage(const QString&)), this, SIGNAL(infoMessage(const QString&)));
- connect(dirLister, SIGNAL(errorMessage(const QString&)), this, SIGNAL(infoMessage(const QString&)));
- connect(dirLister, SIGNAL(percent(int)), this, SIGNAL(pathLoadingProgress(int)));
- connect(dirLister, SIGNAL(urlIsFileError(const KUrl&)), this, SIGNAL(urlIsFileError(const KUrl&)));
- connect(dirLister, SIGNAL(itemsDeleted(const KFileItemList&)), this, SIGNAL(itemCountChanged()));
-
- QAbstractItemView* view = m_viewAccessor.itemView();
- connect(view->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
- this, SLOT(slotSelectionChanged(QItemSelection, QItemSelection)));
-}
-
-void DolphinView::disconnectViewAccessor()
-{
- KDirLister* dirLister = m_viewAccessor.dirLister();
- disconnect(dirLister, SIGNAL(redirection(KUrl,KUrl)), this, SLOT(slotRedirection(KUrl,KUrl)));
- disconnect(dirLister, SIGNAL(started(KUrl)), this, SLOT(slotDirListerStarted(KUrl)));
- disconnect(dirLister, SIGNAL(completed()), this, SLOT(slotDirListerCompleted()));
- disconnect(dirLister, SIGNAL(refreshItems(const QList<QPair<KFileItem,KFileItem>>&)),
- this, SLOT(slotRefreshItems()));
-
- disconnect(dirLister, SIGNAL(clear()), this, SIGNAL(itemCountChanged()));
- disconnect(dirLister, SIGNAL(newItems(KFileItemList)), this, SIGNAL(itemCountChanged()));
- disconnect(dirLister, SIGNAL(infoMessage(const QString&)), this, SIGNAL(infoMessage(const QString&)));
- disconnect(dirLister, SIGNAL(errorMessage(const QString&)), this, SIGNAL(errorMessage(const QString&)));
- disconnect(dirLister, SIGNAL(percent(int)), this, SIGNAL(pathLoadingProgress(int)));
- disconnect(dirLister, SIGNAL(urlIsFileError(const KUrl&)), this, SIGNAL(urlIsFileError(const KUrl&)));
- disconnect(dirLister, SIGNAL(itemsDeleted(const KFileItemList&)), this, SIGNAL(itemCountChanged()));
-
- QAbstractItemView* view = m_viewAccessor.itemView();
- disconnect(view->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
- this, SLOT(slotSelectionChanged(QItemSelection, QItemSelection)));
-}
-
void DolphinView::updateWritableState()
{
const bool wasFolderWritable = m_isFolderWritable;
m_isFolderWritable = true;
- const KFileItem item = m_viewAccessor.dirLister()->rootItem();
+ const KFileItem item; // = m_viewAccessor.dirLister()->rootItem();
if (!item.isNull()) {
KFileItemListProperties capabilities(KFileItemList() << item);
m_isFolderWritable = capabilities.supportsWriting();
}
}
-DolphinView::ViewAccessor::ViewAccessor() :
- m_rootUrl(),
- m_iconsView(0),
- m_detailsView(0),
- m_columnsContainer(0),
- m_dolphinModel(0),
- m_proxyModel(0),
- m_dragSource(0)
-{
- DolphinDirLister* dirLister = new DolphinDirLister();
- dirLister->setAutoUpdate(true);
- dirLister->setDelayedMimeTypes(true);
-
- m_dolphinModel = new DolphinModel();
- m_dolphinModel->setDirLister(dirLister); // m_dolphinModel takes ownership of dirLister
- m_dolphinModel->setDropsAllowed(DolphinModel::DropOnDirectory);
-
- m_proxyModel = new DolphinSortFilterProxyModel();
- m_proxyModel->setSourceModel(m_dolphinModel);
- m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
-}
-
-DolphinView::ViewAccessor::~ViewAccessor()
-{
- delete m_proxyModel;
- m_proxyModel = 0;
-
- delete m_dolphinModel;
- m_dolphinModel = 0;
-
- delete m_dragSource;
- m_dragSource = 0;
-}
-
-void DolphinView::ViewAccessor::createView(QWidget* parent,
- DolphinViewController* dolphinViewController,
- const ViewModeController* viewModeController,
- Mode mode)
-{
- Q_ASSERT(!itemView());
-
- switch (mode) {
- case IconsView:
- m_iconsView = new DolphinIconsView(parent,
- dolphinViewController,
- viewModeController,
- m_proxyModel);
- break;
-
- case DetailsView:
- m_detailsView = new DolphinDetailsView(parent,
- dolphinViewController,
- viewModeController,
- m_proxyModel);
- break;
-
- case ColumnView:
- m_columnsContainer = new DolphinColumnViewContainer(parent,
- dolphinViewController,
- viewModeController);
- if (!m_rootUrl.isEmpty() && m_rootUrl.isParentOf(viewModeController->url())) {
- // The column-view must show several columns starting with m_rootUrl as
- // first column and viewModeController->url() as last column.
- m_columnsContainer->showColumn(m_rootUrl);
- m_columnsContainer->showColumn(viewModeController->url());
- }
- break;
-
- default:
- Q_ASSERT(false);
- }
-
- KDirLister* lister = dirLister();
- if (lister) {
- lister->setMainWindow(parent->window());
- }
-}
-
-void DolphinView::ViewAccessor::deleteView()
-{
- if (m_columnsContainer) {
- m_columnsContainer->close();
- m_columnsContainer->disconnect();
- m_columnsContainer->deleteLater();
- m_columnsContainer = 0;
- } else {
- QAbstractItemView* view = itemView();
- if (view) {
- view->close();
- view->disconnect();
-
- if (DragAndDropHelper::instance().isDragSource(view)) {
- // The view is a drag source (the feature "Open folders
- // during drag operations" is used). Deleting the view
- // during an ongoing drag operation is not allowed, so
- // this will postponed.
- if (m_dragSource) {
- // the old stored view is obviously not the drag source anymore
- m_dragSource->deleteLater();
- m_dragSource = 0;
- }
- view->hide();
- m_dragSource = view;
- } else {
- view->deleteLater();
- view = 0;
- }
- }
-
- m_iconsView = 0;
- m_detailsView = 0;
- }
-}
-
-void DolphinView::ViewAccessor::prepareUrlChange(const KUrl& url)
-{
- if (m_columnsContainer) {
- m_columnsContainer->showColumn(url);
- }
-}
-
-QAbstractItemView* DolphinView::ViewAccessor::itemView() const
-{
- if (m_iconsView) {
- return m_iconsView;
- }
-
- if (m_detailsView) {
- return m_detailsView;
- }
-
- if (m_columnsContainer) {
- return m_columnsContainer->activeColumn();
- }
-
- return 0;
-}
-
-KFileItemDelegate* DolphinView::ViewAccessor::itemDelegate() const
-{
- return static_cast<KFileItemDelegate*>(itemView()->itemDelegate());
-}
-
-QWidget* DolphinView::ViewAccessor::layoutTarget() const
+QByteArray DolphinView::sortRoleForSorting(Sorting sorting) const
{
- if (m_columnsContainer) {
- return m_columnsContainer;
+ switch (sorting) {
+ case SortByName: return "name";
+ case SortBySize: return "size";
+ case SortByDate: return "date";
+ case SortByPermissions: return "permissions";
+ case SortByOwner: return "owner";
+ case SortByGroup: return "group";
+ case SortByType: return "type";
+ case SortByDestination: return "destination";
+ case SortByPath: return "path";
+ default: break;
}
- return itemView();
-}
-
-void DolphinView::ViewAccessor::setRootUrl(const KUrl& rootUrl)
-{
- m_rootUrl = rootUrl;
-}
-
-KUrl DolphinView::ViewAccessor::rootUrl() const
-{
- return m_columnsContainer ? m_columnsContainer->rootUrl() : m_rootUrl;
-}
-bool DolphinView::ViewAccessor::supportsCategorizedSorting() const
-{
- return m_iconsView != 0;
-}
-
-bool DolphinView::ViewAccessor::itemsExpandable() const
-{
- return m_detailsView && m_detailsView->itemsExpandable();
-}
-
-QSet<KUrl> DolphinView::ViewAccessor::expandedUrls() const
-{
- if (m_detailsView) {
- return m_detailsView->expandedUrls();
- }
-
- return QSet<KUrl>();
-}
-
-const DolphinDetailsViewExpander* DolphinView::ViewAccessor::setExpandedUrls(const QSet<KUrl>& urlsToExpand)
-{
- if (m_detailsView && m_detailsView->itemsExpandable() && !urlsToExpand.isEmpty()) {
- // Check if another expander is already active and stop it if necessary.
- if(!m_detailsViewExpander.isNull()) {
- m_detailsViewExpander->stop();
- }
-
- m_detailsViewExpander = new DolphinDetailsViewExpander(m_detailsView, urlsToExpand);
- return m_detailsViewExpander;
- }
- else {
- return 0;
- }
-}
-
-bool DolphinView::ViewAccessor::reloadOnAdditionalInfoChange() const
-{
- // the details view requires no reloading of the directory, as it maps
- // the file item delegate info to its columns internally
- return m_detailsView != 0;
-}
-
-DolphinModel* DolphinView::ViewAccessor::dirModel() const
-{
- return static_cast<DolphinModel*>(proxyModel()->sourceModel());
-}
-
-DolphinSortFilterProxyModel* DolphinView::ViewAccessor::proxyModel() const
-{
- if (m_columnsContainer) {
- return static_cast<DolphinSortFilterProxyModel*>(m_columnsContainer->activeColumn()->model());
- }
- return m_proxyModel;
-}
-
-KDirLister* DolphinView::ViewAccessor::dirLister() const
-{
- return dirModel()->dirLister();
+ return QByteArray();
}
#include "dolphinview.moc"
typedef KIO::FileUndoManager::CommandType CommandType;
-class DolphinColumnViewContainer;
-class DolphinDetailsView;
-class DolphinDetailsViewExpander;
-class DolphinIconsView;
-class DolphinModel;
-class DolphinSortFilterProxyModel;
-class DolphinViewController;
+class DolphinDirLister;
+class DolphinItemListContainer;
class KAction;
class KActionCollection;
-class KDirLister;
+class KFileItemModel;
class KUrl;
-class ViewModeController;
class ViewProperties;
class QRegExp;
/**
* @short Represents a view for the directory content.
*
- * View modes for icons, details and columns are supported. It's
+ * View modes for icons, compact and details are supported. It's
* possible to adjust:
* - sort order
* - sort type
* - show hidden files
* - show previews
- *
- * @see DolphinIconsView
- * @see DolphinDetailsView
- * @see DolphinColumnView
+ * - enable grouping
*/
class LIBDOLPHINPRIVATE_EXPORT DolphinView : public QWidget
{
public:
/**
- * Defines the view mode for a directory. The view mode
- * can be defined when constructing a DolphinView. The
+ * Defines the view mode for a directory. The
* view mode is automatically updated if the directory itself
* defines a view mode (see class ViewProperties for details).
*/
enum Mode
{
/**
- * The directory items are shown as icons including an
- * icon name.
+ * The items are shown as icons with a name-label below.
*/
IconsView = 0,
/**
- * The icon, the name and at least the size of the directory
- * items are shown in a table. It is possible to add columns
- * for date, group and permissions.
+ * The icon, the name and the size of the items are
+ * shown per default as a table.
*/
DetailsView = 1,
/**
- * Each folder is shown in a separate column.
+ * The items are shown as icons with the name-label aligned
+ * to the right side.
*/
- ColumnView = 2,
- MaxModeEnum = ColumnView
+ CompactView = 3
};
/** Defines the sort order for the items of a directory. */
SortByGroup,
SortByType,
SortByDestination,
- SortByPath,
- MaxSortingEnum = SortByPath
+ SortByPath
+ };
+
+ /** Defines the additional information shown for the items of a directory. */
+ enum AdditionalInfo
+ {
+ NoInfo = 0,
+ NameInfo,
+ SizeInfo,
+ DateInfo,
+ PermissionsInfo,
+ OwnerInfo,
+ GroupInfo,
+ TypeInfo,
+ DestinationInfo,
+ PathInfo
};
/**
* @param url Specifies the content which should be shown.
* @param parent Parent widget of the view.
*/
- DolphinView( const KUrl& url, QWidget* parent);
+ DolphinView(const KUrl& url, QWidget* parent);
virtual ~DolphinView();
*/
KUrl url() const;
- /**
- * Returns the root URL of the view, which is defined as the first
- * visible path of DolphinView::url(). Usually the root URL is
- * equal to DolphinView::url(), but in the case of the column view
- * when 2 columns are shown, the root URL might be:
- * /home/peter/Documents
- * and DolphinView::url() might return
- * /home/peter/Documents/Music/
- */
- KUrl rootUrl() const;
-
/**
* If \a active is true, the view will marked as active. The active
* view is defined as view where all actions are applied to.
void setMode(Mode mode);
Mode mode() const;
- /** See setShowPreview */
- bool showPreview() const;
+ /** See setPreviewsShown */
+ bool previewsShown() const;
/** See setShowHiddenFiles */
- bool showHiddenFiles() const;
+ bool hiddenFilesShown() const;
/** See setCategorizedSorting */
bool categorizedSorting() const;
- /**
- * Returns true, if the categorized sorting is supported by the current
- * used mode (see DolphinView::setMode()). Currently only DolphinView::IconsView
- * supports categorizations. To check whether the categorized
- * sorting is set, use DolphinView::categorizedSorting().
- */
- bool supportsCategorizedSorting() const;
-
- /**
- * Returns the root item which represents the current URL. Note that the returned
- * item can be null (KFileItem::isNull() will return true) in case that the directory
- * has not been loaded.
- */
- KFileItem rootItem() const;
-
/**
* Returns the items of the view.
*/
bool sortFoldersFirst() const;
/** Sets the additional information which should be shown for the items. */
- void setAdditionalInfo(KFileItemDelegate::InformationList info);
+ void setAdditionalInfoList(const QList<AdditionalInfo>& info);
/** Returns the additional information which should be shown for the items. */
- KFileItemDelegate::InformationList additionalInfo() const;
+ QList<AdditionalInfo> additionalInfoList() const;
/** Reloads the current directory. */
void reload();
*/
QList<QAction*> versionControlActions(const KFileItemList& items) const;
- /**
- * Updates the state of the 'Additional Information' actions in \a collection.
- */
- void updateAdditionalInfoActions(KActionCollection* collection);
-
/**
* Returns the state of the paste action:
* first is whether the action should be enabled
/** Returns true, if at least one item is selected. */
bool hasSelection() const;
+ /**
+ * Returns the root item which represents the current URL. Note that the returned
+ * item can be null (KFileItem::isNull() will return true) in case that the directory
+ * has not been loaded.
+ */
+ KFileItem rootItem() const;
+
public slots:
/**
* Changes the directory to \a url. If the current directory is equal to
* (GeneralSettings::globalViewProps() returns false), then the
* preview setting will be stored automatically.
*/
- void setShowPreview(bool show);
+ void setPreviewsShown(bool show);
/**
* Shows all hidden files of the current directory,
* (GeneralSettings::globalViewProps() returns false), then the
* show hidden file setting will be stored automatically.
*/
- void setShowHiddenFiles(bool show);
+ void setHiddenFilesShown(bool show);
/**
* Summarizes all sorted items by their category \a categorized
*/
void activated();
+ /**
+ * Is emitted if the URL of the view will be changed to \a url.
+ * After the URL has been changed the signal urlChanged() will
+ * be emitted.
+ */
+ void urlAboutToBeChanged(const KUrl& url);
+
/** Is emitted if URL of the view has been changed to \a url. */
void urlChanged(const KUrl& url);
* Is emitted if the view mode (IconsView, DetailsView,
* PreviewsView) has been changed.
*/
- void modeChanged();
+ void modeChanged(Mode current, Mode previous);
/** Is emitted if the 'show preview' property has been changed. */
- void showPreviewChanged();
+ void previewsShownChanged(bool shown);
/** Is emitted if the 'show hidden files' property has been changed. */
- void showHiddenFilesChanged();
+ void hiddenFilesShownChanged(bool shown);
/** Is emitted if the 'categorized sorting' property has been changed. */
- void categorizedSortingChanged();
+ void categorizedSortingChanged(bool sortCategorized);
/** Is emitted if the sorting by name, size or date has been changed. */
void sortingChanged(DolphinView::Sorting sorting);
void sortFoldersFirstChanged(bool foldersFirst);
/** Is emitted if the additional information shown for this view has been changed. */
- void additionalInfoChanged();
+ void additionalInfoListChanged(const QList<DolphinView::AdditionalInfo>& current,
+ const QList<DolphinView::AdditionalInfo>& previous);
/** Is emitted if the zoom level has been changed by zooming in or out. */
- void zoomLevelChanged(int level);
+ void zoomLevelChanged(int current, int previous);
/**
* Is emitted if information of an item is requested to be shown e. g. in the panel.
void writeStateChanged(bool isFolderWritable);
protected:
- /** @see QWidget::mouseReleaseEvent */
virtual void mouseReleaseEvent(QMouseEvent* event);
- virtual bool eventFilter(QObject* watched, QEvent* event);
- virtual void showEvent(QShowEvent* event);
+ virtual void contextMenuEvent(QContextMenuEvent* event);
private slots:
/**
*/
void activate();
- /**
- * If the item \a item is a directory, then this
- * directory will be loaded. If the item is a file, the corresponding
- * application will get started.
- */
- void triggerItem(const KFileItem& index);
+ void slotItemClicked(int index, Qt::MouseButton button);
+
+ void slotItemExpansionToggleClicked(int index);
/**
* Emits the signal \a selectionChanged() with a small delay. This is
*/
void updateSortFoldersFirst(bool foldersFirst);
- /**
- * Updates the view properties of the current URL to the
- * additional information given by \a info.
- */
- void updateAdditionalInfo(const KFileItemDelegate::InformationList& info);
-
/**
* Updates the status bar to show hover information for the
* item \a item. If currently other items are selected,
*/
void restoreContentsPosition();
- void slotUrlChangeRequested(const KUrl& url);
+ //void slotUrlChangeRequested(const KUrl& url);
private:
+ KFileItemModel* fileItemModel() const;
+
void loadDirectory(const KUrl& url, bool reload = false);
/**
*/
void applyViewProperties();
- /**
- * Creates a new view representing the given view mode (DolphinView::mode()).
- * The current view will get deleted.
- */
- void createView();
-
- void deleteView();
+ void applyAdditionalInfoListToView();
/**
* Helper method for DolphinView::paste() and DolphinView::pasteIntoFolder().
*/
QItemSelection childrenMatchingPattern(const QModelIndex& parent, const QRegExp& pattern) const;
- void connectViewAccessor();
- void disconnectViewAccessor();
-
/**
* Updates m_isFolderWritable dependent on whether the folder represented by
* the current URL is writable. If the state has changed, the signal
*/
void updateWritableState();
-private:
- /**
- * Abstracts the access to the different view implementations
- * for icons-, details- and column-view.
- */
- class ViewAccessor
- {
- public:
- ViewAccessor();
- ~ViewAccessor();
-
- void createView(QWidget* parent,
- DolphinViewController* dolphinViewController,
- const ViewModeController* viewModeController,
- Mode mode);
- void deleteView();
-
- /**
- * Must be invoked before the URL has been changed and allows view implementations
- * like the column view to create a new column.
- */
- void prepareUrlChange(const KUrl& url);
-
- QAbstractItemView* itemView() const;
- KFileItemDelegate* itemDelegate() const;
-
- /**
- * Returns the widget that should be added to the layout as target. Usually
- * the item view itself is returned, but in the case of the column view
- * a container widget is returned.
- */
- QWidget* layoutTarget() const;
-
- void setRootUrl(const KUrl& rootUrl);
- KUrl rootUrl() const;
-
- bool supportsCategorizedSorting() const;
- bool itemsExpandable() const;
- QSet<KUrl> expandedUrls() const;
- const DolphinDetailsViewExpander* setExpandedUrls(const QSet<KUrl>& urlsToExpand);
-
- /**
- * Returns true, if a reloading of the items is required
- * when the additional information properties have been changed
- * by the user.
- */
- bool reloadOnAdditionalInfoChange() const;
-
- DolphinModel* dirModel() const;
- DolphinSortFilterProxyModel* proxyModel() const;
- KDirLister* dirLister() const;
-
- private:
- KUrl m_rootUrl;
- DolphinIconsView* m_iconsView;
- DolphinDetailsView* m_detailsView;
- DolphinColumnViewContainer* m_columnsContainer;
- DolphinModel* m_dolphinModel;
- DolphinSortFilterProxyModel* m_proxyModel;
- QAbstractItemView* m_dragSource;
- QPointer<DolphinDetailsViewExpander> m_detailsViewExpander;
-
- // For unit tests
- friend class DolphinDetailsViewTest;
- };
+ QByteArray sortRoleForSorting(Sorting sorting) const;
+private:
bool m_active : 1;
- bool m_showPreview : 1;
- bool m_storedCategorizedSorting : 1;
bool m_tabsForFiles : 1;
- bool m_isContextMenuOpen : 1; // TODO: workaround for Qt-issue 207192
bool m_assureVisibleCurrentIndex : 1;
bool m_expanderActive : 1;
bool m_isFolderWritable : 1;
+ KUrl m_url;
Mode m_mode;
+ QList<AdditionalInfo> m_additionalInfoList;
QVBoxLayout* m_topLayout;
- DolphinViewController* m_dolphinViewController;
- ViewModeController* m_viewModeController;
- ViewAccessor m_viewAccessor;
+ DolphinDirLister* m_dirLister;
+ DolphinItemListContainer* m_container;
QTimer* m_selectionChangedTimer;
#include <KRun>
#include <KPropertiesDialog>
+#include <KDebug>
+
DolphinViewActionHandler::DolphinViewActionHandler(KActionCollection* collection, QObject* parent)
: QObject(parent),
m_actionCollection(collection),
{
Q_ASSERT(view);
- if (m_currentView)
+ if (m_currentView) {
disconnect(m_currentView, 0, this, 0);
+ }
m_currentView = view;
- connect(view, SIGNAL(modeChanged()),
+ connect(view, SIGNAL(modeChanged(DolphinView::Mode, DolphinView::Mode)),
this, SLOT(updateViewActions()));
- connect(view, SIGNAL(showPreviewChanged()),
- this, SLOT(slotShowPreviewChanged()));
+ connect(view, SIGNAL(previewsShownChanged(bool)),
+ this, SLOT(slotPreviewsShownChanged(bool)));
connect(view, SIGNAL(sortOrderChanged(Qt::SortOrder)),
this, SLOT(slotSortOrderChanged(Qt::SortOrder)));
connect(view, SIGNAL(sortFoldersFirstChanged(bool)),
this, SLOT(slotSortFoldersFirstChanged(bool)));
- connect(view, SIGNAL(additionalInfoChanged()),
- this, SLOT(slotAdditionalInfoChanged()));
- connect(view, SIGNAL(categorizedSortingChanged()),
- this, SLOT(slotCategorizedSortingChanged()));
- connect(view, SIGNAL(showHiddenFilesChanged()),
- this, SLOT(slotShowHiddenFilesChanged()));
+ connect(view, SIGNAL(additionalInfoListChanged(QList<DolphinView::AdditionalInfo>,
+ QList<DolphinView::AdditionalInfo>)),
+ this, SLOT(slotAdditionalInfoListChanged(QList<DolphinView::AdditionalInfo>,
+ QList<DolphinView::AdditionalInfo>)));
+ connect(view, SIGNAL(categorizedSortingChanged(bool)),
+ this, SLOT(slotCategorizedSortingChanged(bool)));
+ connect(view, SIGNAL(hiddenFilesShownChanged(bool)),
+ this, SLOT(slotHiddenFilesShownChanged(bool)));
connect(view, SIGNAL(sortingChanged(DolphinView::Sorting)),
this, SLOT(slotSortingChanged(DolphinView::Sorting)));
- connect(view, SIGNAL(zoomLevelChanged(int)),
- this, SLOT(slotZoomLevelChanged(int)));
+ connect(view, SIGNAL(zoomLevelChanged(int, int)),
+ this, SLOT(slotZoomLevelChanged(int, int)));
}
DolphinView* DolphinViewActionHandler::currentView()
// View menu
KToggleAction* iconsAction = iconsModeAction();
+ KToggleAction* compactAction = compactModeAction();
KToggleAction* detailsAction = detailsModeAction();
- KToggleAction* columnsAction = columnsModeAction();
KSelectAction* viewModeActions = m_actionCollection->add<KSelectAction>("view_mode");
viewModeActions->setText(i18nc("@action:intoolbar", "View Mode"));
viewModeActions->addAction(iconsAction);
+ viewModeActions->addAction(compactAction);
viewModeActions->addAction(detailsAction);
- viewModeActions->addAction(columnsAction);
viewModeActions->setToolBarMode(KSelectAction::MenuMode);
connect(viewModeActions, SIGNAL(triggered(QAction*)), this, SLOT(slotViewModeActionTriggered(QAction*)));
const AdditionalInfoAccessor& infoAccessor = AdditionalInfoAccessor::instance();
- const KFileItemDelegate::InformationList infoKeys = infoAccessor.keys();
- foreach (KFileItemDelegate::Information info, infoKeys) {
+ const QList<DolphinView::AdditionalInfo> infoList = infoAccessor.keys();
+ foreach (DolphinView::AdditionalInfo info, infoList) {
const QString name = infoAccessor.actionCollectionName(info, AdditionalInfoAccessor::AdditionalInfoType);
KToggleAction* action = m_actionCollection->add<KToggleAction>(name);
action->setText(infoAccessor.translation(info));
sortByActionGroup->addAction(sortByName);
const AdditionalInfoAccessor& infoAccessor = AdditionalInfoAccessor::instance();
- const KFileItemDelegate::InformationList infoKeys = infoAccessor.keys();
- foreach (KFileItemDelegate::Information info, infoKeys) {
+ const QList<DolphinView::AdditionalInfo> infoList = infoAccessor.keys();
+ foreach (DolphinView::AdditionalInfo info, infoList) {
const QString name = infoAccessor.actionCollectionName(info, AdditionalInfoAccessor::SortByType);
KToggleAction* action = m_actionCollection->add<KToggleAction>(name);
action->setText(infoAccessor.translation(info));
void DolphinViewActionHandler::togglePreview(bool show)
{
emit actionBeingHandled();
- m_currentView->setShowPreview(show);
+ m_currentView->setPreviewsShown(show);
}
-void DolphinViewActionHandler::slotShowPreviewChanged()
+void DolphinViewActionHandler::slotPreviewsShownChanged(bool shown)
{
+ Q_UNUSED(shown);
// It is not enough to update the 'Show Preview' action, also
// the 'Zoom In' and 'Zoom Out' actions must be adapted.
updateViewActions();
return "icons";
case DolphinView::DetailsView:
return "details";
- case DolphinView::ColumnView:
- return "columns";
+ case DolphinView::CompactView:
+ return "compact";
}
return QString(); // can't happen
}
}
QAction* showPreviewAction = m_actionCollection->action("show_preview");
- showPreviewAction->setChecked(m_currentView->showPreview());
+ showPreviewAction->setChecked(m_currentView->previewsShown());
slotSortOrderChanged(m_currentView->sortOrder());
slotSortFoldersFirstChanged(m_currentView->sortFoldersFirst());
- slotAdditionalInfoChanged();
- slotCategorizedSortingChanged();
+ slotAdditionalInfoListChanged(m_currentView->additionalInfoList(), QList<DolphinView::AdditionalInfo>());
+ slotCategorizedSortingChanged(m_currentView->categorizedSorting());
slotSortingChanged(m_currentView->sorting());
- slotZoomLevelChanged(m_currentView->zoomLevel());
+ slotZoomLevelChanged(m_currentView->zoomLevel(), -1);
QAction* showHiddenFilesAction = m_actionCollection->action("show_hidden_files");
- showHiddenFilesAction->setChecked(m_currentView->showHiddenFiles());
+ showHiddenFilesAction->setChecked(m_currentView->hiddenFilesShown());
}
void DolphinViewActionHandler::zoomIn()
{
emit actionBeingHandled();
- const KFileItemDelegate::Information info =
- static_cast<KFileItemDelegate::Information>(action->data().toInt());
+ const DolphinView::AdditionalInfo info =
+ static_cast<DolphinView::AdditionalInfo>(action->data().toInt());
- KFileItemDelegate::InformationList list = m_currentView->additionalInfo();
+ QList<DolphinView::AdditionalInfo> list = m_currentView->additionalInfoList();
const bool show = action->isChecked();
const bool containsInfo = (index >= 0);
if (show && !containsInfo) {
list.append(info);
- m_currentView->setAdditionalInfo(list);
+ m_currentView->setAdditionalInfoList(list);
} else if (!show && containsInfo) {
list.removeAt(index);
- m_currentView->setAdditionalInfo(list);
+ m_currentView->setAdditionalInfoList(list);
Q_ASSERT(list.indexOf(info) < 0);
}
}
-void DolphinViewActionHandler::slotAdditionalInfoChanged()
+void DolphinViewActionHandler::slotAdditionalInfoListChanged(const QList<DolphinView::AdditionalInfo>& current,
+ const QList<DolphinView::AdditionalInfo>& previous)
{
- m_currentView->updateAdditionalInfoActions(m_actionCollection);
+ Q_UNUSED(previous);
+
+ const AdditionalInfoAccessor& infoAccessor = AdditionalInfoAccessor::instance();
+
+ const QList<DolphinView::AdditionalInfo> checkedInfo = current;
+ const QList<DolphinView::AdditionalInfo> infoList = infoAccessor.keys();
+
+ foreach (DolphinView::AdditionalInfo info, infoList) {
+ const QString name = infoAccessor.actionCollectionName(info, AdditionalInfoAccessor::AdditionalInfoType);
+ QAction* action = m_actionCollection->action(name);
+ Q_ASSERT(action);
+ action->setChecked(checkedInfo.contains(info));
+ }
}
void DolphinViewActionHandler::toggleSortCategorization(bool categorizedSorting)
m_currentView->setCategorizedSorting(categorizedSorting);
}
-void DolphinViewActionHandler::slotCategorizedSortingChanged()
+void DolphinViewActionHandler::slotCategorizedSortingChanged(bool sortCategorized)
{
QAction* showInGroupsAction = m_actionCollection->action("show_in_groups");
- showInGroupsAction->setChecked(m_currentView->categorizedSorting());
- showInGroupsAction->setEnabled(m_currentView->supportsCategorizedSorting());
+ showInGroupsAction->setChecked(sortCategorized);
}
void DolphinViewActionHandler::toggleShowHiddenFiles(bool show)
{
emit actionBeingHandled();
- m_currentView->setShowHiddenFiles(show);
+ m_currentView->setHiddenFilesShown(show);
}
-void DolphinViewActionHandler::slotShowHiddenFilesChanged()
+void DolphinViewActionHandler::slotHiddenFilesShownChanged(bool shown)
{
QAction* showHiddenFilesAction = m_actionCollection->action("show_hidden_files");
- showHiddenFilesAction->setChecked(m_currentView->showHiddenFiles());
+ showHiddenFilesAction->setChecked(shown);
}
return iconsView;
}
+KToggleAction* DolphinViewActionHandler::compactModeAction()
+{
+ KToggleAction* iconsView = m_actionCollection->add<KToggleAction>("compact");
+ iconsView->setText(i18nc("@action:inmenu View Mode", "Compact"));
+ iconsView->setToolTip(i18nc("@info", "Compact view mode"));
+ iconsView->setShortcut(Qt::CTRL | Qt::Key_2);
+ iconsView->setIcon(KIcon("view-list-details")); // TODO: discuss with Oxygen-team the wrong (?) name
+ iconsView->setData(QVariant::fromValue(DolphinView::CompactView));
+ return iconsView;
+}
+
KToggleAction* DolphinViewActionHandler::detailsModeAction()
{
KToggleAction* detailsView = m_actionCollection->add<KToggleAction>("details");
detailsView->setText(i18nc("@action:inmenu View Mode", "Details"));
detailsView->setToolTip(i18nc("@info", "Details view mode"));
- detailsView->setShortcut(Qt::CTRL | Qt::Key_2);
- detailsView->setIcon(KIcon("view-list-details"));
+ detailsView->setShortcut(Qt::CTRL | Qt::Key_3);
+ detailsView->setIcon(KIcon("view-list-text"));
detailsView->setData(QVariant::fromValue(DolphinView::DetailsView));
return detailsView;
}
-KToggleAction* DolphinViewActionHandler::columnsModeAction()
-{
- KToggleAction* columnView = m_actionCollection->add<KToggleAction>("columns");
- columnView->setText(i18nc("@action:inmenu View Mode", "Columns"));
- columnView->setToolTip(i18nc("@info", "Columns view mode"));
- columnView->setShortcut(Qt::CTRL | Qt::Key_3);
- columnView->setIcon(KIcon("view-file-columns"));
- columnView->setData(QVariant::fromValue(DolphinView::ColumnView));
- return columnView;
-}
-
void DolphinViewActionHandler::slotSortingChanged(DolphinView::Sorting sorting)
{
QAction* action = 0;
action = m_actionCollection->action("sort_by_name");
} else {
const AdditionalInfoAccessor& infoAccessor = AdditionalInfoAccessor::instance();
- const KFileItemDelegate::InformationList infoKeys = infoAccessor.keys();
- foreach (const KFileItemDelegate::Information info, infoKeys) {
+ const QList<DolphinView::AdditionalInfo> infoList = infoAccessor.keys();
+ foreach (DolphinView::AdditionalInfo info, infoList) {
if (sorting == infoAccessor.sorting(info)) {
const QString name = infoAccessor.actionCollectionName(info, AdditionalInfoAccessor::SortByType);
action = m_actionCollection->action(name);
}
}
-void DolphinViewActionHandler::slotZoomLevelChanged(int level)
+void DolphinViewActionHandler::slotZoomLevelChanged(int current, int previous)
{
+ Q_UNUSED(previous);
+
QAction* zoomInAction = m_actionCollection->action(KStandardAction::name(KStandardAction::ZoomIn));
if (zoomInAction) {
- zoomInAction->setEnabled(level < ZoomLevelInfo::maximumLevel());
+ zoomInAction->setEnabled(current < ZoomLevelInfo::maximumLevel());
}
QAction* zoomOutAction = m_actionCollection->action(KStandardAction::name(KStandardAction::ZoomOut));
if (zoomOutAction) {
- zoomOutAction->setEnabled(level > ZoomLevelInfo::minimumLevel());
+ zoomOutAction->setEnabled(current > ZoomLevelInfo::minimumLevel());
}
}
void togglePreview(bool);
/** Updates the state of the 'Show preview' menu action. */
- void slotShowPreviewChanged();
+ void slotPreviewsShownChanged(bool shown);
/** Increases the size of the current set view mode. */
void zoomIn();
/**
* Updates the state of the 'Zoom In' and 'Zoom Out' actions.
*/
- void slotZoomLevelChanged(int level);
+ void slotZoomLevelChanged(int current, int previous);
/**
* Switches on or off the displaying of additional information
/**
* Updates the state of the 'Additional Information' actions.
*/
- void slotAdditionalInfoChanged();
+ void slotAdditionalInfoListChanged(const QList<DolphinView::AdditionalInfo>& current,
+ const QList<DolphinView::AdditionalInfo>& previous);
/**
* Switches between sorting by categories or not.
/**
* Updates the state of the 'Categorized sorting' menu action.
*/
- void slotCategorizedSortingChanged();
+ void slotCategorizedSortingChanged(bool sortCategorized);
/**
* Switches between showing and hiding of hidden marked files
/**
* Updates the state of the 'Show hidden files' menu action.
*/
- void slotShowHiddenFilesChanged();
+ void slotHiddenFilesShownChanged(bool shown);
/**
* Opens the view properties dialog, which allows to modify the properties
KToggleAction* iconsModeAction();
/**
- * Returns the "switch to details mode" action.
+ * Returns the "switch to compact mode" action.
* Helper method for createActions();
*/
- KToggleAction* detailsModeAction();
+ KToggleAction* compactModeAction();
/**
- * Returns the "switch to columns mode" action.
+ * Returns the "switch to details mode" action.
* Helper method for createActions();
*/
- KToggleAction* columnsModeAction();
+ KToggleAction* detailsModeAction();
KActionCollection* m_actionCollection;
DolphinView* m_currentView;
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2010 by Peter Penz <peter.penz19@gmail.com> *
- * *
- * 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 "dolphinviewcontroller.h"
-#include "zoomlevelinfo.h"
-
-#include <KDirModel>
-#include <KFileItemActions>
-#include <QAbstractProxyModel>
-#include <QApplication>
-#include <QClipboard>
-#include <QDir>
-
-Qt::MouseButtons DolphinViewController::m_mouseButtons = Qt::NoButton;
-
-DolphinViewController::DolphinViewController(DolphinView* dolphinView) :
- QObject(dolphinView),
- m_dolphinView(dolphinView),
- m_itemView(0),
- m_versionControlActions()
-{
-}
-
-DolphinViewController::~DolphinViewController()
-{
-}
-
-const DolphinView* DolphinViewController::view() const
-{
- return m_dolphinView;
-}
-
-void DolphinViewController::requestUrlChange(const KUrl& url)
-{
- emit urlChangeRequested(url);
-}
-
-void DolphinViewController::setItemView(QAbstractItemView* view)
-{
- if (m_itemView) {
- disconnect(m_itemView, SIGNAL(pressed(const QModelIndex&)),
- this, SLOT(updateMouseButtonState()));
- }
-
- m_itemView = view;
-
- if (m_itemView) {
- // TODO: this is a workaround until Qt-issue 176832 has been fixed
- connect(m_itemView, SIGNAL(pressed(const QModelIndex&)),
- this, SLOT(updateMouseButtonState()));
- }
-}
-
-QAbstractItemView* DolphinViewController::itemView() const
-{
- return m_itemView;
-}
-
-void DolphinViewController::triggerContextMenuRequest(const QPoint& pos,
- const QList<QAction*>& customActions)
-{
- emit activated();
- emit requestContextMenu(pos, customActions);
-}
-
-void DolphinViewController::requestActivation()
-{
- emit activated();
-}
-
-void DolphinViewController::indicateDroppedUrls(const KFileItem& destItem, QDropEvent* event)
-{
- emit urlsDropped(destItem, m_dolphinView->url(), event);
-}
-
-
-void DolphinViewController::indicateSortingChange(DolphinView::Sorting sorting)
-{
- emit sortingChanged(sorting);
-}
-
-void DolphinViewController::indicateSortOrderChange(Qt::SortOrder order)
-{
- emit sortOrderChanged(order);
-}
-
-void DolphinViewController::indicateSortFoldersFirstChange(bool foldersFirst)
-{
- emit sortFoldersFirstChanged(foldersFirst);
-}
-
-void DolphinViewController::indicateAdditionalInfoChange(const KFileItemDelegate::InformationList& info)
-{
- emit additionalInfoChanged(info);
-}
-
-void DolphinViewController::setVersionControlActions(QList<QAction*> actions)
-{
- m_versionControlActions = actions;
-}
-
-QList<QAction*> DolphinViewController::versionControlActions(const KFileItemList& items)
-{
- emit requestVersionControlActions(items);
- // All view implementations are connected with the signal requestVersionControlActions()
- // (see ViewExtensionFactory) and will invoke DolphinViewController::setVersionControlActions(),
- // so that the context dependent actions can be returned.
- return m_versionControlActions;
-}
-
-void DolphinViewController::handleKeyPressEvent(QKeyEvent* event)
-{
- if (!m_itemView) {
- return;
- }
-
- const QItemSelectionModel* selModel = m_itemView->selectionModel();
- const QModelIndex currentIndex = selModel->currentIndex();
- const bool trigger = currentIndex.isValid()
- && ((event->key() == Qt::Key_Return) || (event->key() == Qt::Key_Enter))
- && !selModel->selectedIndexes().isEmpty();
- if (!trigger) {
- return;
- }
-
- // Collect selected files and selected directories
- // as two separate lists.
- QModelIndexList dirQueue;
- const QModelIndexList indexList = selModel->selectedIndexes();
- KFileItemList fileOpenList;
- foreach (const QModelIndex& index, indexList) {
- if (itemForIndex(index).isDir()) {
- dirQueue << index;
- } else {
- fileOpenList << itemForIndex(index);
- }
- }
-
- // Handle selected files
- if (fileOpenList.count() == 1) {
- emit itemTriggered(fileOpenList.first());
- } else {
- KFileItemActions fileItemActions;
- fileItemActions.runPreferredApplications(fileOpenList, "DesktopEntryName != 'dolphin'");
- }
-
- // Handle selected directories
- if (dirQueue.count() == 1) {
- // Open directory in the view
- emit itemTriggered(itemForIndex(dirQueue[0]));
- } else {
- // Open directories in separate tabs
- foreach(const QModelIndex& dir, dirQueue) {
- emit tabRequested(itemForIndex(dir).url());
- }
- }
-}
-
-void DolphinViewController::replaceUrlByClipboard()
-{
- const QClipboard* clipboard = QApplication::clipboard();
- QString text;
- if (clipboard->mimeData(QClipboard::Selection)->hasText()) {
- text = clipboard->mimeData(QClipboard::Selection)->text();
- } else if (clipboard->mimeData(QClipboard::Clipboard)->hasText()) {
- text = clipboard->mimeData(QClipboard::Clipboard)->text();
- }
- if (!text.isEmpty() && QDir::isAbsolutePath(text)) {
- m_dolphinView->setUrl(KUrl(text));
- }
-}
-
-void DolphinViewController::requestToolTipHiding()
-{
- emit hideToolTip();
-}
-
-void DolphinViewController::emitItemTriggered(const KFileItem& item)
-{
- emit itemTriggered(item);
-}
-
-KFileItem DolphinViewController::itemForIndex(const QModelIndex& index) const
-{
- if (m_itemView) {
- QAbstractProxyModel* proxyModel = static_cast<QAbstractProxyModel*>(m_itemView->model());
- if (proxyModel) {
- KDirModel* dirModel = static_cast<KDirModel*>(proxyModel->sourceModel());
- const QModelIndex dirIndex = proxyModel->mapToSource(index);
- return dirModel->itemForIndex(dirIndex);
- }
- }
-
- return KFileItem();
-}
-
-void DolphinViewController::triggerItem(const QModelIndex& index)
-{
- if (m_mouseButtons & Qt::LeftButton) {
- const KFileItem item = itemForIndex(index);
- if (index.isValid() && (index.column() == KDirModel::Name)) {
- emit itemTriggered(item);
- } else if (m_itemView) {
- m_itemView->clearSelection();
- emit itemEntered(KFileItem());
- }
- }
-}
-
-void DolphinViewController::requestTab(const QModelIndex& index)
-{
- if (m_mouseButtons & Qt::MidButton) {
- const KFileItem item = itemForIndex(index);
- const bool validRequest = index.isValid() &&
- (index.column() == KDirModel::Name) &&
- (item.isDir() || m_dolphinView->isTabsForFilesEnabled());
- if (validRequest) {
- emit tabRequested(item.url());
- }
- }
-}
-
-void DolphinViewController::emitItemEntered(const QModelIndex& index)
-{
- KFileItem item = itemForIndex(index);
- if (!item.isNull()) {
- emit itemEntered(item);
- }
-}
-
-void DolphinViewController::emitViewportEntered()
-{
- emit viewportEntered();
-}
-
-void DolphinViewController::updateMouseButtonState()
-{
- m_mouseButtons = QApplication::mouseButtons();
-}
-
-#include "dolphinviewcontroller.moc"
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2010 by Peter Penz <peter.penz19@gmail.com> *
- * *
- * 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 DOLPHINVIEWCONTROLLER_H
-#define DOLPHINVIEWCONTROLLER_H
-
-#include <views/dolphinview.h>
-#include <KUrl>
-#include <QObject>
-#include <libdolphin_export.h>
-
-class QAbstractItemView;
-class DolphinView;
-class KUrl;
-class QPoint;
-
-/**
- * @brief Allows the view mode implementations (DolphinIconsView, DolphinDetailsView, DolphinColumnView)
- * to do a limited control of the DolphinView.
- *
- * The DolphinView connects to the signals of DolphinViewController to react on changes
- * that have been triggered by the view mode implementations. The view mode implementations
- * have read access to the whole DolphinView by DolphinViewController::view(). Limited control of the
- * DolphinView by the view mode implementations are defined by the public DolphinViewController methods.
- */
-class LIBDOLPHINPRIVATE_EXPORT DolphinViewController : public QObject
-{
- Q_OBJECT
-
-public:
- explicit DolphinViewController(DolphinView* dolphinView);
- virtual ~DolphinViewController();
-
- /**
- * Allows read access for the view mode implementation
- * to the DolphinView.
- */
- const DolphinView* view() const;
-
- /**
- * Requests the DolphinView to change the URL to \p url. The signal
- * urlChangeRequested will be emitted.
- */
- void requestUrlChange(const KUrl& url);
-
- /**
- * Changes the current view mode implementation where the controller is working.
- * This is only necessary for views like the column view, where internally
- * several QAbstractItemView instances are used.
- */
- void setItemView(QAbstractItemView* view);
- QAbstractItemView* itemView() const;
-
- /**
- * Requests a context menu for the position \a pos. DolphinView
- * takes care itself to get the selected items depending from
- * \a pos. It is possible to define a custom list of actions for
- * the context menu by \a customActions.
- */
- void triggerContextMenuRequest(const QPoint& pos,
- const QList<QAction*>& customActions = QList<QAction*>());
-
- /**
- * Requests an activation of the DolphinView and emits the signal
- * activated(). This method should be invoked by the view mode implementation
- * if e. g. a mouse click on the view has been done.
- */
- void requestActivation();
-
- /**
- * Indicates that URLs are dropped above a destination. The DolphinView
- * will start the corresponding action (copy, move, link).
- * @param destItem Item of the destination (can be null, see KFileItem::isNull()).
- * @param event Drop event
- */
- void indicateDroppedUrls(const KFileItem& destItem, QDropEvent* event);
-
- /**
- * Informs the DolphinView about a sorting change done inside
- * the view mode implementation.
- */
- void indicateSortingChange(DolphinView::Sorting sorting);
-
- /**
- * Informs the DolphinView about a sort order change done inside
- * the view mode implementation.
- */
- void indicateSortOrderChange(Qt::SortOrder order);
-
- /**
- * Informs the DolphinView about a change between separate sorting
- * (with folders first) and mixed sorting of files and folders done inside
- * the view mode implementation.
- */
- void indicateSortFoldersFirstChange(bool foldersFirst);
-
- /**
- * Informs the DolphinView about an additional information change
- * done inside the view mode implementation.
- */
- void indicateAdditionalInfoChange(const KFileItemDelegate::InformationList& info);
-
- /**
- * Sets the available version control actions. Is called by the view
- * mode implementation as soon as the DolphinView has requested them by the signal
- * requestVersionControlActions().
- */
- void setVersionControlActions(QList<QAction*> actions);
-
- /**
- * Emits the signal requestVersionControlActions(). The view mode implementation
- * listens to the signal and will invoke a DolphinViewController::setVersionControlActions()
- * and the result will be returned.
- */
- QList<QAction*> versionControlActions(const KFileItemList& items);
-
- /**
- * Must be be invoked in each view mode implementation whenever a key has been
- * pressed. If the selection model of \a view is not empty and
- * the return key has been pressed, the selected items will get triggered.
- */
- void handleKeyPressEvent(QKeyEvent* event);
-
- /**
- * Replaces the URL of the DolphinView with the content
- * of the clipboard as URL. If the clipboard contains no text,
- * nothing will be done.
- */
- void replaceUrlByClipboard();
-
- /**
- * Requests the view mode implementation to hide tooltips.
- */
- void requestToolTipHiding();
-
- /**
- * Emits the signal itemTriggered() for the item \a item.
- * The method can be used by the view mode implementations to
- * trigger an item directly without mouse interaction.
- * If the item triggering is done by the mouse, it is recommended
- * to use DolphinViewController::triggerItem(), as this will check
- * the used mouse buttons to execute the correct action.
- */
- void emitItemTriggered(const KFileItem& item);
-
- /**
- * Returns the file item for the proxy index \a index of the DolphinView.
- */
- KFileItem itemForIndex(const QModelIndex& index) const;
-
-public slots:
- /**
- * Emits the signal itemTriggered() if the file item for the index \a index
- * is not null and the left mouse button has been pressed. If the item is
- * null, the signal itemEntered() is emitted.
- * The method should be invoked by the view mode implementations whenever the
- * user has triggered an item with the mouse (see
- * QAbstractItemView::clicked() or QAbstractItemView::doubleClicked()).
- */
- void triggerItem(const QModelIndex& index);
-
- /**
- * Emits the signal tabRequested(), if the file item for the index \a index
- * represents a directory and when the middle mouse button has been pressed.
- */
- void requestTab(const QModelIndex& index);
-
- /**
- * Emits the signal itemEntered() if the file item for the index \a index
- * is not null. The method should be invoked by the view mode implementation
- * whenever the mouse cursor is above an item.
- */
- void emitItemEntered(const QModelIndex& index);
-
- /**
- * Emits the signal viewportEntered(). The method should be invoked by
- * the view mode implementation whenever the mouse cursor is above the viewport.
- */
- void emitViewportEntered();
-
-signals:
- void urlChangeRequested(const KUrl& url);
-
- /**
- * Is emitted if a context menu should be opened (see triggerContextMenuRequest()).
- * @param pos Position relative to the view widget where the
- * context menu should be opened. It is recommended
- * to get the corresponding model index from
- * this position.
- * @param customActions List of actions that is added to the context menu when
- * the menu is opened above the viewport.
- */
- void requestContextMenu(const QPoint& pos, QList<QAction*> customActions);
-
- /**
- * Is emitted if the view has been activated by e. g. a mouse click.
- */
- void activated();
-
- /**
- * Is emitted if URLs have been dropped to the destination
- * path \a destPath. If the URLs have been dropped above an item of
- * the destination path, the item is indicated by \a destItem
- * (can be null, see KFileItem::isNull()).
- */
- void urlsDropped(const KFileItem& destItem,
- const KUrl& destPath,
- QDropEvent* event);
-
- /**
- * Is emitted if the sorting has been changed to \a sorting by
- * the view mode implementation (see indicateSortingChanged().
- * The DolphinView connects to
- * this signal to update its menu action.
- */
- void sortingChanged(DolphinView::Sorting sorting);
-
- /**
- * Is emitted if the sort order has been changed to \a order
- * by the view mode implementation (see indicateSortOrderChanged().
- * The DolphinView connects
- * to this signal to update its menu actions.
- */
- void sortOrderChanged(Qt::SortOrder order);
-
- /**
- * Is emitted if 'sort folders first' has been changed to \a foldersFirst
- * by the view mode implementation (see indicateSortOrderChanged().
- * The DolphinView connects
- * to this signal to update its menu actions.
- */
- void sortFoldersFirstChanged(bool foldersFirst);
-
- /**
- * Is emitted if the additional info has been changed to \a info
- * by the view mode implementation. The DolphinView connects
- * to this signal to update its menu actions.
- */
- void additionalInfoChanged(const KFileItemDelegate::InformationList& info);
-
- /**
- * Is emitted if the item \a item should be triggered. The abstract
- * Dolphin view connects to this signal. If the item represents a directory,
- * the directory is opened. On a file the corresponding application is opened.
- * The item is null (see KFileItem::isNull()), when clicking on the viewport itself.
- */
- void itemTriggered(const KFileItem& item);
-
- /**
- * Is emitted if the mouse cursor has entered the item
- * given by \a index (see emitItemEntered()).
- */
- void itemEntered(const KFileItem& item);
-
- /**
- * Is emitted if a new tab should be opened for the URL \a url.
- */
- void tabRequested(const KUrl& url);
-
- /**
- * Is emitted if the mouse cursor has entered
- * the viewport (see emitViewportEntered()).
- */
- void viewportEntered();
-
- /**
- * Is emitted, if DolphinViewController::requestToolTipHiding() is invoked
- * and requests to hide all tooltips.
- */
- void hideToolTip();
-
- /**
- * Is emitted if pending previews should be canceled (e. g. because of an URL change).
- */
- void cancelPreviews();
-
- /**
- * Requests the view mode implementation to invoke DolphinViewController::setVersionControlActions(),
- * so that they can be returned with DolphinViewController::versionControlActions() for
- * the DolphinView.
- */
- void requestVersionControlActions(const KFileItemList& items);
-
-private slots:
- void updateMouseButtonState();
-
-private:
- static Qt::MouseButtons m_mouseButtons; // TODO: this is a workaround until Qt-issue 176832 has been fixed
-
- DolphinView* m_dolphinView;
- QAbstractItemView* m_itemView;
- QList<QAction*> m_versionControlActions;
-};
-
-#endif
QLabel* editLabel = 0;
if (m_renameOneItem) {
- m_newName = items.first().name();
- editLabel = new QLabel(i18nc("@label:textbox", "Rename the item <filename>%1</filename> to:",
- KStringHandler::csqueeze(m_newName)), page);
- if (m_newName.size() > 40) {
- editLabel->setToolTip(m_newName); // Set the filename as a the tool tip...
- }
+ m_newName = items.first().name();
+ editLabel = new QLabel(i18nc("@label:textbox", "Rename the item <filename>%1</filename> to:", m_newName),
+ page);
} else {
m_newName = i18nc("@info:status", "New name #");
editLabel = new QLabel(i18ncp("@label:textbox",
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2008 by Peter Penz <peter.penz19@gmail.com> *
- * *
- * 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 "selectionmanager.h"
-
-#include "dolphinmodel.h"
-#include "dolphin_generalsettings.h"
-#include "selectiontoggle.h"
-#include "settings/dolphinsettings.h"
-#include <KDirModel>
-#include <KGlobalSettings>
-#include <KIconEffect>
-
-#include <QAbstractButton>
-#include <QAbstractItemView>
-#include <QAbstractProxyModel>
-#include <QApplication>
-#include <QModelIndex>
-#include <QPainter>
-#include <QPaintEvent>
-#include <QRect>
-#include <QTimeLine>
-
-SelectionManager::SelectionManager(QAbstractItemView* parent) :
- QObject(parent),
- m_view(parent),
- m_toggle(0),
- m_connected(false),
- m_appliedPointingHandCursor(false)
-{
- connect(parent, SIGNAL(entered(const QModelIndex&)),
- this, SLOT(slotEntered(const QModelIndex&)));
- connect(parent, SIGNAL(viewportEntered()),
- this, SLOT(slotViewportEntered()));
-
- const GeneralSettings* settings = DolphinSettings::instance().generalSettings();
- if (settings->showSelectionToggle()) {
- m_toggle = new SelectionToggle(m_view->viewport());
- m_toggle->setCheckable(true);
- m_toggle->hide();
- connect(m_toggle, SIGNAL(clicked(bool)),
- this, SLOT(setItemSelected(bool)));
- m_toggle->installEventFilter(this);
- }
-
- m_view->viewport()->installEventFilter(this);
-}
-
-SelectionManager::~SelectionManager()
-{
-}
-
-bool SelectionManager::eventFilter(QObject* watched, QEvent* event)
-{
- if (watched == m_view->viewport()) {
- switch (event->type()) {
- case QEvent::Leave:
- if (m_toggle) {
- m_toggle->hide();
- }
- restoreCursor();
- break;
-
- case QEvent::MouseButtonPress: {
- // Set the toggle invisible, if a mouse button has been pressed
- // outside the toggle boundaries. This e.g. assures, that the toggle
- // gets invisible during dragging items.
- if (m_toggle) {
- const QRect toggleBounds(m_toggle->mapToGlobal(QPoint(0, 0)), m_toggle->size());
- m_toggle->setVisible(toggleBounds.contains(QCursor::pos()));
- }
- break;
- }
-
- default:
- break;
- }
- } else if (watched == m_toggle) {
- switch (event->type()) {
- case QEvent::Enter:
- QApplication::changeOverrideCursor(Qt::ArrowCursor);
- break;
-
- case QEvent::Leave:
- QApplication::changeOverrideCursor(Qt::PointingHandCursor);
- break;
-
- default:
- break;
- }
- }
-
- return QObject::eventFilter(watched, event);
-}
-
-void SelectionManager::reset()
-{
- if (m_toggle) {
- m_toggle->reset();
- }
-}
-
-void SelectionManager::slotEntered(const QModelIndex& index)
-{
- const bool isSelectionCandidate = index.isValid() &&
- (index.column() == DolphinModel::Name) &&
- (QApplication::mouseButtons() == Qt::NoButton);
-
- restoreCursor();
- if (isSelectionCandidate && KGlobalSettings::singleClick()) {
- applyPointingHandCursor();
- }
-
- if (isSelectionCandidate) {
- if (!m_connected) {
- connect(m_view->model(), SIGNAL(rowsRemoved(const QModelIndex&, int, int)),
- this, SLOT(slotRowsRemoved(const QModelIndex&, int, int)));
- connect(m_view->selectionModel(),
- SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
- this,
- SLOT(slotSelectionChanged(const QItemSelection&, const QItemSelection&)));
- m_connected = true;
- }
- } else {
- disconnect(m_view->model(), SIGNAL(rowsRemoved(const QModelIndex&, int, int)),
- this, SLOT(slotRowsRemoved(const QModelIndex&, int, int)));
- disconnect(m_view->selectionModel(),
- SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
- this,
- SLOT(slotSelectionChanged(const QItemSelection&, const QItemSelection&)));
- m_connected = false;
- }
-
- if (!m_toggle) {
- return;
- }
-
- m_toggle->hide();
- if (isSelectionCandidate) {
- m_toggle->setUrl(urlForIndex(index));
-
- // Increase the size of the toggle for large items
- const int iconHeight = m_view->iconSize().height();
-
- int toggleSize = KIconLoader::SizeSmall;
- if (iconHeight >= KIconLoader::SizeEnormous) {
- toggleSize = KIconLoader::SizeMedium;
- } else if (iconHeight >= KIconLoader::SizeLarge) {
- toggleSize = KIconLoader::SizeSmallMedium;
- }
-
- // Add a small invisible margin, if the item-height is nearly
- // equal to the toggleSize (#169494).
- const QRect rect = m_view->visualRect(index);
- int margin = (rect.height() - toggleSize) / 2;
- if (margin > 4) {
- margin = 0;
- }
- toggleSize += 2 * margin;
- m_toggle->setMargin(margin);
- m_toggle->resize(toggleSize, toggleSize);
- m_toggle->move(rect.topLeft());
-
- QItemSelectionModel* selModel = m_view->selectionModel();
- m_toggle->setChecked(selModel->isSelected(index));
- m_toggle->show();
- } else {
- m_toggle->setUrl(KUrl());
- }
-}
-
-void SelectionManager::slotViewportEntered()
-{
- if (m_toggle) {
- m_toggle->hide();
- }
- restoreCursor();
-}
-
-void SelectionManager::setItemSelected(bool selected)
-{
- emit selectionChanged();
-
- if (m_toggle && !m_toggle->url().isEmpty()) {
- const QModelIndex index = indexForUrl(m_toggle->url());
- if (index.isValid()) {
- QItemSelectionModel* selModel = m_view->selectionModel();
- if (selected) {
- selModel->select(index, QItemSelectionModel::Select);
- } else {
- selModel->select(index, QItemSelectionModel::Deselect);
- }
- selModel->setCurrentIndex(index, QItemSelectionModel::Current);
- }
- }
-}
-
-void SelectionManager::slotRowsRemoved(const QModelIndex& parent, int start, int end)
-{
- Q_UNUSED(parent);
- Q_UNUSED(start);
- Q_UNUSED(end);
- if (m_toggle) {
- m_toggle->hide();
- }
- restoreCursor();
-}
-
-void SelectionManager::slotSelectionChanged(const QItemSelection& selected,
- const QItemSelection& deselected)
-{
- // The selection has been changed outside the scope of the selection manager
- // (e. g. by the rubberband or the "Select All" action). Take care updating
- // the state of the toggle button.
- if (m_toggle && !m_toggle->url().isEmpty()) {
- const QModelIndex index = indexForUrl(m_toggle->url());
- if (index.isValid()) {
- if (selected.contains(index)) {
- m_toggle->setChecked(true);
- }
-
- if (deselected.contains(index)) {
- m_toggle->setChecked(false);
- }
- }
- }
-}
-
-KUrl SelectionManager::urlForIndex(const QModelIndex& index) const
-{
- QAbstractProxyModel* proxyModel = static_cast<QAbstractProxyModel*>(m_view->model());
- KDirModel* dirModel = static_cast<KDirModel*>(proxyModel->sourceModel());
- const QModelIndex dirIndex = proxyModel->mapToSource(index);
- return dirModel->itemForIndex(dirIndex).url();
-}
-
-const QModelIndex SelectionManager::indexForUrl(const KUrl& url) const
-{
- QAbstractProxyModel* proxyModel = static_cast<QAbstractProxyModel*>(m_view->model());
- KDirModel* dirModel = static_cast<KDirModel*>(proxyModel->sourceModel());
- const QModelIndex dirIndex = dirModel->indexForUrl(url);
- return proxyModel->mapFromSource(dirIndex);
-}
-
-
-void SelectionManager::applyPointingHandCursor()
-{
- if (!m_appliedPointingHandCursor) {
- QApplication::setOverrideCursor(QCursor(Qt::PointingHandCursor));
- m_appliedPointingHandCursor = true;
- }
-}
-
-void SelectionManager::restoreCursor()
-{
- if (m_appliedPointingHandCursor) {
- QApplication::restoreOverrideCursor();
- m_appliedPointingHandCursor = false;
- }
-}
-
-#include "selectionmanager.moc"
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2008 by Peter Penz <peter.penz19@gmail.com> *
- * *
- * 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 SELECTIONMANAGER_H
-#define SELECTIONMANAGER_H
-
-#include <KFileItem>
-
-#include <QObject>
-
-class QAbstractItemView;
-class QModelIndex;
-class QItemSelection;
-class SelectionToggle;
-
-/**
- * @brief Allows to select and deselect items for item views.
- *
- * Whenever an item is hovered by the mouse, a toggle button is shown
- * which allows to select/deselect the current item.
- */
-class SelectionManager : public QObject
-{
- Q_OBJECT
-
-public:
- SelectionManager(QAbstractItemView* parent);
- virtual ~SelectionManager();
- virtual bool eventFilter(QObject* watched, QEvent* event);
-
-public slots:
- /**
- * Resets the selection manager so that the toggle button gets
- * invisible.
- */
- void reset();
-
-signals:
- /** Is emitted if the selection has been changed by the toggle button. */
- void selectionChanged();
-
-private slots:
- void slotEntered(const QModelIndex& index);
- void slotViewportEntered();
- void setItemSelected(bool selected);
- void slotRowsRemoved(const QModelIndex& parent, int start, int end);
- void slotSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
-
-private:
- KUrl urlForIndex(const QModelIndex& index) const;
- const QModelIndex indexForUrl(const KUrl& url) const;
- void applyPointingHandCursor();
- void restoreCursor();
-
-private:
- QAbstractItemView* m_view;
- SelectionToggle* m_toggle;
- bool m_connected;
- bool m_appliedPointingHandCursor;
-};
-
-#endif
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2008 by Peter Penz <peter.penz19@gmail.com> *
- * *
- * 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 "selectiontoggle.h"
-
-#include <KGlobalSettings>
-#include <KIcon>
-#include <KIconLoader>
-#include <KIconEffect>
-#include <KLocale>
-
-#include <QApplication>
-#include <QPainter>
-#include <QPaintEvent>
-#include <QRect>
-#include <QTimer>
-#include <QTimeLine>
-
-#include <KDebug>
-
-SelectionToggle::SelectionToggle(QWidget* parent) :
- QAbstractButton(parent),
- m_isHovered(false),
- m_leftMouseButtonPressed(false),
- m_fadingValue(0),
- m_margin(0),
- m_icon(),
- m_fadingTimeLine(0)
-{
- setFocusPolicy(Qt::NoFocus);
- parent->installEventFilter(this);
- resize(sizeHint());
- setIconOverlay(isChecked());
- connect(this, SIGNAL(toggled(bool)),
- this, SLOT(setIconOverlay(bool)));
- connect(KGlobalSettings::self(), SIGNAL(iconChanged(int)),
- this, SLOT(refreshIcon()));
-}
-
-SelectionToggle::~SelectionToggle()
-{
-}
-
-QSize SelectionToggle::sizeHint() const
-{
- return QSize(16, 16);
-}
-
-void SelectionToggle::reset()
-{
- m_url = KUrl();
- hide();
-}
-
-void SelectionToggle::setUrl(const KUrl& url)
-{
- m_url = url;
- if (!url.isEmpty()) {
- startFading();
- }
-}
-
-void SelectionToggle::setMargin(int margin)
-{
- if (margin != m_margin) {
- m_margin = margin;
- update();
- }
-}
-
-int SelectionToggle::margin() const
-{
- return m_margin;
-}
-
-KUrl SelectionToggle::url() const
-{
- return m_url;
-}
-
-void SelectionToggle::setVisible(bool visible)
-{
- QAbstractButton::setVisible(visible);
-
- stopFading();
- if (visible) {
- startFading();
- }
-
-}
-
-bool SelectionToggle::eventFilter(QObject* obj, QEvent* event)
-{
- if ((obj == parent()) && (event->type() == QEvent::MouseMove) && m_leftMouseButtonPressed) {
- // Don't forward mouse move events to the viewport,
- // otherwise a rubberband selection will be shown when
- // clicking on the selection toggle and moving the mouse
- // above the viewport.
- return true;
- }
-
- return QAbstractButton::eventFilter(obj, event);
-}
-
-void SelectionToggle::enterEvent(QEvent* event)
-{
- QAbstractButton::enterEvent(event);
-
- // if the mouse cursor is above the selection toggle, display
- // it immediately without fading timer
- m_isHovered = true;
- if (m_fadingTimeLine) {
- m_fadingTimeLine->stop();
- }
- m_fadingValue = 255;
- setToolTip(isChecked() ? i18nc("@info:tooltip", "Deselect Item") :
- i18nc("@info:tooltip", "Select Item"));
- update();
-}
-
-void SelectionToggle::leaveEvent(QEvent* event)
-{
- QAbstractButton::leaveEvent(event);
-
- m_isHovered = false;
- update();
-}
-
-void SelectionToggle::mousePressEvent(QMouseEvent* event)
-{
- QAbstractButton::mousePressEvent(event);
- m_leftMouseButtonPressed = (event->buttons() & Qt::LeftButton);
-}
-
-void SelectionToggle::mouseReleaseEvent(QMouseEvent* event)
-{
- QAbstractButton::mouseReleaseEvent(event);
- m_leftMouseButtonPressed = (event->buttons() & Qt::LeftButton);
-}
-
-void SelectionToggle::resizeEvent(QResizeEvent* event)
-{
- QAbstractButton::resizeEvent(event);
- setIconOverlay(isChecked());
-}
-
-void SelectionToggle::paintEvent(QPaintEvent* event)
-{
- QPainter painter(this);
- painter.setClipRect(event->rect());
-
- // draw the icon overlay
- const QPoint pos(m_margin, m_margin);
- if (m_isHovered) {
- KIconEffect *iconEffect = KIconLoader::global()->iconEffect();
- QPixmap activeIcon = iconEffect->apply(m_icon, KIconLoader::Desktop, KIconLoader::ActiveState);
- painter.drawPixmap(pos, activeIcon);
- } else {
- if (m_fadingValue < 255) {
- // apply an alpha mask respecting the fading value to the icon
- QPixmap icon = m_icon;
- QPixmap alphaMask(icon.width(), icon.height());
- const QColor color(m_fadingValue, m_fadingValue, m_fadingValue);
- alphaMask.fill(color);
- icon.setAlphaChannel(alphaMask);
- painter.drawPixmap(pos, icon);
- } else {
- // no fading is required
- painter.drawPixmap(pos, m_icon);
- }
- }
-
-}
-
-void SelectionToggle::setFadingValue(int value)
-{
- m_fadingValue = value;
- if (m_fadingValue >= 255) {
- Q_ASSERT(m_fadingTimeLine);
- m_fadingTimeLine->stop();
- }
- update();
-}
-
-void SelectionToggle::setIconOverlay(bool checked)
-{
- const char* icon = checked ? "list-remove" : "list-add";
- const int size = qMin(width() - 2 * m_margin, height() - 2 * m_margin);
- m_icon = KIconLoader::global()->loadIcon(icon,
- KIconLoader::NoGroup,
- size);
- update();
-}
-
-void SelectionToggle::refreshIcon()
-{
- setIconOverlay(isChecked());
-}
-
-void SelectionToggle::startFading()
-{
- Q_ASSERT(!m_fadingTimeLine);
-
- const bool animate = KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects;
- const int duration = animate ? 600 : 1;
-
- m_fadingTimeLine = new QTimeLine(duration, this);
- connect(m_fadingTimeLine, SIGNAL(frameChanged(int)),
- this, SLOT(setFadingValue(int)));
- m_fadingTimeLine->setFrameRange(0, 255);
- m_fadingTimeLine->start();
- m_fadingValue = 0;
-}
-
-void SelectionToggle::stopFading()
-{
- if (m_fadingTimeLine) {
- m_fadingTimeLine->stop();
- delete m_fadingTimeLine;
- m_fadingTimeLine = 0;
- }
- m_fadingValue = 0;
-}
-
-#include "selectiontoggle.moc"
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2008 by Peter Penz <peter.penz19@gmail.com> *
- * *
- * 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 SELECTIONTOGGLE_H
-#define SELECTIONTOGGLE_H
-
-#include <KUrl>
-
-#include <QAbstractButton>
-#include <QPixmap>
-
-class QTimeLine;
-
-/**
- * @brief Toggle button for changing the selection of an hovered item.
- *
- * The toggle button is visually invisible until it is displayed at least
- * for one second.
- *
- * @see SelectionManager
- */
-class SelectionToggle : public QAbstractButton
-{
- Q_OBJECT
-
-public:
- explicit SelectionToggle(QWidget* parent);
- virtual ~SelectionToggle();
- virtual QSize sizeHint() const;
-
- /**
- * Resets the selection toggle so that it is hidden and stays
- * visually invisible for at least one second after it is shown again.
- */
- void reset();
-
- void setUrl(const KUrl& url);
- KUrl url() const;
-
- /**
- * Sets the margin around the selection-icon in pixels. Per default
- * the value is 0.
- */
- void setMargin(int margin);
- int margin() const;
-
-public slots:
- virtual void setVisible(bool visible);
-
-protected:
- virtual bool eventFilter(QObject* obj, QEvent* event);
- virtual void enterEvent(QEvent* event);
- virtual void leaveEvent(QEvent* event);
- virtual void mousePressEvent(QMouseEvent* event);
- virtual void mouseReleaseEvent(QMouseEvent* event);
- virtual void resizeEvent(QResizeEvent* event);
- virtual void paintEvent(QPaintEvent* event);
-
-private slots:
- /**
- * Sets the alpha value for the fading animation and is
- * connected with m_fadingTimeLine.
- */
- void setFadingValue(int value);
-
- void setIconOverlay(bool checked);
- void refreshIcon();
-
-private:
- void startFading();
- void stopFading();
-
-private:
- bool m_isHovered;
- bool m_leftMouseButtonPressed;
- int m_fadingValue;
- int m_margin;
- QPixmap m_icon;
- QTimeLine* m_fadingTimeLine;
- KUrl m_url;
-};
-
-#endif
#include <QApplication>
#include <QDesktopWidget>
+#include <QLayout>
#include <QScrollArea>
#include <QScrollBar>
#include <QTimer>
-#include <views/dolphinmodel.h>
-#include <views/dolphinsortfilterproxymodel.h>
-
-ToolTipManager::ToolTipManager(QAbstractItemView* parent,
- DolphinSortFilterProxyModel* model) :
+ToolTipManager::ToolTipManager(QWidget* parent) :
QObject(parent),
m_view(parent),
- m_dolphinModel(0),
- m_proxyModel(model),
m_showToolTipTimer(0),
m_contentRetrievalTimer(0),
m_fileMetaDataToolTip(0),
m_item(),
m_itemRect()
{
- m_dolphinModel = static_cast<DolphinModel*>(m_proxyModel->sourceModel());
- connect(parent, SIGNAL(entered(const QModelIndex&)),
- this, SLOT(requestToolTip(const QModelIndex&)));
- connect(parent, SIGNAL(viewportEntered()),
- this, SLOT(hideToolTip()));
+ //m_dolphinModel = static_cast<DolphinModel*>(m_proxyModel->sourceModel());
+ //connect(parent, SIGNAL(entered(const QModelIndex&)),
+ // this, SLOT(requestToolTip(const QModelIndex&)));
+ //connect(parent, SIGNAL(viewportEntered()),
+ // this, SLOT(hideToolTip()));
// Initialize timers
m_showToolTipTimer = new QTimer(this);
// When the mousewheel is used, the items don't get a hovered indication
// (Qt-issue #200665). To assure that the tooltip still gets hidden,
// the scrollbars are observed.
- connect(parent->horizontalScrollBar(), SIGNAL(valueChanged(int)),
+ /*connect(parent->horizontalScrollBar(), SIGNAL(valueChanged(int)),
this, SLOT(hideToolTip()));
connect(parent->verticalScrollBar(), SIGNAL(valueChanged(int)),
- this, SLOT(hideToolTip()));
+ this, SLOT(hideToolTip()));*/
Q_ASSERT(m_view);
- m_view->viewport()->installEventFilter(this);
- m_view->installEventFilter(this);
+ //m_view->viewport()->installEventFilter(this);
+ //m_view->installEventFilter(this);
}
ToolTipManager::~ToolTipManager()
bool ToolTipManager::eventFilter(QObject* watched, QEvent* event)
{
- if (watched == m_view->viewport()) {
+ /*if (watched == m_view->viewport()) {
switch (event->type()) {
case QEvent::Leave:
case QEvent::MouseButtonPress:
}
} else if ((watched == m_view) && (event->type() == QEvent::KeyPress)) {
hideToolTip();
- }
+ }*/
return QObject::eventFilter(watched, event);
}
void ToolTipManager::requestToolTip(const QModelIndex& index)
{
+ Q_UNUSED(index);
hideToolTip();
// Only request a tooltip for the name column and when no selection or
// drag & drop operation is done (indicated by the left mouse button)
- if ((index.column() == DolphinModel::Name) && !(QApplication::mouseButtons() & Qt::LeftButton)) {
- m_itemRect = m_view->visualRect(index);
- const QPoint pos = m_view->viewport()->mapToGlobal(m_itemRect.topLeft());
+ if (!(QApplication::mouseButtons() & Qt::LeftButton)) {
+ m_itemRect = QRect(); //m_view->visualRect(index);
+ const QPoint pos; // = m_view->viewport()->mapToGlobal(m_itemRect.topLeft());
m_itemRect.moveTo(pos);
- const QModelIndex dirIndex = m_proxyModel->mapToSource(index);
- m_item = m_dolphinModel->itemForIndex(dirIndex);
+ //const QModelIndex dirIndex = m_proxyModel->mapToSource(index);
+ //m_item = m_dolphinModel->itemForIndex(dirIndex);
// Only start the retrieving of the content, when the mouse has been over this
// item for 200 milliseconds. This prevents a lot of useless preview jobs and
Q_OBJECT
public:
- explicit ToolTipManager(QAbstractItemView* parent,
- DolphinSortFilterProxyModel* model);
+ explicit ToolTipManager(QWidget* parent);
virtual ~ToolTipManager();
public slots:
void showToolTip();
private:
- QAbstractItemView* m_view;
+ QWidget* m_view;
DolphinModel* m_dolphinModel;
DolphinSortFilterProxyModel* m_proxyModel;
#include <QMutexLocker>
#include <QTimer>
-#include <views/dolphinmodel.h>
-
-VersionControlObserver::VersionControlObserver(QAbstractItemView* view) :
+VersionControlObserver::VersionControlObserver(QWidget* view) :
QObject(view),
m_pendingItemStatesUpdate(false),
m_versionedDirectory(false),
m_silentUpdate(false),
m_view(view),
- m_dirLister(0),
- m_dolphinModel(0),
+ //m_dirLister(0),
+ //m_dolphinModel(0),
m_dirVerificationTimer(0),
m_plugin(0),
m_updateItemStatesThread(0)
{
Q_ASSERT(view);
- QAbstractProxyModel* proxyModel = qobject_cast<QAbstractProxyModel*>(view->model());
+ /*QAbstractProxyModel* proxyModel = qobject_cast<QAbstractProxyModel*>(view->model());
m_dolphinModel = proxyModel ?
qobject_cast<DolphinModel*>(proxyModel->sourceModel()) :
qobject_cast<DolphinModel*>(view->model());
m_dirVerificationTimer->setInterval(500);
connect(m_dirVerificationTimer, SIGNAL(timeout()),
this, SLOT(verifyDirectory()));
- }
+ }*/
}
VersionControlObserver::~VersionControlObserver()
void VersionControlObserver::verifyDirectory()
{
- const KUrl versionControlUrl = m_dirLister->url();
+ const KUrl versionControlUrl; // = m_dirLister->url();
if (!versionControlUrl.isLocalFile()) {
return;
}
}
m_plugin = searchPlugin(versionControlUrl);
- if (m_plugin) {
+ /*if (m_plugin) {
connect(m_plugin, SIGNAL(versionStatesChanged()),
this, SLOT(silentDirectoryVerification()));
connect(m_plugin, SIGNAL(infoMessage(QString)),
this, SLOT(delayedDirectoryVerification()));
disconnect(m_dirLister, SIGNAL(newItems(const KFileItemList&)),
this, SLOT(delayedDirectoryVerification()));
- }
+ }*/
}
void VersionControlObserver::slotThreadFinished()
// (a detailed description of the root cause is given in the class KFilePreviewGenerator
// from kdelibs). To bypass this bottleneck, the signals of the model are temporary blocked.
// This works as the update of the data does not require a relayout of the views used in Dolphin.
- const bool signalsBlocked = m_dolphinModel->signalsBlocked();
+ /*const bool signalsBlocked = m_dolphinModel->signalsBlocked();
m_dolphinModel->blockSignals(true);
const QList<ItemState> itemStates = m_updateItemStatesThread->itemStates();
if (m_pendingItemStatesUpdate) {
m_pendingItemStatesUpdate = false;
updateItemStates();
- }
+ }*/
}
void VersionControlObserver::updateItemStates()
void VersionControlObserver::addDirectory(const QModelIndex& parentIndex, QList<ItemState>& itemStates)
{
- const int rowCount = m_dolphinModel->rowCount(parentIndex);
+ Q_UNUSED(parentIndex);
+ Q_UNUSED(itemStates);
+ /*const int rowCount = m_dolphinModel->rowCount(parentIndex);
for (int row = 0; row < rowCount; ++row) {
const QModelIndex index = m_dolphinModel->index(row, DolphinModel::Version, parentIndex);
addDirectory(index, itemStates);
itemState.version = KVersionControlPlugin::UnversionedVersion;
itemStates.append(itemState);
- }
+ }*/
}
KVersionControlPlugin* VersionControlObserver::searchPlugin(const KUrl& directory) const
// Verify whether the current directory contains revision information
// like .svn, .git, ...
- foreach (KVersionControlPlugin* plugin, plugins) {
+ Q_UNUSED(directory);
+ /*foreach (KVersionControlPlugin* plugin, plugins) {
// Use the KDirLister cache to check for .svn, .git, ... files
KUrl dirUrl(directory);
KUrl fileUrl = dirUrl;
upUrl = dirUrl.upUrl();
}
}
- }
+ }*/
return 0;
}
bool VersionControlObserver::isVersioned() const
{
- return m_dolphinModel->hasVersionData() && m_plugin;
+ return false; //m_dolphinModel->hasVersionData() && m_plugin;
}
#include "versioncontrolobserver.moc"
Q_OBJECT
public:
- VersionControlObserver(QAbstractItemView* view);
+ VersionControlObserver(QWidget* parent);
virtual ~VersionControlObserver();
QList<QAction*> contextMenuActions(const KFileItemList& items) const;
bool m_silentUpdate; // if true, no messages will be send during the update
// of version states
- QAbstractItemView* m_view;
- KDirLister* m_dirLister;
- DolphinModel* m_dolphinModel;
+ QWidget* m_view;
+ //KDirLister* m_dirLister;
+ //DolphinModel* m_dolphinModel;
QTimer* m_dirVerificationTimer;
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2009 by Peter Penz <peter.penz19@gmail.com> *
- * *
- * 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 "viewextensionsfactory.h"
-
-#include "dolphinfileitemdelegate.h"
-#include "dolphinsortfilterproxymodel.h"
-#include "dolphinview.h"
-#include "dolphinviewcontroller.h"
-#include "dolphinviewautoscroller.h"
-#include "folderexpander.h"
-#include "selectionmanager.h"
-#include "settings/dolphinsettings.h"
-#include "tooltips/tooltipmanager.h"
-#include "versioncontrol/versioncontrolobserver.h"
-#include "viewmodecontroller.h"
-
-#include "dolphin_generalsettings.h"
-
-#include <KDirLister>
-#include <KDirModel>
-#include <KFilePreviewGenerator>
-#include <QAbstractItemView>
-#include <QApplication>
-
-ViewExtensionsFactory::ViewExtensionsFactory(QAbstractItemView* view,
- DolphinViewController* dolphinViewController,
- const ViewModeController* viewModeController) :
- QObject(view),
- m_view(view),
- m_dolphinViewController(dolphinViewController),
- m_toolTipManager(0),
- m_previewGenerator(0),
- m_selectionManager(0),
- m_autoScroller(0),
- m_fileItemDelegate(0),
- m_versionControlObserver(0)
-{
- view->setSelectionMode(QAbstractItemView::ExtendedSelection);
-
- GeneralSettings* settings = DolphinSettings::instance().generalSettings();
-
- // initialize tooltips
- if (settings->showToolTips()) {
- DolphinSortFilterProxyModel* proxyModel = static_cast<DolphinSortFilterProxyModel*>(view->model());
- m_toolTipManager = new ToolTipManager(view, proxyModel);
-
- connect(dolphinViewController, SIGNAL(hideToolTip()),
- m_toolTipManager, SLOT(hideToolTip()));
- }
-
- // initialize preview generator
- Q_ASSERT(view->iconSize().isValid());
- m_previewGenerator = new KFilePreviewGenerator(view);
- m_previewGenerator->setPreviewShown(dolphinViewController->view()->showPreview());
- connect(viewModeController, SIGNAL(zoomLevelChanged(int)),
- this, SLOT(slotZoomLevelChanged()));
- connect(viewModeController, SIGNAL(cancelPreviews()),
- this, SLOT(cancelPreviews()));
-
- // slotPreviewChanged() is connected as Qt::QueuedConnection to prevent performance
- // issues when the directory lister changes its URL after the preview-changes have
- // been applied. Usecase: Switch from directory A having no previews to
- // directory B with previews (see sequence in DolphinView::setUrl()).
- connect(dolphinViewController->view(), SIGNAL(showPreviewChanged()),
- this, SLOT(slotShowPreviewChanged()),
- Qt::QueuedConnection);
-
- // initialize selection manager
- m_selectionManager = new SelectionManager(view);
- connect(m_selectionManager, SIGNAL(selectionChanged()),
- this, SLOT(requestActivation()));
- connect(viewModeController, SIGNAL(urlChanged(const KUrl&)),
- m_selectionManager, SLOT(reset()));
-
- // initialize auto scroller
- m_autoScroller = new DolphinViewAutoScroller(view);
-
- // initialize file item delegate
- m_fileItemDelegate = new DolphinFileItemDelegate(view);
- m_fileItemDelegate->setShowToolTipWhenElided(false);
- view->setItemDelegate(m_fileItemDelegate);
-
- // initialize version control observer
- const DolphinView* dolphinView = dolphinViewController->view();
- m_versionControlObserver = new VersionControlObserver(view);
- connect(m_versionControlObserver, SIGNAL(infoMessage(const QString&)),
- dolphinView, SIGNAL(infoMessage(const QString&)));
- connect(m_versionControlObserver, SIGNAL(errorMessage(const QString&)),
- dolphinView, SIGNAL(errorMessage(const QString&)));
- connect(m_versionControlObserver, SIGNAL(operationCompletedMessage(const QString&)),
- dolphinView, SIGNAL(operationCompletedMessage(const QString&)));
- connect(dolphinViewController, SIGNAL(requestVersionControlActions(const KFileItemList&)),
- this, SLOT(slotRequestVersionControlActions(const KFileItemList&)));
-
- // react on view property changes
- connect(dolphinView, SIGNAL(showHiddenFilesChanged()),
- this, SLOT(slotShowHiddenFilesChanged()));
- connect(dolphinView, SIGNAL(sortingChanged(DolphinView::Sorting)),
- this, SLOT(slotSortingChanged(DolphinView::Sorting)));
- connect(dolphinView, SIGNAL(sortOrderChanged(Qt::SortOrder)),
- this, SLOT(slotSortOrderChanged(Qt::SortOrder)));
- connect(dolphinView, SIGNAL(sortFoldersFirstChanged(bool)),
- this, SLOT(slotSortFoldersFirstChanged(bool)));
-
- // Give the view the ability to auto-expand its directories on hovering
- // (the column view takes care about this itself). If the details view
- // uses expandable folders, the auto-expanding should be used always.
- m_folderExpander = new FolderExpander(view, proxyModel());
- m_folderExpander->setEnabled(settings->autoExpandFolders());
- connect(m_folderExpander, SIGNAL(enterDir(const QModelIndex&)),
- dolphinViewController, SLOT(triggerItem(const QModelIndex&)));
-
- // react on namefilter changes
- connect(viewModeController, SIGNAL(nameFilterChanged(const QString&)),
- this, SLOT(slotNameFilterChanged(const QString&)));
-
- view->viewport()->installEventFilter(this);
-}
-
-ViewExtensionsFactory::~ViewExtensionsFactory()
-{
-}
-
-void ViewExtensionsFactory::handleCurrentIndexChange(const QModelIndex& current, const QModelIndex& previous)
-{
- m_autoScroller->handleCurrentIndexChange(current, previous);
-}
-
-DolphinFileItemDelegate* ViewExtensionsFactory::fileItemDelegate() const
-{
- return m_fileItemDelegate;
-}
-
-void ViewExtensionsFactory::setAutoFolderExpandingEnabled(bool enabled)
-{
- m_folderExpander->setEnabled(enabled);
-}
-
-bool ViewExtensionsFactory::autoFolderExpandingEnabled() const
-{
- return m_folderExpander->enabled();
-}
-
-bool ViewExtensionsFactory::eventFilter(QObject* watched, QEvent* event)
-{
- Q_UNUSED(watched);
- if ((event->type() == QEvent::Wheel) && m_selectionManager) {
- m_selectionManager->reset();
- }
- return false;
-}
-
-void ViewExtensionsFactory::slotZoomLevelChanged()
-{
- m_previewGenerator->updateIcons();
- if (m_selectionManager) {
- m_selectionManager->reset();
- }
-}
-
-void ViewExtensionsFactory::cancelPreviews()
-{
- m_previewGenerator->cancelPreviews();
-}
-
-void ViewExtensionsFactory::slotShowPreviewChanged()
-{
- const bool show = m_dolphinViewController->view()->showPreview();
- m_previewGenerator->setPreviewShown(show);
-}
-
-void ViewExtensionsFactory::slotShowHiddenFilesChanged()
-{
- KDirModel* dirModel = static_cast<KDirModel*>(proxyModel()->sourceModel());
- KDirLister* dirLister = dirModel->dirLister();
-
- dirLister->stop();
-
- const bool show = m_dolphinViewController->view()->showHiddenFiles();
- dirLister->setShowingDotFiles(show);
-
- const KUrl url = dirLister->url();
- if (url.isValid()) {
- dirLister->openUrl(url, KDirLister::NoFlags);
- }
-}
-
-void ViewExtensionsFactory::slotSortingChanged(DolphinView::Sorting sorting)
-{
- proxyModel()->setSorting(sorting);
-}
-
-void ViewExtensionsFactory::slotSortOrderChanged(Qt::SortOrder order)
-{
- proxyModel()->setSortOrder(order);
-}
-
-void ViewExtensionsFactory::slotSortFoldersFirstChanged(bool foldersFirst)
-{
- proxyModel()->setSortFoldersFirst(foldersFirst);
-}
-
-void ViewExtensionsFactory::slotNameFilterChanged(const QString& nameFilter)
-{
- proxyModel()->setFilterFixedString(nameFilter);
-}
-
-void ViewExtensionsFactory::slotRequestVersionControlActions(const KFileItemList& items)
-{
- QList<QAction*> actions;
- if (items.isEmpty()) {
- const KDirModel* dirModel = static_cast<const KDirModel*>(proxyModel()->sourceModel());
- const KUrl url = dirModel->dirLister()->url();
- actions = m_versionControlObserver->contextMenuActions(url.path(KUrl::AddTrailingSlash));
- } else {
- actions = m_versionControlObserver->contextMenuActions(items);
- }
- m_dolphinViewController->setVersionControlActions(actions);
-}
-
-void ViewExtensionsFactory::requestActivation()
-{
- m_dolphinViewController->requestActivation();
-}
-
-DolphinSortFilterProxyModel* ViewExtensionsFactory::proxyModel() const
-{
- return static_cast<DolphinSortFilterProxyModel*>(m_view->model());
-}
-
-#include "viewextensionsfactory.moc"
-
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2009 by Peter Penz <peter.penz19@gmail.com> *
- * *
- * 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 VIEWEXTENSIONSFACTORY_H
-#define VIEWEXTENSIONSFACTORY_H
-
-#include <QObject>
-
-#include "dolphinview.h"
-
-class DolphinFileItemDelegate;
-class DolphinSortFilterProxyModel;
-class DolphinViewAutoScroller;
-class KFilePreviewGenerator;
-class FolderExpander;
-class QModelIndex;
-class SelectionManager;
-class ToolTipManager;
-class QAbstractItemView;
-class VersionControlObserver;
-class ViewModeController;
-
-/**
- * @brief Responsible for creating extensions like tooltips and previews
- * that are available in all view implementations.
- *
- * Each view implementation (iconsview, detailsview, columnview) must
- * instantiate an instance of this class to assure having
- * a common behavior that is independent from the custom functionality of
- * a view implementation.
- */
-class ViewExtensionsFactory : public QObject
-{
- Q_OBJECT
-
-public:
- explicit ViewExtensionsFactory(QAbstractItemView* view,
- DolphinViewController* dolphinViewController,
- const ViewModeController* viewModeController);
- virtual ~ViewExtensionsFactory();
-
- /**
- * Must be invoked by the item view, when QAbstractItemView::currentChanged()
- * has been called. Assures that the current item stays visible when it has been
- * changed by the keyboard.
- */
- void handleCurrentIndexChange(const QModelIndex& current, const QModelIndex& previous);
-
- DolphinFileItemDelegate* fileItemDelegate() const;
-
- /**
- * Enables the automatically expanding of a folder when dragging
- * items above the folder.
- */
- void setAutoFolderExpandingEnabled(bool enabled);
- bool autoFolderExpandingEnabled() const;
-
-protected:
- virtual bool eventFilter(QObject* watched, QEvent* event);
-
-private slots:
- void slotZoomLevelChanged();
- void cancelPreviews();
- void slotShowPreviewChanged();
- void slotShowHiddenFilesChanged();
- void slotSortingChanged(DolphinView::Sorting sorting);
- void slotSortOrderChanged(Qt::SortOrder order);
- void slotSortFoldersFirstChanged(bool foldersFirst);
- void slotNameFilterChanged(const QString& nameFilter);
- void slotRequestVersionControlActions(const KFileItemList& items);
- void requestActivation();
-
-private:
- DolphinSortFilterProxyModel* proxyModel() const;
-
-private:
- QAbstractItemView* m_view;
- DolphinViewController* m_dolphinViewController;
- ToolTipManager* m_toolTipManager;
- KFilePreviewGenerator* m_previewGenerator;
- SelectionManager* m_selectionManager;
- DolphinViewAutoScroller* m_autoScroller;
- DolphinFileItemDelegate* m_fileItemDelegate;
- VersionControlObserver* m_versionControlObserver;
- FolderExpander* m_folderExpander;
-};
-
-#endif
-
namespace {
// String representation to mark the additional properties of
// the details view as customized by the user. See
- // ViewProperties::additionalInfoV2() for more information.
+ // ViewProperties::additionalInfoList() for more information.
const char* CustomizedDetailsString = "CustomizedDetails";
}
if (useDefaultProps) {
if (useDetailsViewWithPath) {
setViewMode(DolphinView::DetailsView);
- setAdditionalInfo(KFileItemDelegate::InformationList() << KFileItemDelegate::LocalPathOrUrl);
+ setAdditionalInfoList(QList<DolphinView::AdditionalInfo>() << DolphinView::PathInfo);
} else {
// The global view-properties act as default for directories without
// any view-property configuration
return static_cast<DolphinView::Mode>(m_node->viewMode());
}
-void ViewProperties::setShowPreview(bool show)
+void ViewProperties::setPreviewsShown(bool show)
{
- if (m_node->showPreview() != show) {
- m_node->setShowPreview(show);
+ if (m_node->previewsShown() != show) {
+ m_node->setPreviewsShown(show);
update();
}
}
-bool ViewProperties::showPreview() const
+bool ViewProperties::previewsShown() const
{
- return m_node->showPreview();
+ return m_node->previewsShown();
}
-void ViewProperties::setShowHiddenFiles(bool show)
+void ViewProperties::setHiddenFilesShown(bool show)
{
- if (m_node->showHiddenFiles() != show) {
- m_node->setShowHiddenFiles(show);
+ if (m_node->hiddenFilesShown() != show) {
+ m_node->setHiddenFilesShown(show);
update();
}
}
return m_node->categorizedSorting();
}
-bool ViewProperties::showHiddenFiles() const
+bool ViewProperties::hiddenFilesShown() const
{
- return m_node->showHiddenFiles();
+ return m_node->hiddenFilesShown();
}
void ViewProperties::setSorting(DolphinView::Sorting sorting)
return m_node->sortFoldersFirst();
}
-void ViewProperties::setAdditionalInfo(const KFileItemDelegate::InformationList& list)
+void ViewProperties::setAdditionalInfoList(const QList<DolphinView::AdditionalInfo>& list)
{
- // See ViewProperties::additionalInfoV2() for the storage format
+ // See ViewProperties::additionalInfoList() for the storage format
// of the additional information.
// Remove the old values stored for the current view-mode
- const QStringList oldInfoStringList = m_node->additionalInfoV2();
+ const QStringList oldInfoStringList = m_node->additionalInfo();
const QString prefix = viewModePrefix();
QStringList newInfoStringList = oldInfoStringList;
for (int i = newInfoStringList.count() - 1; i >= 0; --i) {
// Add the updated values for the current view-mode
AdditionalInfoAccessor& infoAccessor = AdditionalInfoAccessor::instance();
- foreach (KFileItemDelegate::Information info, list) {
+ foreach (DolphinView::AdditionalInfo info, list) {
newInfoStringList.append(prefix + infoAccessor.value(info));
}
}
if (changed) {
- if (m_node->version() < 2) {
- m_node->setVersion(2);
- }
-
const bool markCustomizedDetails = (m_node->viewMode() == DolphinView::DetailsView)
&& !newInfoStringList.contains(CustomizedDetailsString);
if (markCustomizedDetails) {
newInfoStringList.append(CustomizedDetailsString);
}
- m_node->setAdditionalInfoV2(newInfoStringList);
+ m_node->setAdditionalInfo(newInfoStringList);
update();
}
}
-KFileItemDelegate::InformationList ViewProperties::additionalInfo() const
+QList<DolphinView::AdditionalInfo> ViewProperties::additionalInfoList() const
{
- KFileItemDelegate::InformationList usedInfo;
+ // The shown additional information is stored for each view-mode separately as
+ // string with the view-mode as prefix. Example:
+ //
+ // AdditionalInfo=Details_Size,Details_Date,Details_Owner,Icon_Size
+ //
+ // To get the representation as QList<DolphinView::AdditionalInfo>, the current
+ // view-mode must be checked and the values of this mode added to the list.
+ //
+ // For the details-view a special case must be respected: Per default the size
+ // and date should be shown without creating a .directory file. Only if
+ // the user explictly has modified the properties of the details view (marked
+ // by "CustomizedDetails"), also a details-view with no additional information
+ // is accepted.
+
+ QList<DolphinView::AdditionalInfo> usedInfo;
+
+ // infoHash allows to get the mapped DolphinView::AdditionalInfo value
+ // for a stored string-value in a fast way
+ static QHash<QString, DolphinView::AdditionalInfo> infoHash;
+ if (infoHash.isEmpty()) {
+ AdditionalInfoAccessor& infoAccessor = AdditionalInfoAccessor::instance();
+ const QList<DolphinView::AdditionalInfo> keys = infoAccessor.keys();
+ foreach (DolphinView::AdditionalInfo key, keys) {
+ infoHash.insert(infoAccessor.value(key), key);
+ }
+ }
+
+ // Iterate through all stored keys stored as strings and map them to
+ // the corresponding DolphinView::AdditionalInfo values.
+ const QString prefix = viewModePrefix();
+ const int prefixLength = prefix.length();
+ const QStringList infoStringList = m_node->additionalInfo();
+ foreach (const QString& infoString, infoStringList) {
+ if (infoString.startsWith(prefix)) {
+ const QString key = infoString.right(infoString.length() - prefixLength);
+ if (infoHash.contains(key)) {
+ usedInfo.append(infoHash.value(key));
+ } else {
+ kWarning() << "Did not find the key" << key << "in the information string";
+ }
+ }
+ }
- switch (m_node->version()) {
- case 1: usedInfo = additionalInfoV1(); break;
- case 2: usedInfo = additionalInfoV2(); break;
- default: kWarning() << "Unknown version of the view properties";
+ // For the details view the size and date should be shown per default
+ // until the additional information has been explicitly changed by the user
+ const bool useDefaultValues = usedInfo.isEmpty()
+ && (m_node->viewMode() == DolphinView::DetailsView)
+ && !infoStringList.contains(CustomizedDetailsString);
+ Q_UNUSED(useDefaultValues);
+ if (useDefaultValues) {
+ usedInfo.append(DolphinView::SizeInfo);
+ usedInfo.append(DolphinView::DateInfo);
}
return usedInfo;
}
-
void ViewProperties::setDirProperties(const ViewProperties& props)
{
setViewMode(props.viewMode());
- setShowPreview(props.showPreview());
- setShowHiddenFiles(props.showHiddenFiles());
+ setPreviewsShown(props.previewsShown());
+ setHiddenFilesShown(props.hiddenFilesShown());
setCategorizedSorting(props.categorizedSorting());
setSorting(props.sorting());
setSortOrder(props.sortOrder());
setSortFoldersFirst(props.sortFoldersFirst());
- setAdditionalInfo(props.additionalInfo());
+ setAdditionalInfoList(props.additionalInfoList());
}
void ViewProperties::setAutoSaveEnabled(bool autoSave)
{
m_changedProps = true;
m_node->setTimestamp(QDateTime::currentDateTime());
-
- // If the view-properties are stored in an older format, take
- // care to update them to the current format.
- switch (m_node->version()) {
- case 1: {
- const KFileItemDelegate::InformationList infoList = additionalInfoV1();
- m_node->setVersion(2);
- setAdditionalInfo(infoList);
- break;
- }
- case 2:
- // Current version. Nothing needs to get converted.
- break;
- default:
- kWarning() << "Unknown version of the view properties";
- }
}
void ViewProperties::save()
return KStandardDirs::locateLocal("data", basePath);
}
-KFileItemDelegate::InformationList ViewProperties::additionalInfoV1() const
-{
- KFileItemDelegate::InformationList usedInfo;
-
- int decodedInfo = m_node->additionalInfo();
-
- switch (viewMode()) {
- case DolphinView::DetailsView:
- decodedInfo = decodedInfo & 0xFF;
- if (decodedInfo == 0) {
- // A details view without any additional info makes no sense, hence
- // provide at least a size-info and date-info as fallback
- AdditionalInfoAccessor& infoAccessor = AdditionalInfoAccessor::instance();
- decodedInfo = infoAccessor.bitValue(KFileItemDelegate::Size) |
- infoAccessor.bitValue(KFileItemDelegate::ModificationTime);
- }
- break;
- case DolphinView::IconsView:
- decodedInfo = (decodedInfo >> 8) & 0xFF;
- break;
- case DolphinView::ColumnView:
- decodedInfo = (decodedInfo >> 16) & 0xFF;
- break;
- default: break;
- }
-
- AdditionalInfoAccessor& infoAccessor = AdditionalInfoAccessor::instance();
- const KFileItemDelegate::InformationList infoKeys = infoAccessor.keys();
-
- foreach (const KFileItemDelegate::Information info, infoKeys) {
- if (decodedInfo & infoAccessor.bitValue(info)) {
- usedInfo.append(info);
- }
- }
-
- return usedInfo;
-}
-
-KFileItemDelegate::InformationList ViewProperties::additionalInfoV2() const
-{
- // The shown additional information is stored for each view-mode separately as
- // string with the view-mode as prefix. Example:
- //
- // AdditionalInfoV2=Details_Size,Details_Date,Details_Owner,Icon_Size
- //
- // To get the representation as KFileItemDelegate::InformationList, the current
- // view-mode must be checked and the values of this mode added to the list.
- //
- // For the details-view a special case must be respected: Per default the size
- // and date should be shown without creating a .directory file. Only if
- // the user explictly has modified the properties of the details view (marked
- // by "CustomizedDetails"), also a details-view with no additional information
- // is accepted.
-
- KFileItemDelegate::InformationList usedInfo;
-
- // infoHash allows to get the mapped KFileItemDelegate::Information value
- // for a stored string-value in a fast way
- static QHash<QString, KFileItemDelegate::Information> infoHash;
- if (infoHash.isEmpty()) {
- AdditionalInfoAccessor& infoAccessor = AdditionalInfoAccessor::instance();
- const KFileItemDelegate::InformationList keys = infoAccessor.keys();
- foreach (const KFileItemDelegate::Information key, keys) {
- infoHash.insert(infoAccessor.value(key), key);
- }
- }
-
- // Iterate through all stored keys stored as strings and map them to
- // the corresponding KFileItemDelegate::Information values.
- const QString prefix = viewModePrefix();
- const int prefixLength = prefix.length();
- const QStringList infoStringList = m_node->additionalInfoV2();
- foreach (const QString& infoString, infoStringList) {
- if (infoString.startsWith(prefix)) {
- const QString key = infoString.right(infoString.length() - prefixLength);
- Q_ASSERT(infoHash.contains(key));
- usedInfo.append(infoHash.value(key));
- }
- }
-
- // For the details view the size and date should be shown per default
- // until the additional information has been explicitly changed by the user
- const bool useDefaultValues = usedInfo.isEmpty()
- && (m_node->viewMode() == DolphinView::DetailsView)
- && !infoStringList.contains(CustomizedDetailsString);
- if (useDefaultValues) {
- usedInfo.append(KFileItemDelegate::Size);
- usedInfo.append(KFileItemDelegate::ModificationTime);
- }
-
- return usedInfo;
-}
-
QString ViewProperties::viewModePrefix() const
{
QString prefix;
switch (m_node->viewMode()) {
- case DolphinView::DetailsView: prefix = "Details_"; break;
case DolphinView::IconsView: prefix = "Icons_"; break;
- case DolphinView::ColumnView: prefix = "Column_"; break;
+ case DolphinView::CompactView: prefix = "Compact_"; break;
+ case DolphinView::DetailsView: prefix = "Details_"; break;
default: kWarning() << "Unknown view-mode of the view properties";
}
* \code
* ViewProperties props(KUrl("/home/peter/Documents"));
* const DolphinView::Mode mode = props.viewMode();
- * const bool showHiddenFiles = props.isShowHiddenFilesEnabled();
+ * const bool hiddenFilesShown = props.hiddenFilesShown();
* \endcode
*
* When modifying a view property, the '.directory' file is automatically updated
void setViewMode(DolphinView::Mode mode);
DolphinView::Mode viewMode() const;
- void setShowPreview(bool show);
- bool showPreview() const;
+ void setPreviewsShown(bool show);
+ bool previewsShown() const;
- void setShowHiddenFiles(bool show);
- bool showHiddenFiles() const;
+ void setHiddenFilesShown(bool show);
+ bool hiddenFilesShown() const;
void setCategorizedSorting(bool categorized);
bool categorizedSorting() const;
* Note that the additional-info property is the only property where
* the value is dependent from another property (in this case the view-mode).
*/
- void setAdditionalInfo(const KFileItemDelegate::InformationList& info);
+ void setAdditionalInfoList(const QList<DolphinView::AdditionalInfo>& info);
/**
* Returns the additional information for the current set view-mode.
* Note that the additional-info property is the only property where
* the value is dependent from another property (in this case the view-mode).
*/
- KFileItemDelegate::InformationList additionalInfo() const;
+ QList<DolphinView::AdditionalInfo> additionalInfoList() const;
/**
* Sets the directory properties view mode, show preview,
*/
QString destinationDir(const QString& subDir) const;
- /**
- * Helper method for ViewProperties::additionalInfo(): Returns
- * the additional info for the outdated version 1 of the view-properties.
- */
- KFileItemDelegate::InformationList additionalInfoV1() const;
-
- /**
- * Helper method for ViewProperties::additionalInfo(): Returns
- * the additional info for the current version 2 of the view-properties.
- */
- KFileItemDelegate::InformationList additionalInfoV2() const;
-
/**
* Returns the view-mode prefix when storing additional properties for
* a view-mode.