]> cloud.milkyroute.net Git - dolphin.git/blob - src/dolphincolumnview.cpp
${CMAKE_SOURCE_DIR}/libkonq doesn't exist now
[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 "dolphinmodel.h"
23 #include "dolphincontroller.h"
24 #include "dolphinsettings.h"
25
26 #include "dolphin_columnmodesettings.h"
27
28 #include <kcolorutils.h>
29 #include <kcolorscheme.h>
30 #include <kdirlister.h>
31
32 #include <QAbstractProxyModel>
33 #include <QApplication>
34 #include <QPoint>
35 #include <QScrollBar>
36 #include <QTimer>
37 #include <QTimeLine>
38
39 /**
40 * Represents one column inside the DolphinColumnView and has been
41 * extended to respect view options and hovering information.
42 */
43 class ColumnWidget : public QListView
44 {
45 public:
46 ColumnWidget(QWidget* parent,
47 DolphinColumnView* columnView,
48 const KUrl& url);
49 virtual ~ColumnWidget();
50
51 /** Sets the size of the icons. */
52 void setDecorationSize(const QSize& size);
53
54 /**
55 * An active column is defined as column, which shows the same URL
56 * as indicated by the URL navigator. The active column is usually
57 * drawn in a lighter color. All operations are applied to this column.
58 */
59 void setActive(bool active);
60 bool isActive() const;
61
62 /**
63 * Sets the directory URL of the child column that is shown next to
64 * this column. This property is only used for a visual indication
65 * of the shown directory, it does not trigger a loading of the model.
66 */
67 void setChildUrl(const KUrl& url);
68 const KUrl& childUrl() const;
69
70 /** Sets the directory URL that is shown inside the column widget. */
71 void setUrl(const KUrl& url);
72
73 /** Returns the directory URL that is shown inside the column widget. */
74 const KUrl& url() const;
75
76 protected:
77 virtual QStyleOptionViewItem viewOptions() const;
78 virtual void dragEnterEvent(QDragEnterEvent* event);
79 virtual void dragLeaveEvent(QDragLeaveEvent* event);
80 virtual void dragMoveEvent(QDragMoveEvent* event);
81 virtual void dropEvent(QDropEvent* event);
82 virtual void paintEvent(QPaintEvent* event);
83 virtual void mousePressEvent(QMouseEvent* event);
84 virtual void keyPressEvent(QKeyEvent* event);
85 virtual void contextMenuEvent(QContextMenuEvent* event);
86 virtual void selectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
87
88 private:
89 /** Used by ColumnWidget::setActive(). */
90 void activate();
91
92 /** Used by ColumnWidget::setActive(). */
93 void deactivate();
94
95 private:
96 bool m_active;
97 DolphinColumnView* m_view;
98 KUrl m_url; // URL of the directory that is shown
99 KUrl m_childUrl; // URL of the next column that is shown
100 QStyleOptionViewItem m_viewOptions;
101
102 bool m_dragging; // TODO: remove this property when the issue #160611 is solved in Qt 4.4
103 QRect m_dropRect; // TODO: remove this property when the issue #160611 is solved in Qt 4.4
104 };
105
106 ColumnWidget::ColumnWidget(QWidget* parent,
107 DolphinColumnView* columnView,
108 const KUrl& url) :
109 QListView(parent),
110 m_active(true),
111 m_view(columnView),
112 m_url(url),
113 m_childUrl(),
114 m_dragging(false),
115 m_dropRect()
116 {
117 setMouseTracking(true);
118 viewport()->setAttribute(Qt::WA_Hover);
119 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
120 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
121 setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
122 setSelectionBehavior(SelectItems);
123 setSelectionMode(QAbstractItemView::ExtendedSelection);
124 setDragDropMode(QAbstractItemView::DragDrop);
125 setDropIndicatorShown(false);
126 setFocusPolicy(Qt::NoFocus);
127
128 // apply the column mode settings to the widget
129 const ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
130 Q_ASSERT(settings != 0);
131
132 m_viewOptions = QListView::viewOptions();
133
134 QFont font(settings->fontFamily(), settings->fontSize());
135 font.setItalic(settings->italicFont());
136 font.setBold(settings->boldFont());
137 m_viewOptions.font = font;
138
139 const int iconSize = settings->iconSize();
140 m_viewOptions.decorationSize = QSize(iconSize, iconSize);
141
142 m_viewOptions.showDecorationSelected = true;
143
144 KFileItemDelegate* delegate = new KFileItemDelegate(this);
145 setItemDelegate(delegate);
146
147 activate();
148
149 connect(this, SIGNAL(entered(const QModelIndex&)),
150 m_view->m_controller, SLOT(emitItemEntered(const QModelIndex&)));
151 connect(this, SIGNAL(viewportEntered()),
152 m_view->m_controller, SLOT(emitViewportEntered()));
153 }
154
155 ColumnWidget::~ColumnWidget()
156 {
157 }
158
159 void ColumnWidget::setDecorationSize(const QSize& size)
160 {
161 m_viewOptions.decorationSize = size;
162 doItemsLayout();
163 }
164
165 void ColumnWidget::setActive(bool active)
166 {
167 if (m_active == active) {
168 return;
169 }
170
171 m_active = active;
172
173 if (active) {
174 activate();
175 } else {
176 deactivate();
177 }
178 }
179
180 inline bool ColumnWidget::isActive() const
181 {
182 return m_active;
183 }
184
185 inline void ColumnWidget::setChildUrl(const KUrl& url)
186 {
187 m_childUrl = url;
188 }
189
190 inline const KUrl& ColumnWidget::childUrl() const
191 {
192 return m_childUrl;
193 }
194
195 inline void ColumnWidget::setUrl(const KUrl& url)
196 {
197 m_url = url;
198 }
199
200 inline const KUrl& ColumnWidget::url() const
201 {
202 return m_url;
203 }
204
205 inline QStyleOptionViewItem ColumnWidget::viewOptions() const
206 {
207 return m_viewOptions;
208 }
209
210 void ColumnWidget::dragEnterEvent(QDragEnterEvent* event)
211 {
212 if (event->mimeData()->hasUrls()) {
213 event->acceptProposedAction();
214 }
215
216 m_dragging = true;
217 }
218
219 void ColumnWidget::dragLeaveEvent(QDragLeaveEvent* event)
220 {
221 QListView::dragLeaveEvent(event);
222
223 // TODO: remove this code when the issue #160611 is solved in Qt 4.4
224 m_dragging = false;
225 setDirtyRegion(m_dropRect);
226 }
227
228 void ColumnWidget::dragMoveEvent(QDragMoveEvent* event)
229 {
230 QListView::dragMoveEvent(event);
231
232 // TODO: remove this code when the issue #160611 is solved in Qt 4.4
233 const QModelIndex index = indexAt(event->pos());
234 setDirtyRegion(m_dropRect);
235 m_dropRect = visualRect(index);
236 setDirtyRegion(m_dropRect);
237 }
238
239 void ColumnWidget::dropEvent(QDropEvent* event)
240 {
241 const KUrl::List urls = KUrl::List::fromMimeData(event->mimeData());
242 if (!urls.isEmpty()) {
243 event->acceptProposedAction();
244 m_view->m_controller->indicateDroppedUrls(urls,
245 url(),
246 indexAt(event->pos()),
247 event->source());
248 }
249 QListView::dropEvent(event);
250 m_dragging = false;
251 }
252
253 void ColumnWidget::paintEvent(QPaintEvent* event)
254 {
255 if (!m_childUrl.isEmpty()) {
256 // indicate the shown URL of the next column by highlighting the shown folder item
257 const QModelIndex dirIndex = m_view->m_dolphinModel->indexForUrl(m_childUrl);
258 const QModelIndex proxyIndex = m_view->m_proxyModel->mapFromSource(dirIndex);
259 if (proxyIndex.isValid() && !selectionModel()->isSelected(proxyIndex)) {
260 const QRect itemRect = visualRect(proxyIndex);
261 QPainter painter(viewport());
262 painter.save();
263
264 QColor color = KColorScheme(QPalette::Active, KColorScheme::View).foreground().color();
265 color.setAlpha(32);
266 painter.setPen(Qt::NoPen);
267 painter.setBrush(color);
268 painter.drawRect(itemRect);
269
270 painter.restore();
271 }
272 }
273
274 QListView::paintEvent(event);
275
276 // TODO: remove this code when the issue #160611 is solved in Qt 4.4
277 if (m_dragging) {
278 const QBrush& brush = m_viewOptions.palette.brush(QPalette::Normal, QPalette::Highlight);
279 DolphinController::drawHoverIndication(viewport(), m_dropRect, brush);
280 }
281 }
282
283 void ColumnWidget::mousePressEvent(QMouseEvent* event)
284 {
285 if (!m_active) {
286 m_view->requestActivation(this);
287 }
288
289 QListView::mousePressEvent(event);
290 }
291
292 void ColumnWidget::keyPressEvent(QKeyEvent* event)
293 {
294 QListView::keyPressEvent(event);
295
296 const QItemSelectionModel* selModel = selectionModel();
297 const QModelIndex currentIndex = selModel->currentIndex();
298 const bool triggerItem = currentIndex.isValid()
299 && (event->key() == Qt::Key_Return)
300 && (selModel->selectedIndexes().count() <= 1);
301 if (triggerItem) {
302 m_view->m_controller->triggerItem(currentIndex);
303 }
304 }
305
306 void ColumnWidget::contextMenuEvent(QContextMenuEvent* event)
307 {
308 if (!m_active) {
309 m_view->requestActivation(this);
310 }
311
312 QListView::contextMenuEvent(event);
313
314 const QModelIndex index = indexAt(event->pos());
315 if (index.isValid() || m_active) {
316 // Only open a context menu above an item or if the mouse is above
317 // the active column.
318 const QPoint pos = m_view->viewport()->mapFromGlobal(event->globalPos());
319 m_view->m_controller->triggerContextMenuRequest(pos);
320 }
321 }
322
323 void ColumnWidget::selectionChanged(const QItemSelection& selected, const QItemSelection& deselected)
324 {
325 QListView::selectionChanged(selected, deselected);
326
327 QItemSelectionModel* selModel = m_view->selectionModel();
328 selModel->select(selected, QItemSelectionModel::Select);
329 selModel->select(deselected, QItemSelectionModel::Deselect);
330 }
331
332 void ColumnWidget::activate()
333 {
334 if (m_view->hasFocus()) {
335 setFocus(Qt::OtherFocusReason);
336 }
337 m_view->setFocusProxy(this);
338
339 // TODO: Connecting to the signal 'activated()' is not possible, as kstyle
340 // does not forward the single vs. doubleclick to it yet (KDE 4.1?). Hence it is
341 // necessary connecting the signal 'singleClick()' or 'doubleClick'.
342 if (KGlobalSettings::singleClick()) {
343 connect(this, SIGNAL(clicked(const QModelIndex&)),
344 m_view->m_controller, SLOT(triggerItem(const QModelIndex&)));
345 } else {
346 connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
347 m_view->m_controller, SLOT(triggerItem(const QModelIndex&)));
348 }
349
350 const QColor bgColor = KColorScheme(QPalette::Active, KColorScheme::View).background().color();
351 QPalette palette = viewport()->palette();
352 palette.setColor(viewport()->backgroundRole(), bgColor);
353 viewport()->setPalette(palette);
354
355 if (!m_childUrl.isEmpty()) {
356 // assure that the current index is set on the index that represents
357 // the child URL
358 const QModelIndex dirIndex = m_view->m_dolphinModel->indexForUrl(m_childUrl);
359 const QModelIndex proxyIndex = m_view->m_proxyModel->mapFromSource(dirIndex);
360 selectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::Current);
361 }
362
363 update();
364 }
365
366 void ColumnWidget::deactivate()
367 {
368 // TODO: Connecting to the signal 'activated()' is not possible, as kstyle
369 // does not forward the single vs. doubleclick to it yet (KDE 4.1?). Hence it is
370 // necessary connecting the signal 'singleClick()' or 'doubleClick'.
371 if (KGlobalSettings::singleClick()) {
372 disconnect(this, SIGNAL(clicked(const QModelIndex&)),
373 m_view->m_controller, SLOT(triggerItem(const QModelIndex&)));
374 } else {
375 disconnect(this, SIGNAL(doubleClicked(const QModelIndex&)),
376 m_view->m_controller, SLOT(triggerItem(const QModelIndex&)));
377 }
378
379 const QPalette palette = m_view->viewport()->palette();
380 viewport()->setPalette(palette);
381
382 selectionModel()->clear();
383 update();
384 }
385
386 // ---
387
388 DolphinColumnView::DolphinColumnView(QWidget* parent, DolphinController* controller) :
389 QAbstractItemView(parent),
390 m_controller(controller),
391 m_restoreActiveColumnFocus(false),
392 m_index(-1),
393 m_contentX(0),
394 m_columns(),
395 m_animation(0),
396 m_dolphinModel(0),
397 m_proxyModel(0)
398 {
399 Q_ASSERT(controller != 0);
400
401 setAcceptDrops(true);
402 setDragDropMode(QAbstractItemView::DragDrop);
403 setDropIndicatorShown(false);
404 setSelectionMode(ExtendedSelection);
405
406 connect(this, SIGNAL(entered(const QModelIndex&)),
407 controller, SLOT(emitItemEntered(const QModelIndex&)));
408 connect(this, SIGNAL(viewportEntered()),
409 controller, SLOT(emitViewportEntered()));
410 connect(controller, SIGNAL(zoomIn()),
411 this, SLOT(zoomIn()));
412 connect(controller, SIGNAL(zoomOut()),
413 this, SLOT(zoomOut()));
414 connect(controller, SIGNAL(urlChanged(const KUrl&)),
415 this, SLOT(showColumn(const KUrl&)));
416
417 connect(horizontalScrollBar(), SIGNAL(valueChanged(int)),
418 this, SLOT(moveContentHorizontally(int)));
419
420 m_animation = new QTimeLine(500, this);
421 connect(m_animation, SIGNAL(frameChanged(int)), horizontalScrollBar(), SLOT(setValue(int)));
422
423 ColumnWidget* column = new ColumnWidget(viewport(), this, m_controller->url());
424 m_columns.append(column);
425 setActiveColumnIndex(0);
426
427 updateDecorationSize();
428
429 // dim the background of the viewport
430 QColor bgColor = KColorScheme(QPalette::Active, KColorScheme::View).background().color();
431 const QColor fgColor = KColorScheme(QPalette::Active, KColorScheme::View).foreground().color();
432 bgColor = KColorUtils::mix(bgColor, fgColor, 0.04);
433
434 QPalette palette = viewport()->palette();
435 palette.setColor(viewport()->backgroundRole(), bgColor);
436 viewport()->setPalette(palette);
437 }
438
439 DolphinColumnView::~DolphinColumnView()
440 {
441 }
442
443 QModelIndex DolphinColumnView::indexAt(const QPoint& point) const
444 {
445 foreach (ColumnWidget* column, m_columns) {
446 const QPoint topLeft = column->frameGeometry().topLeft();
447 const QPoint adjustedPoint(point.x() - topLeft.x(), point.y() - topLeft.y());
448 const QModelIndex index = column->indexAt(adjustedPoint);
449 if (index.isValid()) {
450 return index;
451 }
452 }
453
454 return QModelIndex();
455 }
456
457 void DolphinColumnView::scrollTo(const QModelIndex& index, ScrollHint hint)
458 {
459 activeColumn()->scrollTo(index, hint);
460 }
461
462 QRect DolphinColumnView::visualRect(const QModelIndex& index) const
463 {
464 return activeColumn()->visualRect(index);
465 }
466
467 void DolphinColumnView::setModel(QAbstractItemModel* model)
468 {
469 if (m_dolphinModel != 0) {
470 m_dolphinModel->disconnect(this);
471 }
472
473 m_proxyModel = static_cast<QAbstractProxyModel*>(model);
474 m_dolphinModel = static_cast<DolphinModel*>(m_proxyModel->sourceModel());
475 connect(m_dolphinModel, SIGNAL(expand(const QModelIndex&)),
476 this, SLOT(triggerReloadColumns(const QModelIndex&)));
477
478 KDirLister* dirLister = m_dolphinModel->dirLister();
479 connect(dirLister, SIGNAL(completed()),
480 this, SLOT(triggerExpandToActiveUrl()));
481
482 activeColumn()->setModel(model);
483 QAbstractItemView::setModel(model);
484 }
485
486 void DolphinColumnView::invertSelection()
487 {
488 // TODO: this approach of inverting the selection is quite slow. It should
489 // be possible to speedup the implementation by using QItemSelection, but
490 // all adempts have failed yet...
491
492 ColumnWidget* column = activeColumn();
493 QItemSelectionModel* selModel = column->selectionModel();
494
495 KDirLister* dirLister = m_dolphinModel->dirLister();
496 const KFileItemList list = dirLister->itemsForDir(column->url());
497 foreach (const KFileItem item, list) {
498 const QModelIndex index = m_dolphinModel->indexForUrl(item.url());
499 selModel->select(m_proxyModel->mapFromSource(index), QItemSelectionModel::Toggle);
500 }
501 }
502
503 void DolphinColumnView::reload()
504 {
505 // Due to the reloading of the model all columns will be reset to show
506 // the same content as the first column. As this is not wanted, all columns
507 // except of the first column are temporary hidden until the root index can
508 // be updated again.
509 m_restoreActiveColumnFocus = false;
510 QList<ColumnWidget*>::iterator start = m_columns.begin() + 1;
511 QList<ColumnWidget*>::iterator end = m_columns.end();
512 for (QList<ColumnWidget*>::iterator it = start; it != end; ++it) {
513 ColumnWidget* column = (*it);
514 if (column->isActive() && column->hasFocus()) {
515 // because of hiding the column, it will lose the focus
516 // -> remember that the focus should be restored after reloading
517 m_restoreActiveColumnFocus = true;
518 }
519 column->hide();
520 }
521
522 // all columns are hidden, now reload the directory lister
523 KDirLister* dirLister = m_dolphinModel->dirLister();
524 const KUrl& rootUrl = m_columns[0]->url();
525 dirLister->openUrl(rootUrl, false, true);
526 updateColumns();
527 }
528
529 void DolphinColumnView::showColumn(const KUrl& url)
530 {
531 const KUrl& rootUrl = m_columns[0]->url();
532 if (!rootUrl.isParentOf(url)) {
533 // the URL is no child URL of the column view, hence clear all columns
534 // and reset the root column
535 QList<ColumnWidget*>::iterator start = m_columns.begin() + 1;
536 QList<ColumnWidget*>::iterator end = m_columns.end();
537 for (QList<ColumnWidget*>::iterator it = start; it != end; ++it) {
538 (*it)->deleteLater();
539 }
540 m_columns.erase(start, end);
541 m_index = 0;
542 m_columns[0]->setActive(true);
543 m_columns[0]->setUrl(url);
544 assureVisibleActiveColumn();
545 return;
546 }
547
548 KDirLister* dirLister = m_dolphinModel->dirLister();
549 const KUrl dirListerUrl = dirLister->url();
550 if (dirListerUrl != rootUrl) {
551 // It is possible that root URL of the directory lister is adjusted
552 // after creating the column widget (e. g. when restoring the history
553 // having a different root URL than the controller indicates).
554 m_columns[0]->setUrl(dirListerUrl);
555 }
556
557 int columnIndex = 0;
558 foreach (ColumnWidget* column, m_columns) {
559 if (column->url() == url) {
560 // the column represents already the requested URL, hence activate it
561 requestActivation(column);
562 return;
563 } else if (!column->url().isParentOf(url)) {
564 // the column is no parent of the requested URL, hence
565 // just delete all remaining columns
566 if (columnIndex > 0) {
567 QList<ColumnWidget*>::iterator start = m_columns.begin() + columnIndex;
568 QList<ColumnWidget*>::iterator end = m_columns.end();
569 for (QList<ColumnWidget*>::iterator it = start; it != end; ++it) {
570 (*it)->deleteLater();
571 }
572 m_columns.erase(start, end);
573
574 const int maxIndex = m_columns.count() - 1;
575 Q_ASSERT(maxIndex >= 0);
576 if (m_index > maxIndex) {
577 m_index = maxIndex;
578 }
579 break;
580 }
581 }
582 ++columnIndex;
583 }
584
585 // Create missing columns. Assuming that the path is "/home/peter/Temp/" and
586 // the target path is "/home/peter/Temp/a/b/c/", then the columns "a", "b" and
587 // "c" will be created.
588 const int lastIndex = m_columns.count() - 1;
589 Q_ASSERT(lastIndex >= 0);
590
591 const KUrl& activeUrl = m_columns[lastIndex]->url();
592 Q_ASSERT(activeUrl.isParentOf(url));
593 Q_ASSERT(activeUrl != url);
594
595 QString path = activeUrl.url(KUrl::AddTrailingSlash);
596 const QString targetPath = url.url(KUrl::AddTrailingSlash);
597
598 columnIndex = lastIndex;
599 int slashIndex = path.count('/');
600 bool hasSubPath = (slashIndex >= 0);
601 while (hasSubPath) {
602 const QString subPath = targetPath.section('/', slashIndex, slashIndex);
603 if (subPath.isEmpty()) {
604 hasSubPath = false;
605 } else {
606 path += subPath + '/';
607 ++slashIndex;
608
609 const KUrl childUrl = KUrl(path);
610 const QModelIndex dirIndex = m_dolphinModel->indexForUrl(KUrl(path));
611 const QModelIndex proxyIndex = m_proxyModel->mapFromSource(dirIndex);
612
613 m_columns[columnIndex]->setChildUrl(childUrl);
614 columnIndex++;
615
616 ColumnWidget* column = new ColumnWidget(viewport(), this, childUrl);
617 column->setModel(model());
618 column->setRootIndex(proxyIndex);
619 column->setActive(false);
620
621 m_columns.append(column);
622
623 // Before invoking layoutColumns() the column must be set visible temporary.
624 // To prevent a flickering the initial geometry is set to a hidden position.
625 column->setGeometry(QRect(-1, -1, 1, 1));
626 column->show();
627 layoutColumns();
628 updateScrollBar();
629
630 // the layout is finished, now let the column be invisible until it
631 // gets a valid root index due to expandToActiveUrl()
632 column->hide();
633 }
634 }
635
636 // set the last column as active column without modifying the controller
637 // and hence the history
638 activeColumn()->setActive(false);
639 m_index = columnIndex;
640 activeColumn()->setActive(true);
641 assureVisibleActiveColumn();
642 }
643
644 void DolphinColumnView::selectAll()
645 {
646 activeColumn()->selectAll();
647 }
648
649 bool DolphinColumnView::isIndexHidden(const QModelIndex& index) const
650 {
651 Q_UNUSED(index);
652 return false;//activeColumn()->isIndexHidden(index);
653 }
654
655 QModelIndex DolphinColumnView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
656 {
657 // Parts of this code have been taken from QColumnView::moveCursor().
658 // Copyright (C) 1992-2007 Trolltech ASA.
659
660 Q_UNUSED(modifiers);
661 if (model() == 0) {
662 return QModelIndex();
663 }
664
665 const QModelIndex current = currentIndex();
666 if (isRightToLeft()) {
667 if (cursorAction == MoveLeft) {
668 cursorAction = MoveRight;
669 } else if (cursorAction == MoveRight) {
670 cursorAction = MoveLeft;
671 }
672 }
673
674 switch (cursorAction) {
675 case MoveLeft:
676 if (m_index > 0) {
677 setActiveColumnIndex(m_index - 1);
678 }
679 break;
680
681 case MoveRight:
682 if (m_index < m_columns.count() - 1) {
683 setActiveColumnIndex(m_index + 1);
684 }
685 break;
686
687 default:
688 break;
689 }
690
691 return QModelIndex();
692 }
693
694 void DolphinColumnView::setSelection(const QRect& rect, QItemSelectionModel::SelectionFlags flags)
695 {
696 Q_UNUSED(rect);
697 Q_UNUSED(flags);
698 //activeColumn()->setSelection(rect, flags);
699 }
700
701 QRegion DolphinColumnView::visualRegionForSelection(const QItemSelection& selection) const
702 {
703 Q_UNUSED(selection);
704 return QRegion(); //activeColumn()->visualRegionForSelection(selection);
705 }
706
707 int DolphinColumnView::horizontalOffset() const
708 {
709 return -m_contentX;
710 }
711
712 int DolphinColumnView::verticalOffset() const
713 {
714 return 0;
715 }
716
717 void DolphinColumnView::mousePressEvent(QMouseEvent* event)
718 {
719 m_controller->triggerActivation();
720 QAbstractItemView::mousePressEvent(event);
721 }
722
723 void DolphinColumnView::resizeEvent(QResizeEvent* event)
724 {
725 QAbstractItemView::resizeEvent(event);
726 layoutColumns();
727 updateScrollBar();
728 }
729
730 void DolphinColumnView::zoomIn()
731 {
732 if (isZoomInPossible()) {
733 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
734 switch (settings->iconSize()) {
735 case KIconLoader::SizeSmall: settings->setIconSize(KIconLoader::SizeMedium); break;
736 case KIconLoader::SizeMedium: settings->setIconSize(KIconLoader::SizeLarge); break;
737 default: Q_ASSERT(false); break;
738 }
739 updateDecorationSize();
740 }
741 }
742
743 void DolphinColumnView::zoomOut()
744 {
745 if (isZoomOutPossible()) {
746 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
747 switch (settings->iconSize()) {
748 case KIconLoader::SizeLarge: settings->setIconSize(KIconLoader::SizeMedium); break;
749 case KIconLoader::SizeMedium: settings->setIconSize(KIconLoader::SizeSmall); break;
750 default: Q_ASSERT(false); break;
751 }
752 updateDecorationSize();
753 }
754 }
755
756 void DolphinColumnView::moveContentHorizontally(int x)
757 {
758 m_contentX = isRightToLeft() ? +x : -x;
759 layoutColumns();
760 }
761
762 void DolphinColumnView::updateDecorationSize()
763 {
764 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
765 const int iconSize = settings->iconSize();
766
767 foreach (QObject* object, viewport()->children()) {
768 if (object->inherits("QListView")) {
769 ColumnWidget* widget = static_cast<ColumnWidget*>(object);
770 widget->setDecorationSize(QSize(iconSize, iconSize));
771 }
772 }
773
774 m_controller->setZoomInPossible(isZoomInPossible());
775 m_controller->setZoomOutPossible(isZoomOutPossible());
776
777 doItemsLayout();
778 }
779
780 void DolphinColumnView::expandToActiveUrl()
781 {
782 const int lastIndex = m_columns.count() - 1;
783 Q_ASSERT(lastIndex >= 0);
784 const KUrl& activeUrl = m_columns[lastIndex]->url();
785 const KUrl rootUrl = m_dolphinModel->dirLister()->url();
786 const bool expand = rootUrl.isParentOf(activeUrl)
787 && !rootUrl.equals(activeUrl, KUrl::CompareWithoutTrailingSlash);
788 if (expand) {
789 m_dolphinModel->expandToUrl(activeUrl);
790 }
791 updateColumns();
792 }
793
794 void DolphinColumnView::triggerUpdateColumns(const QModelIndex& index)
795 {
796 Q_UNUSED(index);
797 // the updating of the columns may not be done in the context of this slot
798 QMetaObject::invokeMethod(this, "updateColumns", Qt::QueuedConnection);
799 }
800
801 void DolphinColumnView::updateColumns()
802 {
803 const int end = m_columns.count() - 2; // next to last column
804 for (int i = 0; i <= end; ++i) {
805 ColumnWidget* nextColumn = m_columns[i + 1];
806 const QModelIndex rootIndex = nextColumn->rootIndex();
807 if (rootIndex.isValid()) {
808 nextColumn->show();
809 } else {
810 const QModelIndex dirIndex = m_dolphinModel->indexForUrl(m_columns[i]->childUrl());
811 const QModelIndex proxyIndex = m_proxyModel->mapFromSource(dirIndex);
812 if (proxyIndex.isValid()) {
813 nextColumn->setRootIndex(proxyIndex);
814 nextColumn->show();
815 if (nextColumn->isActive() && m_restoreActiveColumnFocus) {
816 nextColumn->setFocus();
817 m_restoreActiveColumnFocus = false;
818 }
819 }
820 }
821 }
822 }
823
824 void DolphinColumnView::triggerExpandToActiveUrl()
825 {
826 QMetaObject::invokeMethod(this, "expandToActiveUrl", Qt::QueuedConnection);
827 }
828
829 bool DolphinColumnView::isZoomInPossible() const
830 {
831 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
832 return settings->iconSize() < KIconLoader::SizeLarge;
833 }
834
835 bool DolphinColumnView::isZoomOutPossible() const
836 {
837 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
838 return settings->iconSize() > KIconLoader::SizeSmall;
839 }
840
841 void DolphinColumnView::setActiveColumnIndex(int index)
842 {
843 if (m_index == index) {
844 return;
845 }
846
847 const bool hasActiveColumn = (m_index >= 0);
848 if (hasActiveColumn) {
849 m_columns[m_index]->setActive(false);
850 }
851
852 m_index = index;
853 m_columns[m_index]->setActive(true);
854
855 m_controller->setUrl(m_columns[m_index]->url());
856
857 assureVisibleActiveColumn();
858 }
859
860 void DolphinColumnView::layoutColumns()
861 {
862 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
863 const int columnWidth = settings->columnWidth();
864 if (isRightToLeft()) {
865 int x = viewport()->width() - columnWidth + m_contentX;
866 foreach (ColumnWidget* column, m_columns) {
867 column->setGeometry(QRect(x, 0, columnWidth, viewport()->height()));
868 x -= columnWidth;
869 }
870 } else {
871 int x = m_contentX;
872 foreach (ColumnWidget* column, m_columns) {
873 column->setGeometry(QRect(x, 0, columnWidth, viewport()->height()));
874 x += columnWidth;
875 }
876 }
877 }
878
879 void DolphinColumnView::updateScrollBar()
880 {
881 int contentWidth = 0;
882 foreach (ColumnWidget* column, m_columns) {
883 contentWidth += column->width();
884 }
885
886 horizontalScrollBar()->setPageStep(contentWidth);
887 horizontalScrollBar()->setRange(0, contentWidth - viewport()->width());
888 }
889
890 void DolphinColumnView::assureVisibleActiveColumn()
891 {
892 const int viewportWidth = viewport()->width();
893 const int x = activeColumn()->x();
894 const int width = activeColumn()->width();
895 if (x + width > viewportWidth) {
896 const int newContentX = m_contentX - x - width + viewportWidth;
897 if (isRightToLeft()) {
898 m_animation->setFrameRange(m_contentX, newContentX);
899 } else {
900 m_animation->setFrameRange(-m_contentX, -newContentX);
901 }
902 m_animation->start();
903 } else if (x < 0) {
904 const int newContentX = m_contentX - x;
905 if (isRightToLeft()) {
906 m_animation->setFrameRange(m_contentX, newContentX);
907 } else {
908 m_animation->setFrameRange(-m_contentX, -newContentX);
909 }
910 m_animation->start();
911 }
912 }
913
914 void DolphinColumnView::requestActivation(ColumnWidget* column)
915 {
916 if (column->isActive()) {
917 assureVisibleActiveColumn();
918 } else {
919 int index = 0;
920 foreach (ColumnWidget* currColumn, m_columns) {
921 if (currColumn == column) {
922 setActiveColumnIndex(index);
923 return;
924 }
925 ++index;
926 }
927 }
928 }
929
930 #include "dolphincolumnview.moc"