#include "dolphinview.h"
-#include <config-nepomuk.h>
+#include <config-baloo.h>
#include <QAbstractItemView>
#include <QApplication>
#include <QTimer>
#include <QScrollBar>
+#include <KDesktopFile>
+#include <KProtocolManager>
#include <KActionCollection>
#include <KColorScheme>
#include <KDirModel>
#include "views/tooltips/tooltipmanager.h"
#include "zoomlevelinfo.h"
-#ifdef HAVE_NEPOMUK
- #include <Nepomuk2/ResourceManager>
+#ifdef HAVE_BALOO
+ #include <baloo/indexerconfig.h>
#endif
namespace {
m_scrollToCurrentItem(false),
m_restoredContentsPosition(),
m_selectedUrls(),
+ m_clearSelectionBeforeSelectingNewItems(false),
+ m_markFirstNewlySelectedItemAsCurrent(false),
m_versionControlObserver(0)
{
m_topLayout = new QVBoxLayout(this);
controller->setSelectionBehavior(KItemListController::MultiSelection);
connect(controller, SIGNAL(itemActivated(int)), this, SLOT(slotItemActivated(int)));
- connect(controller, SIGNAL(itemsActivated(QSet<int>)), this, SLOT(slotItemsActivated(QSet<int>)));
+ connect(controller, SIGNAL(itemsActivated(KItemSet)), this, SLOT(slotItemsActivated(KItemSet)));
connect(controller, SIGNAL(itemMiddleClicked(int)), this, SLOT(slotItemMiddleClicked(int)));
connect(controller, SIGNAL(itemContextMenuRequested(int,QPointF)), this, SLOT(slotItemContextMenuRequested(int,QPointF)));
connect(controller, SIGNAL(viewContextMenuRequested(QPointF)), this, SLOT(slotViewContextMenuRequested(QPointF)));
connect(controller, SIGNAL(itemHovered(int)), this, SLOT(slotItemHovered(int)));
connect(controller, SIGNAL(itemUnhovered(int)), this, SLOT(slotItemUnhovered(int)));
connect(controller, SIGNAL(itemDropEvent(int,QGraphicsSceneDragDropEvent*)), this, SLOT(slotItemDropEvent(int,QGraphicsSceneDragDropEvent*)));
+ connect(controller, SIGNAL(escapePressed()), this, SLOT(stopLoading()));
connect(controller, SIGNAL(modelChanged(KItemModelBase*,KItemModelBase*)), this, SLOT(slotModelChanged(KItemModelBase*,KItemModelBase*)));
connect(m_model, SIGNAL(directoryLoadingStarted()), this, SLOT(slotDirectoryLoadingStarted()));
this, SLOT(slotSortRoleChangedByHeader(QByteArray,QByteArray)));
connect(m_view, SIGNAL(visibleRolesChanged(QList<QByteArray>,QList<QByteArray>)),
this, SLOT(slotVisibleRolesChangedByHeader(QList<QByteArray>,QList<QByteArray>)));
- connect(m_view, SIGNAL(roleEditingFinished(int,QByteArray,QVariant)),
- this, SLOT(slotRoleEditingFinished(int,QByteArray,QVariant)));
+ connect(m_view, SIGNAL(roleEditingCanceled(int,QByteArray,QVariant)),
+ this, SLOT(slotRoleEditingCanceled()));
connect(m_view->header(), SIGNAL(columnWidthChanged(QByteArray,qreal,qreal)),
this, SLOT(slotHeaderColumnWidthChanged(QByteArray,qreal,qreal)));
KItemListSelectionManager* selectionManager = controller->selectionManager();
- connect(selectionManager, SIGNAL(selectionChanged(QSet<int>,QSet<int>)),
- this, SLOT(slotSelectionChanged(QSet<int>,QSet<int>)));
+ connect(selectionManager, SIGNAL(selectionChanged(KItemSet,KItemSet)),
+ this, SLOT(slotSelectionChanged(KItemSet,KItemSet)));
m_toolTipManager = new ToolTipManager(this);
if (mode != m_mode) {
ViewProperties props(viewPropertiesUrl());
props.setViewMode(mode);
- props.save();
- applyViewProperties();
+ // We pass the new ViewProperties to applyViewProperties, rather than
+ // storing them on disk and letting applyViewProperties() read them
+ // from there, to prevent that changing the view mode fails if the
+ // .directory file is not writable (see bug 318534).
+ applyViewProperties(props);
}
}
KFileItemList DolphinView::selectedItems() const
{
const KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
- const QSet<int> selectedIndexes = selectionManager->selectedItems();
KFileItemList selectedItems;
- QSetIterator<int> it(selectedIndexes);
- while (it.hasNext()) {
- const int index = it.next();
+ foreach (int index, selectionManager->selectedItems()) {
selectedItems.append(m_model->fileItem(index));
}
return selectedItems;
for (int index = 0; index < m_model->count(); index++) {
const KFileItem item = m_model->fileItem(index);
if (pattern.exactMatch(item.text())) {
- // An alternative approach would be to store the matching items in a QSet<int> and
+ // An alternative approach would be to store the matching items in a KItemSet and
// select them in one go after the loop, but we'd need a new function
- // KItemListSelectionManager::setSelected(QSet<int>, SelectionMode mode)
+ // KItemListSelectionManager::setSelected(KItemSet, SelectionMode mode)
// for that.
selectionManager->setSelected(index, 1, mode);
}
restoreState(restoreStream);
}
-void DolphinView::stopLoading()
-{
- m_model->cancelDirectoryLoading();
-}
-
void DolphinView::readSettings()
{
const int oldZoomLevel = m_view->zoomLevel();
}
if (folderCount + fileCount == 1) {
- // If only one item is selected, show the filename
- filesText = i18nc("@info:status", "<filename>%1</filename> selected", list.first().text());
+ // If only one item is selected, show info about it
+ return list.first().getStatusBarInfo();
} else {
// At least 2 items are selected
foldersText = i18ncp("@info:status", "1 Folder selected", "%1 Folders selected", folderCount);
return;
}
+ clearSelection();
+
emit urlAboutToBeChanged(url);
m_url = url;
hideToolTip();
+ disconnect(m_view, SIGNAL(roleEditingFinished(int,QByteArray,QVariant)),
+ this, SLOT(slotRoleEditingFinished(int,QByteArray,QVariant)));
+
// 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
void DolphinView::clearSelection()
{
+ m_selectedUrls.clear();
m_container->controller()->selectionManager()->clearSelection();
}
void DolphinView::renameSelectedItems()
{
const KFileItemList items = selectedItems();
- if (items.isEmpty()) {
- return;
- }
-
- if (items.count() == 1 && GeneralSettings::renameInline()) {
- const int index = m_model->index(items.first());
- m_view->editRole(index, "text");
- } 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 KFileItemModel
- // will notify the view about changed items (which might result in
- // a changed sorting).
- m_assureVisibleCurrentIndex = true;
+ if (items.isEmpty()) {
+ return;
+ }
+
+ if (items.count() == 1 && GeneralSettings::renameInline()) {
+ const int index = m_model->index(items.first());
+ m_view->editRole(index, "text");
+
+ hideToolTip();
+
+ connect(m_view, SIGNAL(roleEditingFinished(int,QByteArray,QVariant)),
+ this, SLOT(slotRoleEditingFinished(int,QByteArray,QVariant)));
+ } 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 KFileItemModel
+ // will notify the view about changed items (which might result in
+ // a changed sorting).
+ m_assureVisibleCurrentIndex = true;
}
void DolphinView::trashSelectedItems()
}
}
+void DolphinView::stopLoading()
+{
+ m_model->cancelDirectoryLoading();
+}
+
bool DolphinView::eventFilter(QObject* watched, QEvent* event)
{
switch (event->type()) {
}
}
-void DolphinView::slotItemsActivated(const QSet<int>& indexes)
+void DolphinView::slotItemsActivated(const KItemSet& indexes)
{
Q_ASSERT(indexes.count() >= 2);
- KFileItemList items;
-
- QSetIterator<int> it(indexes);
- while (it.hasNext()) {
- const int index = it.next();
- items.append(m_model->fileItem(index));
- }
-
- if (items.count() > 5) {
- QString question = QString("Are you sure you want to open %1 items?").arg(items.count());
+ if (indexes.count() > 5) {
+ QString question = i18np("Are you sure you want to open 1 item?", "Are you sure you want to open %1 items?", indexes.count());
const int answer = KMessageBox::warningYesNo(this, question);
if (answer != KMessageBox::Yes) {
return;
}
}
- foreach (const KFileItem& item, items) {
- if (item.isDir()) {
- emit tabRequested(item.url());
+ KFileItemList items;
+ items.reserve(indexes.count());
+
+ foreach (int index, indexes) {
+ KFileItem item = m_model->fileItem(index);
+ const KUrl& url = openItemAsFolderUrl(item);
+
+ if (!url.isEmpty()) { // Open folders in new tabs
+ emit tabRequested(url);
} else {
- emit itemActivated(item);
+ items.append(item);
}
}
+
+ if (items.count() == 1) {
+ emit itemActivated(items.first());
+ } else if (items.count() > 1) {
+ emit itemsActivated(items);
+ }
}
void DolphinView::slotItemMiddleClicked(int index)
{
- const KFileItem item = m_model->fileItem(index);
- if (item.isDir() || isTabsForFilesEnabled()) {
+ const KFileItem& item = m_model->fileItem(index);
+ const KUrl& url = openItemAsFolderUrl(item);
+ if (!url.isEmpty()) {
+ emit tabRequested(url);
+ } else if (isTabsForFilesEnabled()) {
emit tabRequested(item.url());
}
}
void DolphinView::slotItemContextMenuRequested(int index, const QPointF& pos)
{
+ // Force emit of a selection changed signal before we request the
+ // context menu, to update the edit-actions first. (See Bug 294013)
+ if (m_selectionChangedTimer->isActive()) {
+ emitSelectionChangedSignal();
+ }
+
const KFileItem item = m_model->fileItem(index);
emit requestContextMenu(pos.toPoint(), item, url(), QList<QAction*>());
}
KItemListView* view = m_container->controller()->view();
const QSet<QByteArray> visibleRolesSet = view->visibleRoles().toSet();
- bool nepomukRunning = false;
bool indexingEnabled = false;
-#ifdef HAVE_NEPOMUK
- nepomukRunning = (Nepomuk2::ResourceManager::instance()->initialized());
- if (nepomukRunning) {
- KConfig config("nepomukserverrc");
- indexingEnabled = config.group("Service-nepomukfileindexer").readEntry("autostart", false);
- }
+#ifdef HAVE_BALOO
+ Baloo::IndexerConfig config;
+ indexingEnabled = config.fileIndexingEnabled();
#endif
QString groupName;
action->setChecked(visibleRolesSet.contains(info.role));
action->setData(info.role);
- const bool enable = (!info.requiresNepomuk && !info.requiresIndexer) ||
- (info.requiresNepomuk && nepomukRunning) ||
+ const bool enable = (!info.requiresBaloo && !info.requiresIndexer) ||
+ (info.requiresBaloo) ||
(info.requiresIndexer && indexingEnabled);
action->setEnabled(enable);
}
event->buttons(),
event->modifiers());
- const QString error = DragAndDropHelper::dropUrls(destItem, destUrl, &dropEvent);
+ QString error;
+ KonqOperations* op = DragAndDropHelper::dropUrls(destItem, destUrl, &dropEvent, error);
if (!error.isEmpty()) {
- emit errorMessage(error);
+ emit infoMessage(error);
}
- if (destUrl == url()) {
+ if (op && destUrl == url()) {
// Mark the dropped urls as selected.
- markPastedUrlsAsSelected(event->mimeData());
+ m_clearSelectionBeforeSelectingNewItems = true;
+ connect(op, SIGNAL(aboutToCreate(KUrl::List)), this, SLOT(slotAboutToCreate(KUrl::List)));
}
+
+ setActive(true);
}
void DolphinView::slotModelChanged(KItemModelBase* current, KItemModelBase* previous)
}
}
-void DolphinView::slotSelectionChanged(const QSet<int>& current, const QSet<int>& previous)
+void DolphinView::slotAboutToCreate(const KUrl::List& urls)
+{
+ if (!urls.isEmpty()) {
+ if (m_markFirstNewlySelectedItemAsCurrent) {
+ markUrlAsCurrent(urls.first());
+ m_markFirstNewlySelectedItemAsCurrent = false;
+ }
+ m_selectedUrls << KDirModel::simplifiedUrlList(urls);
+ }
+}
+
+void DolphinView::slotSelectionChanged(const KItemSet& current, const KItemSet& previous)
{
const int currentCount = current.count();
const int previousCount = previous.count();
return m_viewPropertiesContext;
}
+KUrl DolphinView::openItemAsFolderUrl(const KFileItem& item, const bool browseThroughArchives)
+{
+ if (item.isNull()) {
+ return KUrl();
+ }
+
+ KUrl url = item.targetUrl();
+
+ if (item.isDir()) {
+ return url;
+ }
+
+ if (item.isMimeTypeKnown()) {
+ const QString& mimetype = item.mimetype();
+
+ 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(mimetype);
+ if (!protocol.isEmpty()) {
+ url.setProtocol(protocol);
+ return url;
+ }
+ }
+
+ if (mimetype == QLatin1String("application/x-desktop")) {
+ // Redirect to the URL in Type=Link desktop files, unless it is a http(s) URL.
+ KDesktopFile desktopFile(url.toLocalFile());
+ if (desktopFile.hasLinkType()) {
+ const QString linkUrl = desktopFile.readUrl();
+ if (!linkUrl.startsWith(QLatin1String("http"))) {
+ return linkUrl;
+ }
+ }
+ }
+ }
+
+ return KUrl();
+}
+
void DolphinView::observeCreatedItem(const KUrl& url)
{
- markUrlAsCurrent(url);
- markUrlsAsSelected(QList<KUrl>() << url);
+ if (m_active) {
+ clearSelection();
+ markUrlAsCurrent(url);
+ markUrlsAsSelected(QList<KUrl>() << url);
+ }
}
void DolphinView::slotDirectoryRedirection(const KUrl& oldUrl, const KUrl& newUrl)
m_view->scrollToItem(currentIndex);
m_scrollToCurrentItem = false;
}
+
+ m_currentItemUrl = KUrl();
} else {
selectionManager->setCurrentItem(0);
}
- m_currentItemUrl = KUrl();
}
if (!m_restoredContentsPosition.isNull()) {
}
if (!m_selectedUrls.isEmpty()) {
- clearSelection();
-
KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
- QSet<int> selectedItems = selectionManager->selectedItems();
- foreach (const KUrl& url, m_selectedUrls) {
- const int index = m_model->index(url);
+ if (m_clearSelectionBeforeSelectingNewItems) {
+ selectionManager->clearSelection();
+ m_clearSelectionBeforeSelectingNewItems = false;
+ }
+
+ KItemSet selectedItems = selectionManager->selectedItems();
+
+ QList<KUrl>::iterator it = m_selectedUrls.begin();
+ while (it != m_selectedUrls.end()) {
+ const int index = m_model->index(*it);
if (index >= 0) {
selectedItems.insert(index);
+ it = m_selectedUrls.erase(it);
+ } else {
+ ++it;
}
}
selectionManager->setSelectedItems(selectedItems);
- m_selectedUrls.clear();
}
}
}
}
+void DolphinView::slotRenamingFailed(const KUrl& oldUrl, const KUrl& newUrl)
+{
+ const int index = m_model->index(newUrl);
+ if (index >= 0) {
+ QHash<QByteArray, QVariant> data;
+ data.insert("text", oldUrl.fileName());
+ m_model->setData(index, data);
+ }
+}
+
void DolphinView::slotDirectoryLoadingStarted()
{
// Disable the writestate temporary until it can be determined in a fast way
emit visibleRolesChanged(m_visibleRoles, previousVisibleRoles);
}
+void DolphinView::slotRoleEditingCanceled()
+{
+ disconnect(m_view, SIGNAL(roleEditingFinished(int,QByteArray,QVariant)),
+ this, SLOT(slotRoleEditingFinished(int,QByteArray,QVariant)));
+}
+
void DolphinView::slotRoleEditingFinished(int index, const QByteArray& role, const QVariant& value)
{
+ disconnect(m_view, SIGNAL(roleEditingFinished(int,QByteArray,QVariant)),
+ this, SLOT(slotRoleEditingFinished(int,QByteArray,QVariant)));
+
if (index < 0 || index >= m_model->count()) {
return;
}
if (!newName.isEmpty() && newName != oldItem.text() && newName != QLatin1String(".") && newName != QLatin1String("..")) {
const KUrl oldUrl = oldItem.url();
- QHash<QByteArray, QVariant> data;
- data.insert(role, value);
- m_model->setData(index, data);
+ const KUrl newUrl(url().path(KUrl::AddTrailingSlash) + newName);
+ const bool newNameExistsAlready = (m_model->index(newUrl) >= 0);
+ if (!newNameExistsAlready) {
+ // Only change the data in the model if no item with the new name
+ // is in the model yet. If there is an item with the new name
+ // already, calling KonqOperations::rename() will open a dialog
+ // asking for a new name, and KFileItemModel will update the
+ // data when the dir lister signals that the file name has changed.
+ QHash<QByteArray, QVariant> data;
+ data.insert(role, value);
+ m_model->setData(index, data);
+ }
- KonqOperations::rename(this, oldUrl, newName);
+ KonqOperations* op = KonqOperations::renameV2(this, oldUrl, newName);
+ if (op && !newNameExistsAlready) {
+ // Only connect the renamingFailed signal if there is no item with the new name
+ // in the model yet, see bug 328262.
+ connect(op, SIGNAL(renamingFailed(KUrl,KUrl)), SLOT(slotRenamingFailed(KUrl,KUrl)));
+ }
}
}
}
void DolphinView::applyViewProperties()
{
- m_view->beginTransaction();
-
const ViewProperties props(viewPropertiesUrl());
+ applyViewProperties(props);
+}
+
+void DolphinView::applyViewProperties(const ViewProperties& props)
+{
+ m_view->beginTransaction();
const Mode mode = props.viewMode();
if (m_mode != mode) {
void DolphinView::pasteToUrl(const KUrl& url)
{
- markPastedUrlsAsSelected(QApplication::clipboard()->mimeData());
- KonqOperations::doPaste(this, url);
+ KonqOperations* op = KonqOperations::doPasteV2(this, url);
+ if (op) {
+ m_clearSelectionBeforeSelectingNewItems = true;
+ m_markFirstNewlySelectedItemAsCurrent = true;
+ connect(op, SIGNAL(aboutToCreate(KUrl::List)), this, SLOT(slotAboutToCreate(KUrl::List)));
+ }
}
KUrl::List DolphinView::simplifiedSelectedUrls() const
QMimeData* DolphinView::selectionMimeData() const
{
const KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
- const QSet<int> selectedIndexes = selectionManager->selectedItems();
+ const KItemSet selectedIndexes = selectionManager->selectedItems();
return m_model->createMimeData(selectedIndexes);
}
-void DolphinView::markPastedUrlsAsSelected(const QMimeData* mimeData)
-{
- const KUrl::List sourceUrls = KUrl::List::fromMimeData(mimeData);
- KUrl::List destUrls;
- foreach (const KUrl& source, sourceUrls) {
- KUrl destination(url().url() + '/' + source.fileName());
- destUrls << destination;
- }
- markUrlsAsSelected(destUrls);
-}
-
void DolphinView::updateWritableState()
{
const bool wasFolderWritable = m_isFolderWritable;
- m_isFolderWritable = true;
+ m_isFolderWritable = false;
const KFileItem item = m_model->rootItem();
if (!item.isNull()) {