1
/***************************************************************************
2
* Copyright (C) 2007-2009 by Peter Penz <peter.penz19@gmail.com> *
4
* This program is free software; you can redistribute it and/or modify *
5
* it under the terms of the GNU General Public License as published by *
6
* the Free Software Foundation; either version 2 of the License, or *
7
* (at your option) any later version. *
9
* This program is distributed in the hope that it will be useful, *
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12
* GNU General Public License for more details. *
14
* You should have received a copy of the GNU General Public License *
15
* along with this program; if not, write to the *
16
* Free Software Foundation, Inc., *
17
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
18
***************************************************************************/
20
#include "dolphincolumnview.h"
22
#include "dolphinmodel.h"
23
#include "dolphincolumnviewcontainer.h"
24
#include "dolphinviewcontroller.h"
25
#include "dolphindirlister.h"
26
#include "dolphinfileitemdelegate.h"
27
#include "dolphinsortfilterproxymodel.h"
28
#include "settings/dolphinsettings.h"
29
#include "dolphinviewautoscroller.h"
30
#include "dolphin_columnmodesettings.h"
31
#include "dolphin_generalsettings.h"
32
#include "draganddrophelper.h"
33
#include "folderexpander.h"
34
#include "tooltips/tooltipmanager.h"
35
#include "viewextensionsfactory.h"
36
#include "viewmodecontroller.h"
37
#include "zoomlevelinfo.h"
39
#include <KColorScheme>
42
#include <KIO/PreviewJob>
44
#include <KIconEffect>
47
#include <konqmimedata.h>
49
#include <QApplication>
51
#include <QHeaderView>
57
DolphinColumnView::DolphinColumnView(QWidget* parent,
58
DolphinColumnViewContainer* container,
60
DolphinTreeView(parent),
62
m_container(container),
63
m_extensionsFactory(0),
74
setMouseTracking(true);
76
setUniformRowHeights(true);
77
setSelectionBehavior(SelectItems);
78
setSelectionMode(QAbstractItemView::ExtendedSelection);
79
setDragDropMode(QAbstractItemView::DragDrop);
80
setDropIndicatorShown(false);
81
setRootIsDecorated(false);
82
setItemsExpandable(false);
83
setEditTriggers(QAbstractItemView::NoEditTriggers);
84
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
85
setVerticalScrollMode(QTreeView::ScrollPerPixel);
87
m_resizeWidget = new QLabel(this);
88
m_resizeWidget->setPixmap(KIcon("transform-move").pixmap(KIconLoader::SizeSmall));
89
m_resizeWidget->setToolTip(i18nc("@info:tooltip", "Resize column"));
90
setCornerWidget(m_resizeWidget);
91
m_resizeWidget->installEventFilter(this);
93
const ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
96
if (settings->useSystemFont()) {
97
m_font = KGlobalSettings::generalFont();
99
m_font = QFont(settings->fontFamily(),
100
qRound(settings->fontSize()),
101
settings->fontWeight(),
102
settings->italicFont());
103
m_font.setPointSizeF(settings->fontSize());
106
setMinimumWidth(settings->fontSize() * 10);
107
setMaximumWidth(settings->columnWidth());
109
connect(this, SIGNAL(viewportEntered()),
110
m_container->m_dolphinViewController, SLOT(emitViewportEntered()));
111
connect(this, SIGNAL(entered(const QModelIndex&)),
112
this, SLOT(slotEntered(const QModelIndex&)));
114
const DolphinView* dolphinView = m_container->m_dolphinViewController->view();
115
connect(dolphinView, SIGNAL(showPreviewChanged()),
116
this, SLOT(slotShowPreviewChanged()));
118
m_dirLister = new DolphinDirLister();
119
m_dirLister->setAutoUpdate(true);
120
m_dirLister->setMainWindow(window());
121
m_dirLister->setDelayedMimeTypes(true);
122
const bool showHiddenFiles = m_container->m_dolphinViewController->view()->showHiddenFiles();
123
m_dirLister->setShowingDotFiles(showHiddenFiles);
124
connect(m_dirLister, SIGNAL(completed()), this, SLOT(slotDirListerCompleted()));
126
m_dolphinModel = new DolphinModel(this);
127
m_dolphinModel->setDirLister(m_dirLister);
128
m_dolphinModel->setDropsAllowed(DolphinModel::DropOnDirectory);
130
m_proxyModel = new DolphinSortFilterProxyModel(this);
131
m_proxyModel->setSourceModel(m_dolphinModel);
132
m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
134
m_proxyModel->setSorting(dolphinView->sorting());
135
m_proxyModel->setSortOrder(dolphinView->sortOrder());
136
m_proxyModel->setSortFoldersFirst(dolphinView->sortFoldersFirst());
138
setModel(m_proxyModel);
140
connect(KGlobalSettings::self(), SIGNAL(kdisplayFontChanged()),
141
this, SLOT(updateFont()));
143
const ViewModeController* viewModeController = m_container->m_viewModeController;
144
connect(viewModeController, SIGNAL(zoomLevelChanged(int)),
145
this, SLOT(setZoomLevel(int)));
146
const QString nameFilter = viewModeController->nameFilter();
147
if (!nameFilter.isEmpty()) {
148
m_proxyModel->setFilterFixedString(nameFilter);
151
updateDecorationSize(dolphinView->showPreview());
154
DolphinViewController* dolphinViewController = m_container->m_dolphinViewController;
155
m_extensionsFactory = new ViewExtensionsFactory(this, dolphinViewController, viewModeController);
156
m_extensionsFactory->fileItemDelegate()->setMinimizedNameColumn(true);
158
m_dirLister->openUrl(url, KDirLister::NoFlags);
161
DolphinColumnView::~DolphinColumnView()
165
delete m_dolphinModel;
167
m_dirLister = 0; // deleted by m_dolphinModel
171
void DolphinColumnView::setActive(bool active)
173
if (m_active != active) {
184
bool DolphinColumnView::isActive() const
189
void DolphinColumnView::setChildUrl(const KUrl& url)
194
KUrl DolphinColumnView::childUrl() const
199
void DolphinColumnView::setUrl(const KUrl& url)
203
m_dirLister->openUrl(url, KDirLister::NoFlags);
207
KUrl DolphinColumnView::url() const
212
void DolphinColumnView::updateBackground()
214
// TODO: The alpha-value 150 is copied from DolphinView::setActive(). When
215
// cleaning up the cut-indication of DolphinColumnView with the code from
216
// DolphinView a common helper-class should be available which can be shared
217
// by all view implementations -> no hardcoded value anymore
218
const QPalette::ColorRole role = viewport()->backgroundRole();
219
QColor color = viewport()->palette().color(role);
220
color.setAlpha((m_active && m_container->m_active) ? 255 : 150);
222
QPalette palette = viewport()->palette();
223
palette.setColor(role, color);
224
viewport()->setPalette(palette);
229
KFileItem DolphinColumnView::itemAt(const QPoint& pos) const
232
const QModelIndex index = indexAt(pos);
233
if (index.isValid() && (index.column() == DolphinModel::Name)) {
234
const QModelIndex dolphinModelIndex = m_proxyModel->mapToSource(index);
235
item = m_dolphinModel->itemForIndex(dolphinModelIndex);
240
void DolphinColumnView::setSelectionModel(QItemSelectionModel* model)
242
// If a change of the selection is done although the view is not active
243
// (e. g. by the selection markers), the column must be activated. This
244
// is done by listening to the current selectionChanged() signal.
245
if (selectionModel()) {
246
disconnect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
247
this, SLOT(requestActivation()));
250
DolphinTreeView::setSelectionModel(model);
252
connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
253
this, SLOT(requestActivation()));
256
QStyleOptionViewItem DolphinColumnView::viewOptions() const
258
QStyleOptionViewItem viewOptions = DolphinTreeView::viewOptions();
259
viewOptions.font = m_font;
260
viewOptions.fontMetrics = QFontMetrics(m_font);
261
viewOptions.decorationSize = m_decorationSize;
262
viewOptions.showDecorationSelected = true;
266
bool DolphinColumnView::event(QEvent* event)
268
if (event->type() == QEvent::Polish) {
269
// Hide all columns except of the 'Name' column
270
for (int i = DolphinModel::Name + 1; i < DolphinModel::ExtraColumnCount; ++i) {
276
return DolphinTreeView::event(event);
279
void DolphinColumnView::startDrag(Qt::DropActions supportedActions)
281
DragAndDropHelper::instance().startDrag(this, supportedActions, m_container->m_dolphinViewController);
282
DolphinTreeView::startDrag(supportedActions);
285
void DolphinColumnView::dragEnterEvent(QDragEnterEvent* event)
287
event->acceptProposedAction();
289
DolphinTreeView::dragEnterEvent(event);
292
void DolphinColumnView::dragMoveEvent(QDragMoveEvent* event)
294
DolphinTreeView::dragMoveEvent(event);
295
event->acceptProposedAction();
298
void DolphinColumnView::dropEvent(QDropEvent* event)
300
const QModelIndex index = indexAt(event->pos());
301
m_container->m_dolphinViewController->setItemView(this);
302
const QModelIndex dolphinModelIndex = m_proxyModel->mapToSource(index);
303
const KFileItem item = m_dolphinModel->itemForIndex(dolphinModelIndex);
304
m_container->m_dolphinViewController->indicateDroppedUrls(item, event);
305
DolphinTreeView::dropEvent(event);
308
void DolphinColumnView::paintEvent(QPaintEvent* event)
310
if (!m_childUrl.isEmpty()) {
311
// Indicate the shown URL of the next column by highlighting the shown folder item
312
const QModelIndex dirIndex = m_dolphinModel->indexForUrl(m_childUrl);
313
const QModelIndex proxyIndex = m_proxyModel->mapFromSource(dirIndex);
314
if (proxyIndex.isValid() && !selectionModel()->isSelected(proxyIndex)) {
315
QPainter painter(viewport());
317
QStyleOptionViewItemV4 option;
318
option.initFrom(this);
319
option.rect = visualRect(proxyIndex);
320
option.state = QStyle::State_Enabled | QStyle::State_HasFocus;
321
option.viewItemPosition = QStyleOptionViewItemV4::OnlyOne;
322
style()->drawPrimitive(QStyle::PE_FrameFocusRect, &option, &painter, this);
326
DolphinTreeView::paintEvent(event);
329
void DolphinColumnView::mousePressEvent(QMouseEvent* event)
332
if (!indexAt(event->pos()).isValid() && (QApplication::mouseButtons() & Qt::MidButton)) {
333
m_container->m_dolphinViewController->replaceUrlByClipboard();
336
DolphinTreeView::mousePressEvent(event);
339
void DolphinColumnView::keyPressEvent(QKeyEvent* event)
341
const bool hadSelection = selectionModel()->hasSelection();
342
DolphinTreeView::keyPressEvent(event);
344
DolphinViewController* controller = m_container->m_dolphinViewController;
345
controller->handleKeyPressEvent(event);
346
switch (event->key()) {
347
case Qt::Key_Right: {
348
// Special key handling for the column: A Key_Right should
349
// open a new column for the currently selected folder.
350
QModelIndex dolphinModelIndex = m_proxyModel->mapToSource(currentIndex());
352
// If there is no selection we automatically move to the child url
353
// instead of the first directory.
355
if (!hadSelection && !childUrl().isEmpty()) {
356
dolphinModelIndex = m_dolphinModel->indexForUrl(childUrl());
359
const KFileItem item = m_dolphinModel->itemForIndex(dolphinModelIndex);
360
if (!item.isNull() && item.isDir()) {
361
controller->emitItemTriggered(item);
367
selectionModel()->setCurrentIndex(selectionModel()->currentIndex(),
368
QItemSelectionModel::Current |
369
QItemSelectionModel::Clear);
377
void DolphinColumnView::contextMenuEvent(QContextMenuEvent* event)
380
DolphinTreeView::contextMenuEvent(event);
381
m_container->m_dolphinViewController->triggerContextMenuRequest(event->pos());
384
void DolphinColumnView::wheelEvent(QWheelEvent* event)
386
const int step = m_decorationSize.height();
387
verticalScrollBar()->setSingleStep(step);
388
DolphinTreeView::wheelEvent(event);
391
void DolphinColumnView::leaveEvent(QEvent* event)
393
DolphinTreeView::leaveEvent(event);
394
// if the mouse is above an item and moved very fast outside the widget,
395
// no viewportEntered() signal might be emitted although the mouse has been moved
396
// above the viewport
397
m_container->m_dolphinViewController->emitViewportEntered();
400
void DolphinColumnView::currentChanged(const QModelIndex& current, const QModelIndex& previous)
402
DolphinTreeView::currentChanged(current, previous);
403
m_extensionsFactory->handleCurrentIndexChange(current, previous);
406
QRect DolphinColumnView::visualRect(const QModelIndex& index) const
408
QRect rect = DolphinTreeView::visualRect(index);
410
const QModelIndex dolphinModelIndex = m_proxyModel->mapToSource(index);
411
const KFileItem item = m_dolphinModel->itemForIndex(dolphinModelIndex);
412
if (!item.isNull()) {
413
const int width = DolphinFileItemDelegate::nameColumnWidth(item.text(), viewOptions());
414
rect.setWidth(width);
420
bool DolphinColumnView::acceptsDrop(const QModelIndex& index) const
422
if (index.isValid() && (index.column() == DolphinModel::Name)) {
423
// Accept drops above directories
424
const QModelIndex dolphinModelIndex = m_proxyModel->mapToSource(index);
425
const KFileItem item = m_dolphinModel->itemForIndex(dolphinModelIndex);
426
return !item.isNull() && item.isDir();
432
bool DolphinColumnView::eventFilter(QObject* watched, QEvent* event)
434
if (watched == m_resizeWidget) {
435
switch (event->type()) {
436
case QEvent::MouseButtonPress: {
437
// Initiate the resizing of the column
438
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
439
m_resizeXOrigin = mouseEvent->globalX();
440
m_resizeWidget->setMouseTracking(true);
445
case QEvent::MouseButtonDblClick: {
446
// Reset the column width to the default value
447
const ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
448
setMaximumWidth(settings->columnWidth());
449
m_container->layoutColumns();
450
m_resizeWidget->setMouseTracking(false);
451
m_resizeXOrigin = -1;
456
case QEvent::MouseMove: {
457
// Resize the column and trigger a relayout of the container
458
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
459
int requestedWidth = maximumWidth() - m_resizeXOrigin + mouseEvent->globalX();;
460
if (requestedWidth < minimumWidth()) {
461
requestedWidth = minimumWidth();
463
setMaximumWidth(requestedWidth);
465
m_container->layoutColumns();
467
m_resizeXOrigin = mouseEvent->globalX();
473
case QEvent::MouseButtonRelease: {
474
// The resizing has been finished
475
m_resizeWidget->setMouseTracking(false);
476
m_resizeXOrigin = -1;
485
return DolphinTreeView::eventFilter(watched, event);
487
void DolphinColumnView::setZoomLevel(int level)
489
const int size = ZoomLevelInfo::iconSizeForZoomLevel(level);
490
ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
492
const bool showPreview = m_container->m_dolphinViewController->view()->showPreview();
494
settings->setPreviewSize(size);
496
settings->setIconSize(size);
499
updateDecorationSize(showPreview);
502
void DolphinColumnView::slotEntered(const QModelIndex& index)
504
m_container->m_dolphinViewController->setItemView(this);
505
m_container->m_dolphinViewController->emitItemEntered(index);
508
void DolphinColumnView::requestActivation()
510
m_container->m_dolphinViewController->requestActivation();
512
m_container->requestActivation(this);
513
selectionModel()->clear();
517
void DolphinColumnView::updateFont()
519
const ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
522
if (settings->useSystemFont()) {
523
m_font = KGlobalSettings::generalFont();
527
void DolphinColumnView::slotShowPreviewChanged()
529
const DolphinView* view = m_container->m_dolphinViewController->view();
530
updateDecorationSize(view->showPreview());
533
void DolphinColumnView::slotDirListerCompleted()
535
if (!m_childUrl.isEmpty()) {
539
// Try to optimize the width of the column, so that no name gets clipped
540
const int requiredWidth = sizeHintForColumn(DolphinModel::Name);
542
const ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
543
if (requiredWidth > settings->columnWidth()) {
544
int frameAroundContents = 0;
545
if (style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents)) {
546
// TODO: Using 2 PM_DefaultFrameWidths are not sufficient. Check Qt-code
547
// for other pixelmetrics that should be added...
548
frameAroundContents = style()->pixelMetric(QStyle::PM_DefaultFrameWidth) * 4;
551
const int scrollBarWidth = style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, verticalScrollBar());
553
setMaximumWidth(requiredWidth + frameAroundContents + scrollBarWidth);
554
m_container->layoutColumns();
556
m_container->assureVisibleActiveColumn();
561
void DolphinColumnView::activate()
563
setFocus(Qt::OtherFocusReason);
565
connect(this, SIGNAL(clicked(const QModelIndex&)),
566
m_container->m_dolphinViewController, SLOT(requestTab(const QModelIndex&)));
567
if (KGlobalSettings::singleClick()) {
568
connect(this, SIGNAL(clicked(const QModelIndex&)),
569
m_container->m_dolphinViewController, SLOT(triggerItem(const QModelIndex&)));
571
connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
572
m_container->m_dolphinViewController, SLOT(triggerItem(const QModelIndex&)));
575
if (selectionModel() && selectionModel()->currentIndex().isValid()) {
576
selectionModel()->setCurrentIndex(selectionModel()->currentIndex(), QItemSelectionModel::SelectCurrent);
582
void DolphinColumnView::deactivate()
586
disconnect(this, SIGNAL(clicked(const QModelIndex&)),
587
m_container->m_dolphinViewController, SLOT(requestTab(const QModelIndex&)));
588
if (KGlobalSettings::singleClick()) {
589
disconnect(this, SIGNAL(clicked(const QModelIndex&)),
590
m_container->m_dolphinViewController, SLOT(triggerItem(const QModelIndex&)));
592
disconnect(this, SIGNAL(doubleClicked(const QModelIndex&)),
593
m_container->m_dolphinViewController, SLOT(triggerItem(const QModelIndex&)));
596
// It is important to disconnect the connection to requestActivation() temporary, otherwise the internal
597
// clearing of the selection would result in activating the column again.
598
disconnect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
599
this, SLOT(requestActivation()));
600
const QModelIndex current = selectionModel()->currentIndex();
601
selectionModel()->clear();
602
selectionModel()->setCurrentIndex(current, QItemSelectionModel::NoUpdate);
603
connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
604
this, SLOT(requestActivation()));
609
void DolphinColumnView::updateDecorationSize(bool showPreview)
611
ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
612
const int iconSize = showPreview ? settings->previewSize() : settings->iconSize();
613
const QSize size(iconSize, iconSize);
616
m_decorationSize = size;
621
#include "dolphincolumnview.moc"