add more spacing
[personal-kdebase.git] / apps / plasma / applets / folderview / folderview.cpp
blob1fcb8a1bb312ee2ec5c7d0d3c875abf9dace92e4
1 /*
2 * Copyright © 2008 Fredrik Höglund <fredrik@kde.org>
3 * Copyright © 2008 Rafael Fernández López <ereslibre@kde.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
21 #include "folderview.h"
23 #include <QApplication>
24 #include <QClipboard>
25 #include <QDebug>
26 #include <QDesktopServices>
27 #include <QDrag>
28 #include <QGraphicsLinearLayout>
29 #include <QGraphicsView>
30 #include <QGraphicsSceneDragDropEvent>
31 #include <QItemSelectionModel>
32 #include <QScrollBar>
34 #include <KAction>
35 #include <KAuthorized>
36 #include <KBookmarkManager>
37 #include <KConfigDialog>
38 #include <KDesktopFile>
39 #include <KDirModel>
40 #include <KFileItemDelegate>
41 #include <kfileplacesmodel.h>
42 #include <kfilepreviewgenerator.h>
43 #include <KGlobalSettings>
44 #include <KMenu>
45 #include <KStandardShortcut>
46 #include <KStringHandler>
48 #include <kio/fileundomanager.h>
49 #include <kio/paste.h>
50 #include <KParts/BrowserExtension>
52 #include <knewmenu.h>
53 #include <konqmimedata.h>
54 #include <konq_operations.h>
55 #include <konq_popupmenu.h>
57 #include <limits.h>
59 #include "plasma/corona.h"
60 #include "plasma/paintutils.h"
61 #include "plasma/theme.h"
62 #include "plasma/tooltipmanager.h"
64 #include "dirlister.h"
65 #include "dialog.h"
66 #include "folderviewadapter.h"
67 #include "iconview.h"
68 #include "iconwidget.h"
69 #include "label.h"
70 #include "previewpluginsmodel.h"
71 #include "proxymodel.h"
72 #include "listview.h"
75 K_EXPORT_PLASMA_APPLET(folderview, FolderView)
77 MimeModel::MimeModel(QObject *parent)
78 : QStringListModel(parent)
80 m_mimetypes = KMimeType::allMimeTypes();
83 QVariant MimeModel::data(const QModelIndex &index, int role) const
85 if (!index.isValid()) {
86 return QVariant();
88 KMimeType *mime = static_cast<KMimeType*>(index.internalPointer());
89 switch (role) {
90 case Qt::DisplayRole: {
91 if (!mime->comment().isEmpty()) {
92 QString description;
93 if (mime->patterns().count()) {
94 description = mime->patterns().join(", ");
95 } else {
96 description = mime->name();
98 return QString("%1 (%2)").arg(mime->comment()).arg(description);
99 } else {
100 return mime->name();
103 case Qt::DecorationRole:
104 return KIcon(mime->iconName());
105 case Qt::CheckStateRole:
106 return m_state[mime];
107 default:
108 return QStringListModel::data(index, role);
112 Qt::ItemFlags MimeModel::flags(const QModelIndex &index) const
114 Qt::ItemFlags itemFlags = QStringListModel::flags(index);
115 itemFlags &= ~Qt::ItemIsEditable;
116 if (!index.isValid()) {
117 return itemFlags;
119 return itemFlags | Qt::ItemIsUserCheckable;
122 QModelIndex MimeModel::index(int row, int column, const QModelIndex &parent) const
124 if (parent.isValid() || row >= m_mimetypes.count()) {
125 return QModelIndex();
127 return createIndex(row, column, (void*) m_mimetypes[row].data());
130 int MimeModel::rowCount(const QModelIndex &parent) const
132 if (parent.isValid()) {
133 return 0;
135 return m_mimetypes.count();
138 bool MimeModel::setData(const QModelIndex &index, const QVariant &value, int role)
140 if (!index.isValid()) {
141 return false;
144 if (role == Qt::CheckStateRole) {
145 KMimeType *mime = static_cast<KMimeType*>(index.internalPointer());
146 m_state[mime] = (Qt::CheckState) value.toInt();
147 emit dataChanged(index, index);
148 return true;
151 return QStringListModel::setData(index, value, role);
156 // ---------------------------------------------------------------------------
160 ProxyMimeModel::ProxyMimeModel(QObject *parent)
161 : QSortFilterProxyModel(parent)
165 void ProxyMimeModel::setSourceModel(QAbstractItemModel *sourceModel)
167 QSortFilterProxyModel::setSourceModel(sourceModel);
168 sort(0);
171 void ProxyMimeModel::setFilter(const QString &filter)
173 m_filter = filter;
174 invalidateFilter();
177 bool ProxyMimeModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
179 KMimeType *leftPtr = static_cast<KMimeType*>(left.internalPointer());
180 KMimeType *rightPtr = static_cast<KMimeType*>(right.internalPointer());
182 return KStringHandler::naturalCompare(leftPtr->comment(), rightPtr->comment()) < 0;
185 bool ProxyMimeModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
187 QModelIndex sourceIndex = sourceModel()->index(source_row, 0, source_parent);
188 KMimeType *mime = static_cast<KMimeType*>(sourceIndex.internalPointer());
189 if (m_filter.isEmpty()) {
190 return true;
193 bool fastRet = mime->comment().contains(m_filter, Qt::CaseInsensitive) ||
194 ((!mime->patterns().count() || mime->comment().isEmpty()) && mime->name().contains(m_filter, Qt::CaseInsensitive));
196 if (fastRet) {
197 return true;
200 foreach (const QString &pattern, mime->patterns()) {
201 if (pattern.contains(m_filter, Qt::CaseInsensitive)) {
202 return true;
206 return false;
211 // ---------------------------------------------------------------------------
215 // Proxy model for KFilePlacesModel that filters out hidden items.
216 class PlacesFilterModel : public QSortFilterProxyModel
218 public:
219 PlacesFilterModel(QObject *parent = 0) : QSortFilterProxyModel(parent) {}
220 bool filterAcceptsRow(int row, const QModelIndex &parent) const {
221 KFilePlacesModel *model = static_cast<KFilePlacesModel*>(sourceModel());
222 const QModelIndex index = model->index(row, 0, parent);
223 return !model->isHidden(index);
229 // ---------------------------------------------------------------------------
233 FolderView::FolderView(QObject *parent, const QVariantList &args)
234 : Plasma::Containment(parent, args),
235 m_previewGenerator(0),
236 m_placesModel(0),
237 m_iconView(0),
238 m_listView(0),
239 m_label(0),
240 m_iconWidget(0),
241 m_dialog(0),
242 m_newMenu(0),
243 m_actionCollection(this)
245 setContainmentType(DesktopContainment);
246 setAspectRatioMode(Plasma::IgnoreAspectRatio);
247 setHasConfigurationInterface(true);
248 setAcceptHoverEvents(true);
249 setAcceptDrops(true);
251 m_dirModel = new KDirModel(this);
252 m_dirModel->setDropsAllowed(KDirModel::DropOnDirectory | KDirModel::DropOnLocalExecutable);
254 m_model = new ProxyModel(this);
255 m_model->setSourceModel(m_dirModel);
256 m_model->setSortLocaleAware(true);
257 m_model->setFilterCaseSensitivity(Qt::CaseInsensitive);
259 m_delegate = new KFileItemDelegate(this);
260 m_selectionModel = new QItemSelectionModel(m_model, this);
262 if (args.count() > 0) {
263 setUrl(KUrl(args.value(0).toString()));
266 resize(600, 400);
268 // As we use some part of konqueror libkonq must be added to have translations
269 KGlobal::locale()->insertCatalog("libkonq");
272 void FolderView::init()
274 Containment::init();
276 // Find out about icon and font settings changes
277 connect(KGlobalSettings::self(), SIGNAL(kdisplayFontChanged()), SLOT(fontSettingsChanged()));
278 connect(KGlobalSettings::self(), SIGNAL(iconChanged(int)), SLOT(iconSettingsChanged(int)));
280 // Find out about theme changes
281 connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), SLOT(themeChanged()));
283 // Find out about network availability changes
284 connect(Solid::Networking::notifier(), SIGNAL(statusChanged(Solid::Networking::Status)),
285 SLOT(networkStatusChanged(Solid::Networking::Status)));
287 KConfigGroup cg = config();
288 m_customLabel = cg.readEntry("customLabel", "");
289 m_customIconSize = cg.readEntry("customIconSize", 0);
290 m_showPreviews = cg.readEntry("showPreviews", true);
291 m_drawShadows = cg.readEntry("drawShadows", true);
292 m_numTextLines = cg.readEntry("numTextLines", 2);
293 m_textColor = cg.readEntry("textColor", QColor(Qt::transparent));
294 m_iconsLocked = cg.readEntry("iconsLocked", false);
295 m_alignToGrid = cg.readEntry("alignToGrid", false);
296 m_previewPlugins = cg.readEntry("previewPlugins", QStringList() << "imagethumbnail" << "jpegthumbnail");
297 m_sortDirsFirst = cg.readEntry("sortDirsFirst", true);
298 m_sortColumn = cg.readEntry("sortColumn", int(KDirModel::Name));
299 m_filterFiles = cg.readEntry("filterFiles", "*");
300 m_filterType = cg.readEntry("filter", 0);
301 m_filterFilesMimeList = cg.readEntry("mimeFilter", QStringList());
303 m_flow = isContainment() ? QListView::TopToBottom : QListView::LeftToRight;
304 m_flow = static_cast<QListView::Flow>(cg.readEntry("flow", static_cast<int>(m_flow)));
306 m_model->setFilterMode(ProxyModel::filterModeFromInt(m_filterType));
307 m_model->setMimeTypeFilterList(m_filterFilesMimeList);
308 m_model->setFilterFixedString(m_filterFiles);
309 m_model->setSortDirectoriesFirst(m_sortDirsFirst);
310 m_model->sort(m_sortColumn != -1 ? m_sortColumn : KDirModel::Name, Qt::AscendingOrder);
312 DirLister *lister = new DirLister(this);
313 lister->setDelayedMimeTypes(true);
314 lister->setAutoErrorHandlingEnabled(false, 0);
316 m_dirModel->setDirLister(lister);
318 if (!m_url.isValid()) {
320 //FIXME: 4.3 Need to update folderview's description
321 QString path = QDir::homePath();
322 if (isContainment()) {
323 QString desktopPath = KGlobalSettings::desktopPath();
324 QDir desktopFolder(desktopPath);
326 if (desktopPath != QDir::homePath() && desktopFolder.exists()) {
327 path = QString("desktop:/");
330 setUrl(cg.readEntry("url", KUrl(path)));
332 } else {
333 KConfigGroup cg = config();
334 cg.writeEntry("url", m_url);
337 // TODO: 4.3 Check if the URL is a remote URL, and if it is check the network status
338 // and display a message saying it's not available, instead of trying to open
339 // the URL and waiting for the job to time out.
340 lister->openUrl(m_url);
342 if (isContainment()) {
343 setupIconView();
346 createActions();
348 if (isContainment()) {
350 // Set a low Z value so applets don't end up below the icon view
351 m_iconView->setZValue(INT_MIN);
354 connect(QApplication::clipboard(), SIGNAL(dataChanged()), SLOT(clipboardDataChanged()));
357 FolderView::~FolderView()
359 delete m_newMenu;
362 void FolderView::saveState(KConfigGroup &config) const
364 Q_UNUSED(config)
365 saveIconPositions();
368 void FolderView::createConfigurationInterface(KConfigDialog *parent)
370 QWidget *widgetFilter = new QWidget;
371 QWidget *widgetDisplay = new QWidget;
372 QWidget *widgetLocation = new QWidget;
373 uiFilter.setupUi(widgetFilter);
374 uiDisplay.setupUi(widgetDisplay);
375 uiLocation.setupUi(widgetLocation);
377 if (!m_placesModel) {
378 m_placesModel = new KFilePlacesModel(this);
381 PlacesFilterModel *placesFilter = new PlacesFilterModel(parent);
382 placesFilter->setSourceModel(m_placesModel);
383 uiLocation.placesCombo->setModel(placesFilter);
385 QString desktopPath = KGlobalSettings::desktopPath();
386 QDir desktopFolder(desktopPath);
388 bool desktopVisible = desktopPath != QDir::homePath() && desktopFolder.exists();
389 uiLocation.showDesktopFolder->setVisible(desktopVisible);
391 if (desktopVisible && m_url == KUrl("desktop:/")) {
392 uiLocation.showDesktopFolder->setChecked(true);
393 uiLocation.placesCombo->setEnabled(false);
394 uiLocation.lineEdit->setEnabled(false);
395 } else {
396 QModelIndex index;
397 for (int i = 0; i < placesFilter->rowCount(); i++) {
398 KUrl url = m_placesModel->url(placesFilter->mapToSource(placesFilter->index(i, 0)));
399 if (url.equals(m_url, KUrl::CompareWithoutTrailingSlash)) {
400 index = placesFilter->index(i, 0);
401 break;
404 if (index.isValid()) {
405 uiLocation.placesCombo->setCurrentIndex(index.row());
406 uiLocation.showPlace->setChecked(true);
407 uiLocation.lineEdit->setEnabled(false);
408 } else {
409 uiLocation.showCustomFolder->setChecked(true);
410 uiLocation.lineEdit->setUrl(m_url);
411 uiLocation.placesCombo->setEnabled(false);
415 uiLocation.lineEdit->setMode(KFile::Directory);
416 uiFilter.filterFilesPattern->setText(m_filterFiles);
418 MimeModel *mimeModel = new MimeModel(uiFilter.filterFilesList);
419 ProxyMimeModel *pMimeModel = new ProxyMimeModel(uiFilter.filterFilesList);
420 pMimeModel->setSourceModel(mimeModel);
421 uiFilter.filterFilesList->setModel(pMimeModel);
423 // The label is not shown when the applet is acting as a containment,
424 // so don't confuse the user by making it editable.
425 if (isContainment()) {
426 uiDisplay.lblCustomLabel->hide();
427 uiDisplay.labelEdit->hide();
430 uiDisplay.labelEdit->setText(m_titleText);
432 const QList<int> iconSizes = QList<int>() << 16 << 22 << 32 << 48 << 64 << 128;
433 uiDisplay.sizeSlider->setRange(0, iconSizes.size() - 1);
434 uiDisplay.sizeSlider->setValue(iconSizes.indexOf(iconSize().width()));
436 uiDisplay.sortCombo->addItem(i18nc("Sort Icons", "Unsorted"), -1);
437 uiDisplay.sortCombo->addItem(m_actionCollection.action("sort_name")->text(), KDirModel::Name);
438 uiDisplay.sortCombo->addItem(m_actionCollection.action("sort_size")->text(), KDirModel::Size);
439 uiDisplay.sortCombo->addItem(m_actionCollection.action("sort_type")->text(), KDirModel::Type);
440 uiDisplay.sortCombo->addItem(m_actionCollection.action("sort_date")->text(), KDirModel::ModifiedTime);
442 uiDisplay.flowCombo->addItem(i18n("Top to Bottom"), QListView::TopToBottom);
443 uiDisplay.flowCombo->addItem(i18n("Left to Right"), QListView::LeftToRight);
445 uiDisplay.alignToGrid->setChecked(m_alignToGrid);
446 uiDisplay.lockInPlace->setChecked(m_iconsLocked);
447 uiDisplay.drawShadows->setChecked(m_drawShadows);
448 uiDisplay.showPreviews->setChecked(m_showPreviews);
449 uiDisplay.previewsAdvanced->setEnabled(m_showPreviews);
450 uiDisplay.numLinesEdit->setValue(m_numTextLines);
452 if (m_textColor != Qt::transparent) {
453 uiDisplay.colorButton->setColor(m_textColor);
454 } else {
455 uiDisplay.colorButton->setColor(Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
458 for (int i = 0; i < uiDisplay.sortCombo->maxCount(); i++) {
459 if (m_sortColumn == uiDisplay.sortCombo->itemData(i).toInt()) {
460 uiDisplay.sortCombo->setCurrentIndex(i);
461 break;
465 for (int i = 0; i < uiDisplay.flowCombo->maxCount(); i++) {
466 if (m_flow == uiDisplay.flowCombo->itemData(i).toInt()) {
467 uiDisplay.flowCombo->setCurrentIndex(i);
468 break;
472 // Hide the icon arrangement controls when we're not acting as a containment,
473 // since this option doesn't make much sense in the applet.
474 if (!isContainment()) {
475 uiDisplay.flowLabel->hide();
476 uiDisplay.flowCombo->hide();
479 connect(uiFilter.searchMimetype, SIGNAL(textChanged(QString)), pMimeModel, SLOT(setFilter(QString)));
481 parent->addPage(widgetLocation, i18nc("Title of the page that lets the user choose which location should the folderview show", "Location"), "folder");
482 parent->addPage(widgetDisplay, i18nc("Title of the page that lets the user choose how the folderview should be shown", "Display"), "preferences-desktop-display");
483 parent->addPage(widgetFilter, i18nc("Title of the page that lets the user choose how to filter the folderview contents", "Filter"), "view-filter");
484 parent->setButtons(KDialog::Ok | KDialog::Cancel | KDialog::Apply);
486 connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
487 connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
488 connect(uiLocation.showPlace, SIGNAL(toggled(bool)), uiLocation.placesCombo, SLOT(setEnabled(bool)));
489 connect(uiLocation.showCustomFolder, SIGNAL(toggled(bool)), uiLocation.lineEdit, SLOT(setEnabled(bool)));
490 connect(uiFilter.filterType, SIGNAL(currentIndexChanged(int)), this, SLOT(filterChanged(int)));
491 connect(uiFilter.selectAll, SIGNAL(clicked(bool)), this, SLOT(selectUnselectAll()));
492 connect(uiFilter.deselectAll, SIGNAL(clicked(bool)), this, SLOT(selectUnselectAll()));
493 connect(uiDisplay.previewsAdvanced, SIGNAL(clicked()), this, SLOT(showPreviewConfigDialog()));
494 connect(uiDisplay.showPreviews, SIGNAL(toggled(bool)), uiDisplay.previewsAdvanced, SLOT(setEnabled(bool)));
496 KConfigGroup cg = config();
497 int filter = cg.readEntry("filter", 0);
498 uiFilter.filterType->setCurrentIndex(filter);
499 filterChanged(filter);
501 QStringList selectedItems = cg.readEntry("mimeFilter", QStringList());
503 if (selectedItems.count()) {
504 for (int i = 0; i < pMimeModel->rowCount(); i++) {
505 const QModelIndex index = pMimeModel->index(i, 0);
506 const KMimeType *mime = static_cast<KMimeType*>(pMimeModel->mapToSource(index).internalPointer());
507 if (selectedItems.contains(mime->name())) {
508 selectedItems.removeAll(mime->name());
509 uiFilter.filterFilesList->model()->setData(index, Qt::Checked, Qt::CheckStateRole);
515 void FolderView::configAccepted()
517 KUrl url;
519 if (uiLocation.showDesktopFolder->isChecked()) {
520 url = KUrl("desktop:/");
521 } else if (uiLocation.showPlace->isChecked()) {
522 PlacesFilterModel *filter = static_cast<PlacesFilterModel*>(uiLocation.placesCombo->model());
523 KFilePlacesModel *model = static_cast<KFilePlacesModel*>(filter->sourceModel());
524 url = model->url(filter->mapToSource(filter->index(uiLocation.placesCombo->currentIndex(), 0)));
525 } else {
526 url = uiLocation.lineEdit->url();
529 if (url.isEmpty()) {
530 url = KUrl(QDir::homePath());
533 // Now, we have to iterate over all items (not only the filtered ones). For that reason we have
534 // to ask the source model, not the proxy model.
535 QStringList selectedItems;
536 ProxyMimeModel *proxyModel = static_cast<ProxyMimeModel*>(uiFilter.filterFilesList->model());
537 for (int i = 0; i < proxyModel->sourceModel()->rowCount(); i++) {
538 const QModelIndex index = proxyModel->sourceModel()->index(i, 0);
539 if (index.model()->data(index, Qt::CheckStateRole).toInt() == Qt::Checked) {
540 selectedItems << static_cast<KMimeType*>(index.internalPointer())->name();
544 int filterType = uiFilter.filterType->currentIndex();
545 KConfigGroup cg = config();
546 bool needReload = false;
548 if (m_drawShadows != uiDisplay.drawShadows->isChecked()) {
549 m_drawShadows = uiDisplay.drawShadows->isChecked();
550 cg.writeEntry("drawShadows", m_drawShadows);
553 if (m_showPreviews != uiDisplay.showPreviews->isChecked() ||
554 (m_previewGenerator && m_previewPlugins != m_previewGenerator->enabledPlugins()))
556 m_showPreviews = uiDisplay.showPreviews->isChecked();
557 cg.writeEntry("showPreviews", m_showPreviews);
558 cg.writeEntry("previewPlugins", m_previewPlugins);
560 m_previewGenerator->setEnabledPlugins(m_previewPlugins);
561 m_previewGenerator->setPreviewShown(m_showPreviews);
562 needReload = true;
565 const QColor color = uiDisplay.colorButton->color();
566 if ((m_textColor != Qt::transparent && color != m_textColor) ||
567 (m_textColor == Qt::transparent && color != Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor)))
569 m_textColor = color;
570 cg.writeEntry("textColor", m_textColor);
573 if (m_numTextLines != uiDisplay.numLinesEdit->value()) {
574 m_numTextLines = uiDisplay.numLinesEdit->value();
575 cg.writeEntry("numTextLines", m_numTextLines);
578 const QList<int> iconSizes = QList<int>() << 16 << 22 << 32 << 48 << 64 << 128;
579 int size = iconSizes.at(uiDisplay.sizeSlider->value());
580 if (size != iconSize().width())
582 m_customIconSize = size;
583 cg.writeEntry("customIconSize", m_customIconSize);
585 // This is to force the preview images to be regenerated with the new size
586 if (m_showPreviews) {
587 needReload = true;
591 int sortColumn = uiDisplay.sortCombo->itemData(uiDisplay.sortCombo->currentIndex()).toInt();
592 if (m_sortColumn != sortColumn) {
593 m_sortColumn = sortColumn;
594 if (m_sortColumn != -1) {
595 m_model->invalidate();
596 m_model->sort(m_sortColumn, Qt::AscendingOrder);
598 updateSortActionsState();
599 cg.writeEntry("sortColumn", m_sortColumn);
602 int flow = uiDisplay.flowCombo->itemData(uiDisplay.flowCombo->currentIndex()).toInt();
603 if (m_flow != flow) {
604 m_flow = static_cast<QListView::Flow>(flow);
605 cg.writeEntry("flow", flow);
608 if (m_alignToGrid != uiDisplay.alignToGrid->isChecked()) {
609 m_alignToGrid = uiDisplay.alignToGrid->isChecked();
610 cg.writeEntry("alignToGrid", m_alignToGrid);
611 m_actionCollection.action("auto_align")->setChecked(m_alignToGrid);
614 if (m_iconsLocked != uiDisplay.lockInPlace->isChecked()) {
615 m_iconsLocked = uiDisplay.lockInPlace->isChecked();
616 cg.writeEntry("iconsLocked", m_iconsLocked);
617 m_actionCollection.action("lock_icons")->setChecked(m_iconsLocked);
620 const QString label = uiDisplay.labelEdit->text();
621 if ((m_customLabel.isEmpty() && label != m_titleText) ||
622 (!m_customLabel.isEmpty() && label != m_customLabel))
624 m_customLabel = label;
625 setUrl(url);
626 cg.writeEntry("customLabel", m_customLabel);
629 if (m_url != url || m_filterFiles != uiFilter.filterFilesPattern->text() ||
630 m_filterFilesMimeList != selectedItems || m_filterType != filterType)
632 m_model->setFilterFixedString(uiFilter.filterFilesPattern->text());
633 m_filterFiles = uiFilter.filterFilesPattern->text();
634 m_filterFilesMimeList = selectedItems;
635 m_filterType = filterType;
636 setUrl(url);
638 cg.writeEntry("url", m_url);
639 cg.writeEntry("filterFiles", m_filterFiles);
640 cg.writeEntry("filter", m_filterType);
641 cg.writeEntry("mimeFilter", m_filterFilesMimeList);
643 m_model->setMimeTypeFilterList(m_filterFilesMimeList);
644 m_model->setFilterMode(ProxyModel::filterModeFromInt(m_filterType));
645 needReload = true;
648 if (m_iconView) {
649 updateIconViewState();
652 if (m_listView) {
653 updateListViewState();
656 if (needReload) {
657 m_dirModel->dirLister()->openUrl(m_url);
660 m_delayedSaveTimer.start(5000, this);
661 emit configNeedsSaving();
664 void FolderView::showPreviewConfigDialog()
666 QWidget *widget = new QWidget;
667 uiPreviewConfig.setupUi(widget);
669 PreviewPluginsModel *model = new PreviewPluginsModel(this);
670 model->setCheckedPlugins(m_previewPlugins);
672 uiPreviewConfig.listView->setModel(model);
674 KDialog *dialog = new KDialog;
675 dialog->setMainWidget(widget);
677 if (dialog->exec() == KDialog::Accepted) {
678 m_previewPlugins = model->checkedPlugins();
681 delete widget;
682 delete dialog;
683 delete model;
686 void FolderView::updateListViewState()
688 QPalette palette = m_listView->palette();
689 palette.setColor(QPalette::Text, m_textColor != Qt::transparent ? m_textColor :
690 Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
691 m_listView->setPalette(palette);
693 const QFont font = Plasma::Theme::defaultTheme()->font(Plasma::Theme::DesktopFont);
694 if (m_listView->font() != font) {
695 m_listView->setFont(font);
697 m_listView->setDrawShadows(m_drawShadows);
698 m_listView->setIconSize(iconSize());
699 m_listView->setWordWrap(m_numTextLines > 1);
702 void FolderView::updateIconViewState()
704 QPalette palette = m_iconView->palette();
705 palette.setColor(QPalette::Text, m_textColor != Qt::transparent ? m_textColor :
706 Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
707 m_iconView->setPalette(palette);
709 m_iconView->setDrawShadows(m_drawShadows);
710 m_iconView->setIconSize(iconSize());
711 m_iconView->setGridSize(gridSize());
712 m_iconView->setFlow(m_flow);
713 m_iconView->setWordWrap(m_numTextLines > 1);
714 m_iconView->setAlignToGrid(m_alignToGrid);
715 m_iconView->setIconsMoveable(!m_iconsLocked);
717 if (m_label) {
718 m_label->setPalette(palette);
719 m_label->setDrawShadow(m_drawShadows);
723 void FolderView::setupIconView()
725 if (m_iconView) {
726 return;
729 m_iconView = new IconView(this);
730 m_iconView->setModel(m_model);
731 m_iconView->setItemDelegate(m_delegate);
732 m_iconView->setSelectionModel(m_selectionModel);
733 m_iconView->setFont(Plasma::Theme::defaultTheme()->font(Plasma::Theme::DesktopFont));
735 if (!isContainment()) {
736 m_label = new Label(this);
737 m_label->setText(m_titleText);
740 updateIconViewState();
742 const QStringList data = config().readEntry("savedPositions", QStringList());
743 m_iconView->setIconPositionsData(data);
745 connect(m_iconView, SIGNAL(activated(QModelIndex)), SLOT(activated(QModelIndex)));
746 connect(m_iconView, SIGNAL(indexesMoved(QModelIndexList)), SLOT(indexesMoved(QModelIndexList)));
747 connect(m_iconView, SIGNAL(contextMenuRequest(QWidget*,QPoint)), SLOT(contextMenuRequest(QWidget*,QPoint)));
748 connect(m_iconView, SIGNAL(busy(bool)), SLOT(setBusy(bool)));
750 FolderViewAdapter *adapter = new FolderViewAdapter(m_iconView);
751 m_previewGenerator = new KFilePreviewGenerator(adapter, m_model);
752 m_previewGenerator->setPreviewShown(m_showPreviews);
753 m_previewGenerator->setEnabledPlugins(m_previewPlugins);
755 QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(Qt::Vertical, this);
756 layout->setContentsMargins(0, 0, 0, 0);
757 layout->setSpacing(0);
758 if (m_label) {
759 layout->addItem(m_label);
761 layout->addItem(m_iconView);
763 setLayout(layout);
766 void FolderView::fontSettingsChanged()
768 const QFont font = Plasma::Theme::defaultTheme()->font(Plasma::Theme::DesktopFont);
770 if (m_iconView && m_iconView->font() != font) {
771 m_iconView->setFont(font);
772 m_iconView->setGridSize(gridSize());
775 if (m_label && m_label->font() != font) {
776 m_label->setFont(font);
780 void FolderView::iconSettingsChanged(int group)
782 if (group == KIconLoader::Desktop && m_iconView)
784 const int size = (m_customIconSize != 0) ?
785 m_customIconSize : KIconLoader::global()->currentSize(KIconLoader::Desktop);
787 m_iconView->setIconSize(QSize(size, size));
789 else if (group == KIconLoader::Panel && m_listView)
791 const int size = (m_customIconSize != 0) ?
792 m_customIconSize : KIconLoader::global()->currentSize(KIconLoader::Panel);
794 m_listView->setIconSize(QSize(size, size));
798 void FolderView::themeChanged()
800 if (m_textColor != Qt::transparent) {
801 return;
804 if (m_iconView) {
805 QPalette palette = m_iconView->palette();
806 palette.setColor(QPalette::Text, Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
807 m_iconView->setPalette(palette);
810 if (m_listView) {
811 updateListViewState();
814 if (m_label) {
815 QPalette palette = m_label->palette();
816 palette.setColor(QPalette::Text, Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
817 m_label->setPalette(palette);
821 void FolderView::networkStatusChanged(Solid::Networking::Status status)
823 if (status == Solid::Networking::Connected && !m_url.isLocalFile() &&
824 m_url.protocol() != "desktop") {
825 refreshIcons();
829 void FolderView::clipboardDataChanged()
831 const QMimeData *mimeData = QApplication::clipboard()->mimeData();
832 if (KonqMimeData::decodeIsCutSelection(mimeData)) {
833 KUrl::List urls = KUrl::List::fromMimeData(mimeData);
835 // TODO Mark the cut icons as cut
838 // Update the paste action
839 if (QAction *action = m_actionCollection.action("paste"))
841 const QString actionText = KIO::pasteActionText();
842 if (!actionText.isEmpty()) {
843 action->setText(actionText);
844 action->setEnabled(true);
845 } else {
846 action->setText(i18n("&Paste"));
847 action->setEnabled(false);
852 void FolderView::saveIconPositions() const
854 if (!m_iconView) {
855 return;
858 const QStringList data = m_iconView->iconPositionsData();
859 if (!data.isEmpty()) {
860 config().writeEntry("savedPositions", data);
861 } else {
862 config().deleteEntry("savedPositions");
866 void FolderView::paintInterface(QPainter *painter, const QStyleOptionGraphicsItem *option, const QRect &contentRect)
868 Q_UNUSED(painter)
869 Q_UNUSED(option)
870 Q_UNUSED(contentRect)
873 void FolderView::constraintsEvent(Plasma::Constraints constraints)
875 if (constraints & Plasma::FormFactorConstraint) {
876 if (isContainment()) {
877 setBackgroundHints(Applet::NoBackground);
878 } else if (formFactor() == Plasma::Planar || formFactor() == Plasma::MediaCenter) {
879 setBackgroundHints(Applet::TranslucentBackground);
882 if (formFactor() == Plasma::Planar || formFactor() == Plasma::MediaCenter) {
883 // Clean up the icon widget
884 if (m_iconWidget) {
885 disconnect(m_dirModel->dirLister(), SIGNAL(newItems(KFileItemList)), this, SLOT(updateIconWidget()));
886 disconnect(m_dirModel->dirLister(), SIGNAL(itemsDeleted(KFileItemList)), this, SLOT(updateIconWidget()));
887 disconnect(m_dirModel->dirLister(), SIGNAL(clear()), this, SLOT(updateIconWidget()));
889 delete m_iconWidget;
890 delete m_dialog;
891 m_iconWidget = 0;
892 m_dialog = 0;
893 m_listView = 0;
895 if (!isContainment()) {
896 // Give the applet a sane size
897 setupIconView();
899 setAspectRatioMode(Plasma::IgnoreAspectRatio);
900 } else {
901 // Clean up the icon view
902 delete m_label;
903 delete m_iconView;
904 m_label = 0;
905 m_iconView = 0;
907 // Set up the icon widget
908 m_iconWidget = new IconWidget(this);
909 m_iconWidget->setModel(m_dirModel);
910 m_iconWidget->setIcon(m_icon.isNull() ? KIcon("user-folder") : m_icon);
911 connect(m_iconWidget, SIGNAL(clicked()), SLOT(iconWidgetClicked()));
913 updateIconWidget();
915 // We need to update the tooltip (and maybe the icon) when the contents of the folder changes
916 connect(m_dirModel->dirLister(), SIGNAL(newItems(KFileItemList)), SLOT(updateIconWidget()));
917 connect(m_dirModel->dirLister(), SIGNAL(itemsDeleted(KFileItemList)), SLOT(updateIconWidget()));
918 connect(m_dirModel->dirLister(), SIGNAL(clear()), SLOT(updateIconWidget()));
920 m_listView = new ListView;
921 m_listView->setItemDelegate(m_delegate);
922 m_listView->setModel(m_model);
923 m_listView->setSelectionModel(m_selectionModel);
925 connect(m_listView, SIGNAL(activated(QModelIndex)), SLOT(activated(QModelIndex)));
926 connect(m_listView, SIGNAL(contextMenuRequest(QWidget*,QPoint)), SLOT(contextMenuRequest(QWidget*,QPoint)));
928 FolderViewAdapter *adapter = new FolderViewAdapter(m_listView);
929 m_previewGenerator = new KFilePreviewGenerator(adapter, m_model);
930 m_previewGenerator->setPreviewShown(m_showPreviews);
931 m_previewGenerator->setEnabledPlugins(m_previewPlugins);
933 updateListViewState();
935 m_dialog = new Dialog;
936 m_dialog->setGraphicsWidget(m_listView); // Ownership is transferred to the scene in the dialog
938 QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(Qt::Vertical, this);
939 layout->setContentsMargins(0, 0, 0, 0);
940 layout->setSpacing(0);
941 layout->addItem(m_iconWidget);
943 setLayout(layout);
944 setAspectRatioMode(Plasma::ConstrainedSquare);
948 if (constraints & Plasma::ScreenConstraint) {
949 Plasma::Corona *c = corona();
950 disconnect(c, SIGNAL(availableScreenRegionChanged()), this, SLOT(updateScreenRegion()));
951 if (isContainment()) {
952 if (screen() >= 0) {
953 updateScreenRegion();
954 connect(c, SIGNAL(availableScreenRegionChanged()), this, SLOT(updateScreenRegion()));
955 } else {
956 m_iconView->setContentsMargins(0, 0, 0, 0);
962 void FolderView::updateScreenRegion()
964 Plasma::Corona *c = corona();
966 if (!c) {
967 return;
970 QRect availRect = c->availableScreenRegion(screen()).boundingRect();
971 QRect screenRect = c->screenGeometry(screen());
972 m_iconView->setContentsMargins(availRect.x() - screenRect.x(),
973 availRect.y() - screenRect.y(),
974 screenRect.right() - availRect.right(),
975 screenRect.bottom() - availRect.bottom());
978 void FolderView::mousePressEvent(QGraphicsSceneMouseEvent *event)
980 if (isContainment() && event->widget()->window()->inherits("DashboardView")) {
981 emit releaseVisualFocus();
982 return;
985 Containment::mousePressEvent(event);
988 void FolderView::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
990 const QString appletMimeType = static_cast<Plasma::Corona*>(scene())->appletMimeType();
991 event->setAccepted(isContainment() && immutability() == Plasma::Mutable &&
992 event->mimeData()->hasFormat(appletMimeType));
995 void FolderView::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
997 const QString appletMimeType = static_cast<Plasma::Corona*>(scene())->appletMimeType();
998 event->setAccepted(isContainment() && event->mimeData()->hasFormat(appletMimeType));
1001 void FolderView::dropEvent(QGraphicsSceneDragDropEvent *event)
1003 const QString appletMimeType = static_cast<Plasma::Corona*>(scene())->appletMimeType();
1004 if (isContainment() && event->mimeData()->hasFormat(appletMimeType)) {
1005 Containment::dropEvent(event);
1009 void FolderView::setUrl(const KUrl &url)
1011 m_url = url;
1013 if (!m_customLabel.isEmpty()) {
1014 m_titleText = m_customLabel;
1015 } else if (m_url == KUrl("desktop:/")) {
1016 m_titleText = i18n("Desktop Folder");
1017 } else {
1018 m_titleText = m_url.pathOrUrl();
1020 if (!m_placesModel) {
1021 m_placesModel = new KFilePlacesModel(this);
1023 const QModelIndex index = m_placesModel->closestItem(url);
1024 if (index.isValid()) {
1025 m_titleText = m_titleText.right(m_titleText.length() - m_placesModel->url(index).pathOrUrl().length());
1027 if (!m_titleText.isEmpty()) {
1028 if (m_titleText.at(0) == '/') {
1029 m_titleText.remove(0, 1);
1032 if (layoutDirection() == Qt::RightToLeft) {
1033 m_titleText.prepend(" < ");
1034 } else {
1035 m_titleText.prepend(" > ");
1039 m_titleText.prepend(m_placesModel->text(index));
1043 if (m_label) {
1044 m_label->setText(m_titleText);
1047 updateIconWidget();
1050 void FolderView::createActions()
1052 KIO::FileUndoManager *manager = KIO::FileUndoManager::self();
1054 // Remove the Shift+Delete shortcut from the cut action, since it's used for deleting files
1055 KAction *cut = KStandardAction::cut(this, SLOT(cut()), this);
1056 KShortcut cutShortCut = cut->shortcut();
1057 cutShortCut.remove(Qt::SHIFT + Qt::Key_Delete);
1058 cut->setShortcut(cutShortCut);
1060 KAction *copy = KStandardAction::copy(this, SLOT(copy()), this);
1062 KAction *undo = KStandardAction::undo(manager, SLOT(undo()), this);
1063 connect(manager, SIGNAL(undoAvailable(bool)), undo, SLOT(setEnabled(bool)));
1064 connect(manager, SIGNAL(undoTextChanged(QString)), SLOT(undoTextChanged(QString)));
1065 undo->setEnabled(manager->undoAvailable());
1067 KAction *paste = KStandardAction::paste(this, SLOT(paste()), this);
1068 KAction *pasteTo = KStandardAction::paste(this, SLOT(pasteTo()), this);
1069 pasteTo->setEnabled(false); // Only enabled during popupMenu()
1071 QString actionText = KIO::pasteActionText();
1072 if (!actionText.isEmpty()) {
1073 paste->setText(actionText);
1074 } else {
1075 paste->setEnabled(false);
1078 KAction *reload = new KAction(i18n("&Reload"), this);
1079 connect(reload, SIGNAL(triggered()), SLOT(refreshIcons()));
1081 KAction *refresh = new KAction(isContainment() ? i18n("&Refresh Desktop") : i18n("&Refresh View"), this);
1082 refresh->setShortcut(KStandardShortcut::reload());
1083 if (isContainment()) {
1084 refresh->setIcon(KIcon("user-desktop"));
1086 connect(refresh, SIGNAL(triggered()), SLOT(refreshIcons()));
1088 KAction *rename = new KAction(KIcon("edit-rename"), i18n("&Rename"), this);
1089 rename->setShortcut(Qt::Key_F2);
1090 connect(rename, SIGNAL(triggered()), SLOT(renameSelectedIcon()));
1092 KAction *trash = new KAction(KIcon("user-trash"), i18n("&Move to Trash"), this);
1093 trash->setShortcut(Qt::Key_Delete);
1094 connect(trash, SIGNAL(triggered(Qt::MouseButtons, Qt::KeyboardModifiers)),
1095 SLOT(moveToTrash(Qt::MouseButtons, Qt::KeyboardModifiers)));
1097 KAction *del = new KAction(i18n("&Delete"), this);
1098 del->setIcon(KIcon("edit-delete"));
1099 del->setShortcut(Qt::SHIFT + Qt::Key_Delete);
1100 connect(del, SIGNAL(triggered()), SLOT(deleteSelectedIcons()));
1102 m_actionCollection.addAction("cut", cut);
1103 m_actionCollection.addAction("undo", undo);
1104 m_actionCollection.addAction("copy", copy);
1105 m_actionCollection.addAction("paste", paste);
1106 m_actionCollection.addAction("pasteto", pasteTo);
1107 m_actionCollection.addAction("reload", reload);
1108 m_actionCollection.addAction("refresh", refresh);
1109 m_actionCollection.addAction("rename", rename);
1110 m_actionCollection.addAction("trash", trash);
1111 m_actionCollection.addAction("del", del);
1113 if (KAuthorized::authorize("editable_desktop_icons")) {
1114 KAction *alignToGrid = new KAction(i18n("Align to Grid"), this);
1115 alignToGrid->setCheckable(true);
1116 alignToGrid->setChecked(m_alignToGrid);
1117 connect(alignToGrid, SIGNAL(toggled(bool)), SLOT(toggleAlignToGrid(bool)));
1119 KAction *lockIcons = new KAction(i18nc("Icons on the desktop", "Lock in Place"), this);
1120 lockIcons->setCheckable(true);
1121 lockIcons->setChecked(m_iconsLocked);
1122 connect(lockIcons, SIGNAL(toggled(bool)), SLOT(toggleIconsLocked(bool)));
1124 m_sortingGroup = new QActionGroup(this);
1125 connect(m_sortingGroup, SIGNAL(triggered(QAction*)), SLOT(sortingChanged(QAction*)));
1126 QAction *sortByName = m_sortingGroup->addAction(i18nc("Sort icons", "By Name"));
1127 QAction *sortBySize = m_sortingGroup->addAction(i18nc("Sort icons", "By Size"));
1128 QAction *sortByType = m_sortingGroup->addAction(i18nc("Sort icons", "By Type"));
1129 QAction *sortByDate = m_sortingGroup->addAction(i18nc("Sort icons", "By Date"));
1131 sortByName->setCheckable(true);
1132 sortByName->setData(int(KDirModel::Name));
1134 sortBySize->setCheckable(true);
1135 sortBySize->setData(int(KDirModel::Size));
1137 sortByType->setCheckable(true);
1138 sortByType->setData(int(KDirModel::Type));
1140 sortByDate->setCheckable(true);
1141 sortByDate->setData(int(KDirModel::ModifiedTime));
1143 KAction *dirsFirst = new KAction(i18nc("Sort icons", "Folders First"), this);
1144 dirsFirst->setCheckable(true);
1145 dirsFirst->setChecked(m_sortDirsFirst);
1146 connect(dirsFirst, SIGNAL(toggled(bool)), SLOT(toggleDirectoriesFirst(bool)));
1148 QMenu *sortMenu = new QMenu(i18n("Sort Icons"));
1149 sortMenu->addAction(sortByName);
1150 sortMenu->addAction(sortBySize);
1151 sortMenu->addAction(sortByType);
1152 sortMenu->addAction(sortByDate);
1153 sortMenu->addSeparator();
1154 sortMenu->addAction(dirsFirst);
1156 QMenu *iconsMenu = new QMenu;
1157 iconsMenu->addMenu(sortMenu);
1158 iconsMenu->addSeparator();
1159 iconsMenu->addAction(alignToGrid);
1160 iconsMenu->addAction(lockIcons);
1162 QAction *iconsMenuAction = new KAction(i18n("Icons"), this);
1163 iconsMenuAction->setIcon(KIcon("preferences-desktop-icons"));
1164 iconsMenuAction->setMenu(iconsMenu);
1166 // Create the new menu
1167 m_newMenu = new KNewMenu(&m_actionCollection, view(), "new_menu");
1168 connect(m_newMenu->menu(), SIGNAL(aboutToShow()), this, SLOT(aboutToShowCreateNew()));
1170 m_actionCollection.addAction("lock_icons", lockIcons);
1171 m_actionCollection.addAction("auto_align", alignToGrid);
1172 m_actionCollection.addAction("icons_menu", iconsMenuAction);
1173 m_actionCollection.addAction("sort_name", sortByName);
1174 m_actionCollection.addAction("sort_size", sortBySize);
1175 m_actionCollection.addAction("sort_type", sortByType);
1176 m_actionCollection.addAction("sort_date", sortByDate);
1178 updateSortActionsState();
1181 // Note: We have to create our own action collection, because the one Plasma::Applet
1182 // provides can only be manipulated indirectly, and we need to be able to pass
1183 // a pointer to the collection to KNewMenu and KonqPopupMenu.
1184 // But we still have to add all the actions to the collection in Plasma::Applet
1185 // in order for the shortcuts to work.
1186 addAction("cut", cut);
1187 addAction("undo", undo);
1188 addAction("copy", copy);
1189 addAction("paste", paste);
1190 addAction("reload", reload);
1191 addAction("rename", rename);
1192 addAction("trash", trash);
1193 addAction("del", del);
1196 QList<QAction*> FolderView::contextualActions()
1198 QList<QAction*> actions;
1200 if (KAuthorized::authorize("action/kdesktop_rmb"))
1202 if (QAction *action = m_actionCollection.action("new_menu")) {
1203 actions.append(action);
1204 QAction *separator = new QAction(this);
1205 separator->setSeparator(true);
1206 actions.append(separator);
1209 actions.append(m_actionCollection.action("undo"));
1210 actions.append(m_actionCollection.action("paste"));
1212 QAction *separator = new QAction(this);
1213 separator->setSeparator(true);
1214 actions.append(separator);
1216 if (m_iconView) {
1217 if (QAction *iconsMenu = m_actionCollection.action("icons_menu")) {
1218 actions.append(iconsMenu);
1222 actions.append(m_actionCollection.action("refresh"));
1224 separator = new QAction(this);
1225 separator->setSeparator(true);
1226 actions.append(separator);
1229 return actions;
1232 void FolderView::aboutToShowCreateNew()
1234 if (m_newMenu) {
1235 m_newMenu->slotCheckUpToDate();
1236 m_newMenu->setPopupFiles(m_url);
1240 KUrl::List FolderView::selectedUrls() const
1242 KUrl::List urls;
1243 foreach (const QModelIndex &index, m_selectionModel->selectedIndexes())
1245 KFileItem item = m_model->itemForIndex(index);
1246 // Prefer the local URL if there is one, since we can't trash remote URL's
1247 const QString path = item.localPath();
1248 if (!path.isEmpty()) {
1249 urls.append(path);
1250 } else {
1251 urls.append(item.url());
1254 return urls;
1257 void FolderView::copy()
1259 QMimeData *mimeData = m_model->mimeData(m_selectionModel->selectedIndexes());
1260 QApplication::clipboard()->setMimeData(mimeData);
1263 void FolderView::cut()
1265 QMimeData *mimeData = m_model->mimeData(m_selectionModel->selectedIndexes());
1266 KonqMimeData::addIsCutSelection(mimeData, true);
1267 QApplication::clipboard()->setMimeData(mimeData);
1270 void FolderView::paste()
1272 KonqOperations::doPaste(view(), m_url);
1275 void FolderView::pasteTo()
1277 KUrl::List urls = selectedUrls();
1278 Q_ASSERT(urls.count() == 1);
1279 KonqOperations::doPaste(view(), urls.first());
1282 void FolderView::refreshIcons()
1284 m_dirModel->dirLister()->updateDirectory(m_url);
1287 void FolderView::toggleIconsLocked(bool locked)
1289 m_iconsLocked = locked;
1291 if (m_iconView) {
1292 m_iconView->setIconsMoveable(!locked);
1295 config().writeEntry("iconsLocked", locked);
1296 emit configNeedsSaving();
1299 void FolderView::toggleAlignToGrid(bool align)
1301 m_alignToGrid = align;
1303 if (m_iconView) {
1304 m_iconView->setAlignToGrid(align);
1307 config().writeEntry("alignToGrid", align);
1308 emit configNeedsSaving();
1310 m_delayedSaveTimer.start(5000, this);
1313 void FolderView::toggleDirectoriesFirst(bool enable)
1315 m_sortDirsFirst = enable;
1317 m_model->setSortDirectoriesFirst(m_sortDirsFirst);
1318 if (m_sortColumn != -1) {
1319 m_model->invalidate();
1320 m_delayedSaveTimer.start(5000, this);
1323 config().writeEntry("sortDirsFirst", m_sortDirsFirst);
1324 emit configNeedsSaving();
1327 void FolderView::sortingChanged(QAction *action)
1329 int column = action->data().toInt();
1331 if (column != m_sortColumn) {
1332 m_model->invalidate();
1333 m_model->sort(column, Qt::AscendingOrder);
1334 m_sortColumn = column;
1335 config().writeEntry("sortColumn", m_sortColumn);
1336 emit configNeedsSaving();
1337 m_delayedSaveTimer.start(5000, this);
1341 void FolderView::updateSortActionsState()
1343 foreach (QAction *action, m_sortingGroup->actions()) {
1344 action->setChecked(action->data() == int(m_sortColumn));
1349 void FolderView::filterChanged(int index)
1351 uiFilter.filterFilesPattern->setEnabled(index != 0);
1352 uiFilter.searchMimetype->setEnabled(index != 0);
1353 uiFilter.filterFilesList->setEnabled(index != 0);
1354 uiFilter.selectAll->setEnabled(index != 0);
1355 uiFilter.deselectAll->setEnabled(index != 0);
1358 void FolderView::selectUnselectAll()
1360 Qt::CheckState state = sender() == uiFilter.selectAll ? Qt::Checked : Qt::Unchecked;
1361 for (int i = 0; i < uiFilter.filterFilesList->model()->rowCount(); i++) {
1362 const QModelIndex index = uiFilter.filterFilesList->model()->index(i, 0);
1363 uiFilter.filterFilesList->model()->setData(index, state, Qt::CheckStateRole);
1367 void FolderView::moveToTrash(Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
1369 Q_UNUSED(buttons)
1370 if (m_iconView && m_iconView->renameInProgress()) {
1371 return;
1374 KonqOperations::Operation op = (modifiers & Qt::ShiftModifier) ?
1375 KonqOperations::DEL : KonqOperations::TRASH;
1377 KonqOperations::del(view(), op, selectedUrls());
1380 void FolderView::deleteSelectedIcons()
1382 if (m_iconView && m_iconView->renameInProgress()) {
1383 return;
1386 KonqOperations::del(view(), KonqOperations::DEL, selectedUrls());
1389 void FolderView::renameSelectedIcon()
1391 if (m_iconView) {
1392 m_iconView->renameSelectedIcon();
1396 void FolderView::undoTextChanged(const QString &text)
1398 if (QAction *action = m_actionCollection.action("undo")) {
1399 action->setText(text);
1403 void FolderView::activated(const QModelIndex &index)
1405 const KFileItem item = m_model->itemForIndex(index);
1406 item.run();
1408 if (m_dialog && m_dialog->isVisible()) {
1409 m_dialog->hide();
1412 emit releaseVisualFocus();
1415 void FolderView::indexesMoved(const QModelIndexList &indexes)
1417 Q_UNUSED(indexes)
1419 // If the user has rearranged the icons, the view is no longer sorted
1420 if (m_sortColumn != -1) {
1421 m_sortColumn = -1;
1422 updateSortActionsState();
1423 config().writeEntry("sortColumn", m_sortColumn);
1424 emit configNeedsSaving();
1427 m_delayedSaveTimer.start(5000, this);
1430 void FolderView::contextMenuRequest(QWidget *widget, const QPoint &screenPos)
1432 showContextMenu(widget, screenPos, m_selectionModel->selectedIndexes());
1435 void FolderView::showContextMenu(QWidget *widget, const QPoint &pos, const QModelIndexList &indexes)
1437 if (!KAuthorized::authorize("action/kdesktop_rmb") || indexes.isEmpty()) {
1438 return;
1441 KFileItemList items;
1442 bool hasRemoteFiles = false;
1443 bool isTrashLink = false;
1445 foreach (const QModelIndex &index, indexes) {
1446 KFileItem item = m_model->itemForIndex(index);
1447 hasRemoteFiles |= item.localPath().isEmpty();
1448 items.append(item);
1451 // Check if we're showing the menu for the trash link
1452 if (items.count() == 1 && items.at(0).isDesktopFile()) {
1453 KDesktopFile file(items.at(0).localPath());
1454 if (file.readType() == "Link" && file.readUrl() == "trash:/") {
1455 isTrashLink = true;
1459 QAction* pasteTo = m_actionCollection.action("pasteto");
1460 if (pasteTo) {
1461 pasteTo->setEnabled(m_actionCollection.action("paste")->isEnabled());
1462 pasteTo->setText(m_actionCollection.action("paste")->text());
1465 QList<QAction*> editActions;
1466 editActions.append(m_actionCollection.action("rename"));
1468 KConfigGroup configGroup(KGlobal::config(), "KDE");
1469 bool showDeleteCommand = configGroup.readEntry("ShowDeleteCommand", false);
1471 // Don't add the "Move to Trash" action if we're showing the menu for the trash link
1472 if (!isTrashLink) {
1473 if (!hasRemoteFiles) {
1474 editActions.append(m_actionCollection.action("trash"));
1475 } else {
1476 showDeleteCommand = true;
1479 if (showDeleteCommand) {
1480 editActions.append(m_actionCollection.action("del"));
1483 KParts::BrowserExtension::ActionGroupMap actionGroups;
1484 actionGroups.insert("editactions", editActions);
1486 KParts::BrowserExtension::PopupFlags flags = KParts::BrowserExtension::ShowProperties;
1488 // Use the Dolphin setting for showing the "Copy To" and "Move To" actions
1489 KConfig dolphin("dolphinrc");
1490 if (KConfigGroup(&dolphin, "General").readEntry("ShowCopyMoveMenu", false)) {
1491 flags |= KParts::BrowserExtension::ShowUrlOperations;
1494 // m_newMenu can be NULL here but KonqPopupMenu does handle this.
1495 KonqPopupMenu *contextMenu = new KonqPopupMenu(items, m_url, m_actionCollection, m_newMenu,
1496 KonqPopupMenu::ShowNewWindow, flags, widget,
1497 KBookmarkManager::userBookmarksManager(),
1498 actionGroups);
1500 contextMenu->exec(pos);
1501 delete contextMenu;
1503 if (pasteTo) {
1504 pasteTo->setEnabled(false);
1508 void FolderView::updateIconWidget()
1510 if (!m_iconWidget) {
1511 return;
1514 if (!m_placesModel) {
1515 m_placesModel = new KFilePlacesModel(this);
1518 const QModelIndex index = m_placesModel->closestItem(m_url);
1520 // TODO: Custom icon
1522 KFileItem item = m_dirModel->itemForIndex(QModelIndex());
1523 if (!item.isNull() && item.iconName() != "inode-directory") {
1524 m_icon = KIcon(item.iconName(), 0, item.overlays());
1525 } else if (m_url.protocol() == "desktop") {
1526 m_icon = KIcon("user-desktop");
1527 } else if (m_url.protocol() == "trash") {
1528 m_icon = m_model->rowCount() > 0 ? KIcon("user-trash-full") : KIcon("user-trash");
1529 } else if (index.isValid()) {
1530 m_icon = m_placesModel->icon(index);
1531 } else {
1532 m_icon = KIcon("user-folder");
1535 m_iconWidget->setIcon(m_icon);
1536 m_iconWidget->update();
1538 int nFolders = 0;
1539 int nFiles = 0;
1540 foreach (const KFileItem &item, m_dirModel->dirLister()->items()) {
1541 if (item.isDir()) {
1542 nFolders++;
1543 } else {
1544 nFiles++;
1548 const QString str1 = i18ncp("Inserted as %1 in the message below.", "1 folder", "%1 folders", nFolders);
1549 const QString str2 = i18ncp("Inserted as %2 in the message below.", "1 file", "%1 files", nFiles);
1551 QString subText;
1552 if (nFolders > 0) {
1553 subText = i18nc("%1 and %2 are the messages translated above.", "%1, %2.", str1, str2);
1554 } else {
1555 subText = i18np("1 file.", "%1 files.", nFiles);
1558 // Update the tooltip
1559 Plasma::ToolTipContent data;
1560 data.setMainText(m_titleText);
1561 data.setSubText(subText);
1562 data.setImage(m_icon);
1563 Plasma::ToolTipManager::self()->setContent(m_iconWidget, data);
1566 void FolderView::iconWidgetClicked()
1568 if (m_dialog->isVisible()) {
1569 m_dialog->hide();
1570 } else {
1571 m_dialog->show(this);
1575 QSize FolderView::iconSize() const
1577 const int defaultSize = KIconLoader::global()->currentSize(m_listView ? KIconLoader::Panel : KIconLoader::Desktop);
1578 const int size = (m_customIconSize != 0) ? m_customIconSize : defaultSize;
1579 return QSize(size, size);
1582 QSize FolderView::gridSize() const
1584 const QFontMetrics fm(Plasma::Theme::defaultTheme()->font(Plasma::Theme::DesktopFont));
1585 const int textHeight = fm.lineSpacing() * m_numTextLines;
1586 QSize size = iconSize();
1587 size.rheight() = size.height() + textHeight + 16;
1588 size.rwidth() = qMax(size.width() * 2, fm.averageCharWidth() * 10);
1589 return size;
1592 void FolderView::timerEvent(QTimerEvent *event)
1594 if (event->timerId() == m_delayedSaveTimer.timerId()) {
1595 m_delayedSaveTimer.stop();
1596 saveIconPositions();
1597 emit configNeedsSaving();
1600 Containment::timerEvent(event);
1603 #include "folderview.moc"