#include <QTimer>
#include <QScrollBar>
+#include <KDesktopFile>
+#include <KProtocolManager>
#include <KActionCollection>
#include <KColorScheme>
#include <KDirModel>
#include "zoomlevelinfo.h"
#ifdef HAVE_NEPOMUK
- #include <Nepomuk/ResourceManager>
+ #include <Nepomuk2/ResourceManager>
#endif
namespace {
m_scrollToCurrentItem(false),
m_restoredContentsPosition(),
m_selectedUrls(),
+ m_clearSelectionBeforeSelectingNewItems(false),
+ m_markFirstNewlySelectedItemAsCurrent(false),
m_versionControlObserver(0)
{
m_topLayout = new QVBoxLayout(this);
m_model = new KFileItemModel(this);
m_view = new DolphinItemListView();
m_view->setEnabledSelectionToggles(GeneralSettings::showSelectionToggle());
- m_view->setEnlargeSmallPreviews(GeneralSettings::enlargeSmallPreviews());
m_view->setVisibleRoles(QList<QByteArray>() << "text");
applyModeToView();
const int delay = GeneralSettings::autoExpandFolders() ? 750 : -1;
controller->setAutoActivationDelay(delay);
+ // The EnlargeSmallPreviews setting can only be changed after the model
+ // has been set in the view by KItemListController.
+ m_view->setEnlargeSmallPreviews(GeneralSettings::enlargeSmallPreviews());
+
m_container = new KItemListContainer(controller, this);
m_container->installEventFilter(this);
setFocusProxy(m_container);
connect(m_model, SIGNAL(directoryLoadingStarted()), this, SLOT(slotDirectoryLoadingStarted()));
connect(m_model, SIGNAL(directoryLoadingCompleted()), this, SLOT(slotDirectoryLoadingCompleted()));
+ connect(m_model, SIGNAL(directoryLoadingCanceled()), this, SIGNAL(directoryLoadingCanceled()));
connect(m_model, SIGNAL(directoryLoadingProgress(int)), this, SIGNAL(directoryLoadingProgress(int)));
connect(m_model, SIGNAL(directorySortingProgress(int)), this, SIGNAL(directorySortingProgress(int)));
connect(m_model, SIGNAL(itemsChanged(KItemRangeList,QSet<QByteArray>)),
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(int,QByteArray,QVariant)));
connect(m_view->header(), SIGNAL(columnWidthChanged(QByteArray,qreal,qreal)),
this, SLOT(slotHeaderColumnWidthChanged(QByteArray,qreal,qreal)));
KFileItemList DolphinView::selectedItems() const
{
const KItemListSelectionManager* selectionManager = m_container->controller()->selectionManager();
- const QSet<int> selectedIndexes = selectionManager->selectedItems();
+ QList<int> selectedIndexes = selectionManager->selectedItems().toList();
+
+ qSort(selectedIndexes);
KFileItemList selectedItems;
- QSetIterator<int> it(selectedIndexes);
+ QListIterator<int> it(selectedIndexes);
while (it.hasNext()) {
const int index = it.next();
selectedItems.append(m_model->fileItem(index));
return m_model->nameFilter();
}
+void DolphinView::setMimeTypeFilters(const QStringList& filters)
+{
+ return m_model->setMimeTypeFilters(filters);
+}
+
+QStringList DolphinView::mimeTypeFilters() const
+{
+ return m_model->mimeTypeFilters();
+}
+
QString DolphinView::statusBarText() const
{
QString summary;
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) {
- 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");
+
+ 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()
QWidget::hideEvent(event);
}
+bool DolphinView::event(QEvent* event)
+{
+ /* See Bug 297355
+ * Dolphin leaves file preview tooltips open even when is not visible.
+ *
+ * Hide tool-tip when Dolphin loses focus.
+ */
+ if (event->type() == QEvent::WindowDeactivate) {
+ hideToolTip();
+ }
+
+ return QWidget::event(event);
+}
+
void DolphinView::activate()
{
setActive(true);
{
Q_ASSERT(indexes.count() >= 2);
+ 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;
+ }
+ }
+
KFileItemList items;
+ items.reserve(indexes.count());
QSetIterator<int> it(indexes);
while (it.hasNext()) {
const int index = it.next();
- items.append(m_model->fileItem(index));
- }
+ KFileItem item = m_model->fileItem(index);
+ const KUrl& url = openItemAsFolderUrl(item);
- foreach (const KFileItem& item, items) {
- if (item.isDir()) {
- emit tabRequested(item.url());
+ 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());
}
}
bool nepomukRunning = false;
bool indexingEnabled = false;
#ifdef HAVE_NEPOMUK
- nepomukRunning = (Nepomuk::ResourceManager::instance()->initialized());
+ nepomukRunning = (Nepomuk2::ResourceManager::instance()->initialized());
if (nepomukRunning) {
KConfig config("nepomukserverrc");
- indexingEnabled = config.group("Service-nepomukfileindexer").readEntry("autostart", false);
+ indexingEnabled = config.group("Service-nepomukfileindexer").readEntry("autostart", true);
}
#endif
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(urlPasted(KUrl)), this, SLOT(slotUrlPasted(KUrl)));
}
+
+ setActive(true);
}
void DolphinView::slotModelChanged(KItemModelBase* current, KItemModelBase* previous)
}
}
+void DolphinView::slotAboutToCreate(const KUrl::List& urls)
+{
+ if (!urls.isEmpty()) {
+ if (m_markFirstNewlySelectedItemAsCurrent) {
+ markUrlAsCurrent(urls.first());
+ m_markFirstNewlySelectedItemAsCurrent = false;
+ }
+ m_selectedUrls << urls;
+ }
+}
+
void DolphinView::slotSelectionChanged(const QSet<int>& current, const QSet<int>& previous)
{
const int currentCount = current.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
+ KDesktopFile desktopFile(url.toLocalFile());
+ if (desktopFile.hasLinkType()) {
+ return desktopFile.readUrl();
+ }
+ }
+ }
+
+ 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();
+
+ if (m_clearSelectionBeforeSelectingNewItems) {
+ selectionManager->clearSelection();
+ m_clearSelectionBeforeSelectingNewItems = false;
+ }
+
QSet<int> selectedItems = selectionManager->selectedItems();
- foreach (const KUrl& url, m_selectedUrls) {
- const int index = m_model->index(url);
+ 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(int index, const QByteArray& role, const QVariant& value)
+{
+ 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 (role == "text") {
const KFileItem oldItem = m_model->fileItem(index);
const QString newName = value.toString();
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) {
+ connect(op, SIGNAL(renamingFailed(KUrl,KUrl)), SLOT(slotRenamingFailed(KUrl,KUrl)));
+ }
}
}
}
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
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;