]> cloud.milkyroute.net Git - dolphin.git/blob - src/dolphincolumnview.cpp
assure that the folder which is shown in the next column is always selected
[dolphin.git] / src / dolphincolumnview.cpp
1 /***************************************************************************
2 * Copyright (C) 2007 by Peter Penz <peter.penz@gmx.at> *
3 * *
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. *
8 * *
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. *
13 * *
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 ***************************************************************************/
19
20 #include "dolphincolumnview.h"
21
22 #include "dolphincontroller.h"
23 #include "dolphinsettings.h"
24
25 #include "dolphin_columnmodesettings.h"
26
27 #include <kcolorutils.h>
28 #include <kcolorscheme.h>
29 #include <kdirmodel.h>
30
31 #include <QAbstractProxyModel>
32 #include <QPoint>
33
34 /**
35 * Represents one column inside the DolphinColumnView and has been
36 * extended to respect view options and hovering information.
37 */
38 class ColumnWidget : public QListView
39 {
40 public:
41 ColumnWidget(QWidget* parent,
42 DolphinColumnView* columnView,
43 const KUrl& url);
44 virtual ~ColumnWidget();
45
46 /** Sets the size of the icons. */
47 void setDecorationSize(const QSize& size);
48
49 /**
50 * An active column is defined as column, which shows the same URL
51 * as indicated by the URL navigator. The active column is usually
52 * drawn in a lighter color. All operations are applied to this column.
53 */
54 void setActive(bool active);
55 inline bool isActive() const;
56
57 inline const KUrl& url() const;
58
59 protected:
60 virtual QStyleOptionViewItem viewOptions() const;
61 virtual void dragEnterEvent(QDragEnterEvent* event);
62 virtual void dragLeaveEvent(QDragLeaveEvent* event);
63 virtual void dragMoveEvent(QDragMoveEvent* event);
64 virtual void dropEvent(QDropEvent* event);
65 virtual void mousePressEvent(QMouseEvent* event);
66 virtual void paintEvent(QPaintEvent* event);
67 virtual void contextMenuEvent(QContextMenuEvent* event);
68
69 private:
70 /** Used by ColumnWidget::setActive(). */
71 void activate();
72
73 /** Used by ColumnWidget::setActive(). */
74 void deactivate();
75
76 private:
77 bool m_active;
78 DolphinColumnView* m_view;
79 KUrl m_url;
80 QStyleOptionViewItem m_viewOptions;
81
82 bool m_dragging; // TODO: remove this property when the issue #160611 is solved in Qt 4.4
83 QRect m_dropRect; // TODO: remove this property when the issue #160611 is solved in Qt 4.4
84 };
85
86 ColumnWidget::ColumnWidget(QWidget* parent,
87 DolphinColumnView* columnView,
88 const KUrl& url) :
89 QListView(parent),
90 m_active(true),
91 m_view(columnView),
92 m_url(url),
93 m_dragging(false),
94 m_dropRect()
95 {
96 setAcceptDrops(true);
97 setDragDropMode(QAbstractItemView::DragDrop);
98 setDropIndicatorShown(false);
99
100 setMouseTracking(true);
101 viewport()->setAttribute(Qt::WA_Hover);
102
103 // apply the column mode settings to the widget
104 const ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
105 Q_ASSERT(settings != 0);
106
107 m_viewOptions = QListView::viewOptions();
108
109 QFont font(settings->fontFamily(), settings->fontSize());
110 font.setItalic(settings->italicFont());
111 font.setBold(settings->boldFont());
112 m_viewOptions.font = font;
113
114 const int iconSize = settings->iconSize();
115 m_viewOptions.decorationSize = QSize(iconSize, iconSize);
116
117 activate();
118 }
119
120 ColumnWidget::~ColumnWidget()
121 {
122 }
123
124 void ColumnWidget::setDecorationSize(const QSize& size)
125 {
126 m_viewOptions.decorationSize = size;
127 doItemsLayout();
128 }
129
130 void ColumnWidget::setActive(bool active)
131 {
132 if (m_active == active) {
133 return;
134 }
135
136 m_active = active;
137
138 if (active) {
139 activate();
140 } else {
141 deactivate();
142 }
143 }
144
145 inline bool ColumnWidget::isActive() const
146 {
147 return m_active;
148 }
149
150 const KUrl& ColumnWidget::url() const
151 {
152 return m_url;
153 }
154
155 QStyleOptionViewItem ColumnWidget::viewOptions() const
156 {
157 return m_viewOptions;
158 }
159
160 void ColumnWidget::dragEnterEvent(QDragEnterEvent* event)
161 {
162 if (event->mimeData()->hasUrls()) {
163 event->acceptProposedAction();
164 }
165
166 m_dragging = true;
167 }
168
169 void ColumnWidget::dragLeaveEvent(QDragLeaveEvent* event)
170 {
171 QListView::dragLeaveEvent(event);
172
173 // TODO: remove this code when the issue #160611 is solved in Qt 4.4
174 m_dragging = false;
175 setDirtyRegion(m_dropRect);
176 }
177
178 void ColumnWidget::dragMoveEvent(QDragMoveEvent* event)
179 {
180 QListView::dragMoveEvent(event);
181
182 // TODO: remove this code when the issue #160611 is solved in Qt 4.4
183 const QModelIndex index = indexAt(event->pos());
184 setDirtyRegion(m_dropRect);
185 m_dropRect = visualRect(index);
186 setDirtyRegion(m_dropRect);
187 }
188
189 void ColumnWidget::dropEvent(QDropEvent* event)
190 {
191 const KUrl::List urls = KUrl::List::fromMimeData(event->mimeData());
192 if (!urls.isEmpty()) {
193 event->acceptProposedAction();
194 m_view->m_controller->indicateDroppedUrls(urls,
195 indexAt(event->pos()),
196 event->source());
197 }
198 QListView::dropEvent(event);
199 m_dragging = false;
200 }
201
202 void ColumnWidget::mousePressEvent(QMouseEvent* event)
203 {
204 QListView::mousePressEvent(event);
205 const QModelIndex index = indexAt(event->pos());
206
207 bool requestActivation = false;
208 if (index.isValid()) {
209 // A click on an item has been done. Only request an activation
210 // if the item is not a directory.
211 const QAbstractProxyModel* proxyModel = static_cast<const QAbstractProxyModel*>(m_view->model());
212 const KDirModel* dirModel = static_cast<const KDirModel*>(proxyModel->sourceModel());
213 const QModelIndex dirIndex = proxyModel->mapToSource(index);
214 KFileItem* item = dirModel->itemForIndex(dirIndex);
215 requestActivation = (item != 0) && !item->isDir();
216 } else {
217 // a click on the viewport has been done
218 requestActivation = true;
219 }
220
221 if (requestActivation) {
222 m_view->requestActivation(this);
223 } else {
224 m_view->updateSelections();
225 }
226 }
227
228 void ColumnWidget::paintEvent(QPaintEvent* event)
229 {
230 QListView::paintEvent(event);
231
232 // TODO: remove this code when the issue #160611 is solved in Qt 4.4
233 if (m_dragging) {
234 const QBrush& brush = m_viewOptions.palette.brush(QPalette::Normal, QPalette::Highlight);
235 DolphinController::drawHoverIndication(viewport(), m_dropRect, brush);
236 }
237 }
238
239 void ColumnWidget::contextMenuEvent(QContextMenuEvent* event)
240 {
241 m_view->requestActivation(this);
242
243 QListView::contextMenuEvent(event);
244
245 const QModelIndex index = indexAt(event->pos());
246 if (index.isValid() || m_active) {
247 // Only open a context menu above an item or if the mouse is above
248 // the active column.
249 const QPoint pos = m_view->viewport()->mapFromGlobal(event->globalPos());
250 m_view->m_controller->triggerContextMenuRequest(pos);
251 }
252 }
253
254 void ColumnWidget::activate()
255 {
256 const QColor bgColor = KColorScheme(KColorScheme::View).background();
257 QPalette palette = viewport()->palette();
258 palette.setColor(viewport()->backgroundRole(), bgColor);
259 viewport()->setPalette(palette);
260
261 setSelectionMode(MultiSelection);
262 update();
263 }
264
265 void ColumnWidget::deactivate()
266 {
267 QColor bgColor = KColorScheme(KColorScheme::View).background();
268 const QColor fgColor = KColorScheme(KColorScheme::View).foreground();
269 bgColor = KColorUtils::mix(bgColor, fgColor, 0.04);
270
271 QPalette palette = viewport()->palette();
272 palette.setColor(viewport()->backgroundRole(), bgColor);
273 viewport()->setPalette(palette);
274
275 setSelectionMode(SingleSelection);
276 update();
277 }
278
279 // ---
280
281 DolphinColumnView::DolphinColumnView(QWidget* parent, DolphinController* controller) :
282 QColumnView(parent),
283 m_controller(controller)
284 {
285 Q_ASSERT(controller != 0);
286
287 setAcceptDrops(true);
288 setDragDropMode(QAbstractItemView::DragDrop);
289 setDropIndicatorShown(false);
290 setSelectionMode(MultiSelection);
291
292 if (KGlobalSettings::singleClick()) {
293 connect(this, SIGNAL(clicked(const QModelIndex&)),
294 this, SLOT(triggerItem(const QModelIndex&)));
295 } else {
296 connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
297 this, SLOT(triggerItem(const QModelIndex&)));
298 }
299 connect(this, SIGNAL(entered(const QModelIndex&)),
300 controller, SLOT(emitItemEntered(const QModelIndex&)));
301 connect(this, SIGNAL(viewportEntered()),
302 controller, SLOT(emitViewportEntered()));
303 connect(controller, SIGNAL(zoomIn()),
304 this, SLOT(zoomIn()));
305 connect(controller, SIGNAL(zoomOut()),
306 this, SLOT(zoomOut()));
307 connect(controller, SIGNAL(urlChanged(const KUrl&)),
308 this, SLOT(updateColumnsState(const KUrl&)));
309
310 updateDecorationSize();
311 }
312
313 DolphinColumnView::~DolphinColumnView()
314 {
315 }
316
317 QAbstractItemView* DolphinColumnView::createColumn(const QModelIndex& index)
318 {
319 // let the column widget be aware about its URL...
320 KUrl columnUrl;
321 if (viewport()->children().count() == 0) {
322 // For the first column widget the directory lister has not been started
323 // yet, hence use the URL from the controller instead.
324 columnUrl = m_controller->url();
325 } else {
326 const QAbstractProxyModel* proxyModel = static_cast<const QAbstractProxyModel*>(model());
327 const KDirModel* dirModel = static_cast<const KDirModel*>(proxyModel->sourceModel());
328
329 const QModelIndex dirModelIndex = proxyModel->mapToSource(index);
330 KFileItem* fileItem = dirModel->itemForIndex(dirModelIndex);
331 if (fileItem != 0) {
332 columnUrl = fileItem->url();
333 }
334 }
335
336 ColumnWidget* view = new ColumnWidget(viewport(), this, columnUrl);
337
338 // The following code has been copied 1:1 from QColumnView::createColumn().
339 // Copyright (C) 1992-2007 Trolltech ASA. In Qt 4.4 the new method
340 // QColumnView::initializeColumn() will be available for this.
341
342 view->setFrameShape(QFrame::NoFrame);
343 view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
344 view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
345 view->setMinimumWidth(100);
346 view->setAttribute(Qt::WA_MacShowFocusRect, false);
347
348 // copy the 'view' behavior
349 view->setDragDropMode(dragDropMode());
350 view->setDragDropOverwriteMode(dragDropOverwriteMode());
351 view->setDropIndicatorShown(showDropIndicator());
352 view->setAlternatingRowColors(alternatingRowColors());
353 view->setAutoScroll(hasAutoScroll());
354 view->setEditTriggers(editTriggers());
355 view->setHorizontalScrollMode(horizontalScrollMode());
356 view->setIconSize(iconSize());
357 view->setSelectionBehavior(selectionBehavior());
358 view->setSelectionMode(selectionMode());
359 view->setTabKeyNavigation(tabKeyNavigation());
360 view->setTextElideMode(textElideMode());
361 view->setVerticalScrollMode(verticalScrollMode());
362
363 view->setModel(model());
364
365 // set the delegate to be the columnview delegate
366 QAbstractItemDelegate* delegate = view->itemDelegate();
367 view->setItemDelegate(itemDelegate());
368 delete delegate;
369
370 view->setRootIndex(index);
371
372 if (model()->canFetchMore(index)) {
373 model()->fetchMore(index);
374 }
375
376 return view;
377 }
378
379 void DolphinColumnView::mousePressEvent(QMouseEvent* event)
380 {
381 m_controller->triggerActivation();
382 QColumnView::mousePressEvent(event);
383 }
384
385 void DolphinColumnView::dragEnterEvent(QDragEnterEvent* event)
386 {
387 if (event->mimeData()->hasUrls()) {
388 event->acceptProposedAction();
389 }
390 }
391
392 void DolphinColumnView::dropEvent(QDropEvent* event)
393 {
394 const KUrl::List urls = KUrl::List::fromMimeData(event->mimeData());
395 if (!urls.isEmpty()) {
396 m_controller->indicateDroppedUrls(urls,
397 indexAt(event->pos()),
398 event->source());
399 event->acceptProposedAction();
400 }
401 QColumnView::dropEvent(event);
402 }
403
404 void DolphinColumnView::zoomIn()
405 {
406 if (isZoomInPossible()) {
407 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
408 // TODO: get rid of K3Icon sizes
409 switch (settings->iconSize()) {
410 case K3Icon::SizeSmall: settings->setIconSize(K3Icon::SizeMedium); break;
411 case K3Icon::SizeMedium: settings->setIconSize(K3Icon::SizeLarge); break;
412 default: Q_ASSERT(false); break;
413 }
414 updateDecorationSize();
415 }
416 }
417
418 void DolphinColumnView::zoomOut()
419 {
420 if (isZoomOutPossible()) {
421 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
422 // TODO: get rid of K3Icon sizes
423 switch (settings->iconSize()) {
424 case K3Icon::SizeLarge: settings->setIconSize(K3Icon::SizeMedium); break;
425 case K3Icon::SizeMedium: settings->setIconSize(K3Icon::SizeSmall); break;
426 default: Q_ASSERT(false); break;
427 }
428 updateDecorationSize();
429 }
430 }
431
432 void DolphinColumnView::triggerItem(const QModelIndex& index)
433 {
434 m_controller->triggerItem(index);
435 updateColumnsState(m_controller->url());
436 }
437
438 void DolphinColumnView::updateColumnsState(const KUrl& url)
439 {
440 foreach (QObject* object, viewport()->children()) {
441 if (object->inherits("QListView")) {
442 ColumnWidget* widget = static_cast<ColumnWidget*>(object);
443 widget->setActive(widget->url() == url);
444 }
445 }
446 }
447
448 bool DolphinColumnView::isZoomInPossible() const
449 {
450 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
451 return settings->iconSize() < K3Icon::SizeLarge;
452 }
453
454 bool DolphinColumnView::isZoomOutPossible() const
455 {
456 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
457 return settings->iconSize() > K3Icon::SizeSmall;
458 }
459
460 void DolphinColumnView::requestActivation(QWidget* column)
461 {
462 foreach (QObject* object, viewport()->children()) {
463 if (object->inherits("QListView")) {
464 ColumnWidget* widget = static_cast<ColumnWidget*>(object);
465 const bool isActive = (widget == column);
466 widget->setActive(isActive);
467 if (isActive) {
468 m_controller->setUrl(widget->url());
469 }
470 }
471 }
472 updateSelections();
473 }
474
475 void DolphinColumnView::updateSelections()
476 {
477 ColumnWidget* previousWidget = 0;
478 foreach (QObject* object, viewport()->children()) {
479 if (object->inherits("QListView")) {
480 ColumnWidget* widget = static_cast<ColumnWidget*>(object);
481 if (previousWidget != 0) {
482 const QAbstractProxyModel* proxyModel = static_cast<const QAbstractProxyModel*>(model());
483 const KDirModel* dirModel = static_cast<const KDirModel*>(proxyModel->sourceModel());
484 const QModelIndex dirIndex = dirModel->indexForUrl(widget->url());
485 const QModelIndex proxyIndex = proxyModel->mapFromSource(dirIndex);
486
487 QItemSelectionModel* selModel = previousWidget->selectionModel();
488 const QItemSelection selection = selModel->selection();
489 const bool isIndexSelected = selModel->isSelected(proxyIndex);
490
491 const bool clearSelection = !previousWidget->isActive() &&
492 ((selection.count() > 1) || !isIndexSelected);
493 if (clearSelection) {
494 selModel->clear();
495 }
496 if (!isIndexSelected) {
497 selModel->select(proxyIndex, QItemSelectionModel::Select);
498 }
499 }
500
501 previousWidget = widget;
502 }
503 }
504 }
505
506 void DolphinColumnView::updateDecorationSize()
507 {
508 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
509 const int iconSize = settings->iconSize();
510
511 foreach (QObject* object, viewport()->children()) {
512 if (object->inherits("QListView")) {
513 ColumnWidget* widget = static_cast<ColumnWidget*>(object);
514 widget->setDecorationSize(QSize(iconSize, iconSize));
515 }
516 }
517
518 m_controller->setZoomInPossible(isZoomInPossible());
519 m_controller->setZoomOutPossible(isZoomOutPossible());
520
521 doItemsLayout();
522 }
523
524 #include "dolphincolumnview.moc"