]> cloud.milkyroute.net Git - dolphin.git/blob - src/dolphincolumnview.cpp
warning--
[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 "dolphincolumnwidget.h"
23 #include "dolphincontroller.h"
24 #include "dolphinsettings.h"
25
26 #include "dolphin_columnmodesettings.h"
27
28 #include <QPoint>
29 #include <QScrollBar>
30 #include <QTimeLine>
31
32 DolphinColumnView::DolphinColumnView(QWidget* parent, DolphinController* controller) :
33 QAbstractItemView(parent),
34 m_controller(controller),
35 m_active(false),
36 m_index(-1),
37 m_contentX(0),
38 m_columns(),
39 m_emptyViewport(0),
40 m_animation(0),
41 m_nameFilter()
42 {
43 Q_ASSERT(controller != 0);
44
45 setAcceptDrops(true);
46 setDragDropMode(QAbstractItemView::DragDrop);
47 setDropIndicatorShown(false);
48 setSelectionMode(ExtendedSelection);
49 setFocusPolicy(Qt::NoFocus);
50 setFrameShape(QFrame::NoFrame);
51 setLayoutDirection(Qt::LeftToRight);
52
53 connect(this, SIGNAL(viewportEntered()),
54 controller, SLOT(emitViewportEntered()));
55 connect(controller, SIGNAL(zoomLevelChanged(int)),
56 this, SLOT(setZoomLevel(int)));
57 connect(controller, SIGNAL(activationChanged(bool)),
58 this, SLOT(updateColumnsBackground(bool)));
59
60 const DolphinView* view = controller->dolphinView();
61 connect(view, SIGNAL(sortingChanged(DolphinView::Sorting)),
62 this, SLOT(slotSortingChanged(DolphinView::Sorting)));
63 connect(view, SIGNAL(sortOrderChanged(Qt::SortOrder)),
64 this, SLOT(slotSortOrderChanged(Qt::SortOrder)));
65 connect(view, SIGNAL(showHiddenFilesChanged()),
66 this, SLOT(slotShowHiddenFilesChanged()));
67 connect(view, SIGNAL(showPreviewChanged()),
68 this, SLOT(slotShowPreviewChanged()));
69
70 connect(horizontalScrollBar(), SIGNAL(valueChanged(int)),
71 this, SLOT(moveContentHorizontally(int)));
72
73 m_animation = new QTimeLine(500, this);
74 connect(m_animation, SIGNAL(frameChanged(int)), horizontalScrollBar(), SLOT(setValue(int)));
75
76 DolphinColumnWidget* column = new DolphinColumnWidget(viewport(), this, m_controller->url());
77 m_columns.append(column);
78 setActiveColumnIndex(0);
79
80 m_emptyViewport = new QFrame(viewport());
81 m_emptyViewport->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
82
83 updateDecorationSize(view->showPreview());
84 updateColumnsBackground(true);
85 }
86
87 DolphinColumnView::~DolphinColumnView()
88 {
89 }
90
91 QModelIndex DolphinColumnView::indexAt(const QPoint& point) const
92 {
93 foreach (DolphinColumnWidget* column, m_columns) {
94 const QModelIndex index = column->indexAt(columnPosition(column, point));
95 if (index.isValid()) {
96 return index;
97 }
98 }
99
100 return QModelIndex();
101 }
102
103 KFileItem DolphinColumnView::itemAt(const QPoint& point) const
104 {
105 foreach (DolphinColumnWidget* column, m_columns) {
106 KFileItem item = column->itemAt(columnPosition(column, point));
107 if (!item.isNull()) {
108 return item;
109 }
110 }
111
112 return KFileItem();
113 }
114
115 void DolphinColumnView::scrollTo(const QModelIndex& index, ScrollHint hint)
116 {
117 activeColumn()->scrollTo(index, hint);
118 }
119
120 QRect DolphinColumnView::visualRect(const QModelIndex& index) const
121 {
122 return activeColumn()->visualRect(index);
123 }
124
125 void DolphinColumnView::invertSelection()
126 {
127 QItemSelectionModel* selectionModel = activeColumn()->selectionModel();
128 const QAbstractItemModel* itemModel = selectionModel->model();
129
130 const QModelIndex topLeft = itemModel->index(0, 0);
131 const QModelIndex bottomRight = itemModel->index(itemModel->rowCount() - 1,
132 itemModel->columnCount() - 1);
133
134 const QItemSelection selection(topLeft, bottomRight);
135 selectionModel->select(selection, QItemSelectionModel::Toggle);
136 }
137
138 void DolphinColumnView::reload()
139 {
140 foreach (DolphinColumnWidget* column, m_columns) {
141 column->reload();
142 }
143 }
144
145 void DolphinColumnView::setRootUrl(const KUrl& url)
146 {
147 removeAllColumns();
148 m_columns[0]->setUrl(url);
149 }
150
151 void DolphinColumnView::setNameFilter(const QString& nameFilter)
152 {
153 if (nameFilter != m_nameFilter) {
154 m_nameFilter = nameFilter;
155 foreach (DolphinColumnWidget* column, m_columns) {
156 column->setNameFilter(nameFilter);
157 }
158 }
159 }
160
161 QString DolphinColumnView::nameFilter() const
162 {
163 return m_nameFilter;
164 }
165
166 KUrl DolphinColumnView::rootUrl() const
167 {
168 return m_columns[0]->url();
169 }
170
171 void DolphinColumnView::showColumn(const KUrl& url)
172 {
173 if (!rootUrl().isParentOf(url)) {
174 setRootUrl(url);
175 return;
176 }
177
178 int columnIndex = 0;
179 foreach (DolphinColumnWidget* column, m_columns) {
180 if (column->url() == url) {
181 // the column represents already the requested URL, hence activate it
182 requestActivation(column);
183 layoutColumns();
184 return;
185 } else if (!column->url().isParentOf(url)) {
186 // the column is no parent of the requested URL, hence
187 // just delete all remaining columns
188 if (columnIndex > 0) {
189 QList<DolphinColumnWidget*>::iterator start = m_columns.begin() + columnIndex;
190 QList<DolphinColumnWidget*>::iterator end = m_columns.end();
191 for (QList<DolphinColumnWidget*>::iterator it = start; it != end; ++it) {
192 deleteColumn(*it);
193 }
194 m_columns.erase(start, end);
195
196 const int maxIndex = m_columns.count() - 1;
197 Q_ASSERT(maxIndex >= 0);
198 if (m_index > maxIndex) {
199 m_index = maxIndex;
200 }
201 break;
202 }
203 }
204 ++columnIndex;
205 }
206
207 // Create missing columns. Assuming that the path is "/home/peter/Temp/" and
208 // the target path is "/home/peter/Temp/a/b/c/", then the columns "a", "b" and
209 // "c" will be created.
210 const int lastIndex = m_columns.count() - 1;
211 Q_ASSERT(lastIndex >= 0);
212
213 const KUrl& activeUrl = m_columns[lastIndex]->url();
214 Q_ASSERT(activeUrl.isParentOf(url));
215 Q_ASSERT(activeUrl != url);
216
217 QString path = activeUrl.url(KUrl::AddTrailingSlash);
218 const QString targetPath = url.url(KUrl::AddTrailingSlash);
219
220 columnIndex = lastIndex;
221 int slashIndex = path.count('/');
222 bool hasSubPath = (slashIndex >= 0);
223 while (hasSubPath) {
224 const QString subPath = targetPath.section('/', slashIndex, slashIndex);
225 if (subPath.isEmpty()) {
226 hasSubPath = false;
227 } else {
228 path += subPath + '/';
229 ++slashIndex;
230
231 const KUrl childUrl = KUrl(path);
232 m_columns[columnIndex]->setChildUrl(childUrl);
233 columnIndex++;
234
235 DolphinColumnWidget* column = new DolphinColumnWidget(viewport(), this, childUrl);
236 const QString filter = nameFilter();
237 if (!filter.isEmpty()) {
238 column->setNameFilter(filter);
239 }
240 column->setActive(false);
241
242 m_columns.append(column);
243
244 // Before invoking layoutColumns() the column must be set visible temporary.
245 // To prevent a flickering the initial geometry is set to a hidden position.
246 column->setGeometry(QRect(-1, -1, 1, 1));
247 column->show();
248 layoutColumns();
249 updateScrollBar();
250 }
251 }
252
253 // set the last column as active column without modifying the controller
254 // and hence the history
255 activeColumn()->setActive(false);
256 m_index = columnIndex;
257 activeColumn()->setActive(true);
258 assureVisibleActiveColumn();
259 }
260
261 void DolphinColumnView::editItem(const KFileItem& item)
262 {
263 activeColumn()->editItem(item);
264 }
265
266 KFileItemList DolphinColumnView::selectedItems() const
267 {
268 return activeColumn()->selectedItems();
269 }
270
271 void DolphinColumnView::selectAll()
272 {
273 activeColumn()->selectAll();
274 }
275
276 bool DolphinColumnView::isIndexHidden(const QModelIndex& index) const
277 {
278 Q_UNUSED(index);
279 return false;//activeColumn()->isIndexHidden(index);
280 }
281
282 QModelIndex DolphinColumnView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
283 {
284 // Parts of this code have been taken from QColumnView::moveCursor().
285 // Copyright (C) 1992-2007 Trolltech ASA.
286
287 Q_UNUSED(modifiers);
288 if (model() == 0) {
289 return QModelIndex();
290 }
291
292 const QModelIndex current = currentIndex();
293 if (isRightToLeft()) {
294 if (cursorAction == MoveLeft) {
295 cursorAction = MoveRight;
296 } else if (cursorAction == MoveRight) {
297 cursorAction = MoveLeft;
298 }
299 }
300
301 switch (cursorAction) {
302 case MoveLeft:
303 if (m_index > 0) {
304 setActiveColumnIndex(m_index - 1);
305 m_controller->triggerUrlChangeRequest(activeColumn()->url());
306 }
307 break;
308
309 case MoveRight:
310 if (m_index < m_columns.count() - 1) {
311 setActiveColumnIndex(m_index + 1);
312 m_controller->triggerUrlChangeRequest(m_columns[m_index]->url());
313 }
314 break;
315
316 default:
317 break;
318 }
319
320 return QModelIndex();
321 }
322
323 void DolphinColumnView::setSelection(const QRect& rect, QItemSelectionModel::SelectionFlags flags)
324 {
325 Q_UNUSED(rect);
326 Q_UNUSED(flags);
327 }
328
329 QRegion DolphinColumnView::visualRegionForSelection(const QItemSelection& selection) const
330 {
331 Q_UNUSED(selection);
332 return QRegion();
333 }
334
335 int DolphinColumnView::horizontalOffset() const
336 {
337 return -m_contentX;
338 }
339
340 int DolphinColumnView::verticalOffset() const
341 {
342 return 0;
343 }
344
345 void DolphinColumnView::mousePressEvent(QMouseEvent* event)
346 {
347 m_controller->requestActivation();
348 QAbstractItemView::mousePressEvent(event);
349 }
350
351 void DolphinColumnView::resizeEvent(QResizeEvent* event)
352 {
353 QAbstractItemView::resizeEvent(event);
354 layoutColumns();
355 updateScrollBar();
356 assureVisibleActiveColumn();
357 }
358
359 void DolphinColumnView::wheelEvent(QWheelEvent* event)
360 {
361 // let Ctrl+wheel events propagate to the DolphinView for icon zooming
362 if ((event->modifiers() & Qt::ControlModifier) == Qt::ControlModifier) {
363 event->ignore();
364 return;
365 }
366 QAbstractItemView::wheelEvent(event);
367 }
368
369 void DolphinColumnView::setZoomLevel(int level)
370 {
371 const int size = DolphinController::iconSizeForZoomLevel(level);
372 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
373
374 const bool showPreview = m_controller->dolphinView()->showPreview();
375 if (showPreview) {
376 settings->setPreviewSize(size);
377 } else {
378 settings->setIconSize(size);
379 }
380
381 updateDecorationSize(showPreview);
382 }
383
384 void DolphinColumnView::moveContentHorizontally(int x)
385 {
386 m_contentX = isRightToLeft() ? +x : -x;
387 layoutColumns();
388 }
389
390 void DolphinColumnView::updateDecorationSize(bool showPreview)
391 {
392 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
393 const int iconSize = showPreview ? settings->previewSize() : settings->iconSize();
394 const QSize size(iconSize, iconSize);
395 setIconSize(size);
396
397 foreach (QObject* object, viewport()->children()) {
398 if (object->inherits("QListView")) {
399 DolphinColumnWidget* widget = static_cast<DolphinColumnWidget*>(object);
400 widget->setDecorationSize(size);
401 }
402 }
403
404 doItemsLayout();
405 }
406
407 void DolphinColumnView::updateColumnsBackground(bool active)
408 {
409 if (active == m_active) {
410 return;
411 }
412
413 m_active = active;
414
415 // dim the background of the viewport
416 const QPalette::ColorRole role = viewport()->backgroundRole();
417 QColor background = viewport()->palette().color(role);
418 background.setAlpha(0); // make background transparent
419
420 QPalette palette = viewport()->palette();
421 palette.setColor(role, background);
422 viewport()->setPalette(palette);
423
424 foreach (DolphinColumnWidget* column, m_columns) {
425 column->updateBackground();
426 }
427 }
428
429 void DolphinColumnView::slotSortingChanged(DolphinView::Sorting sorting)
430 {
431 foreach (DolphinColumnWidget* column, m_columns) {
432 column->setSorting(sorting);
433 }
434 }
435
436 void DolphinColumnView::slotSortOrderChanged(Qt::SortOrder order)
437 {
438 foreach (DolphinColumnWidget* column, m_columns) {
439 column->setSortOrder(order);
440 }
441 }
442
443 void DolphinColumnView::slotShowHiddenFilesChanged()
444 {
445 const bool show = m_controller->dolphinView()->showHiddenFiles();
446 foreach (DolphinColumnWidget* column, m_columns) {
447 column->setShowHiddenFiles(show);
448 }
449 }
450
451 void DolphinColumnView::slotShowPreviewChanged()
452 {
453 const bool show = m_controller->dolphinView()->showPreview();
454 updateDecorationSize(show);
455 foreach (DolphinColumnWidget* column, m_columns) {
456 column->setShowPreview(show);
457 }
458 }
459
460 void DolphinColumnView::setActiveColumnIndex(int index)
461 {
462 if (m_index == index) {
463 return;
464 }
465
466 const bool hasActiveColumn = (m_index >= 0);
467 if (hasActiveColumn) {
468 m_columns[m_index]->setActive(false);
469 }
470
471 m_index = index;
472 m_columns[m_index]->setActive(true);
473
474 assureVisibleActiveColumn();
475 }
476
477 void DolphinColumnView::layoutColumns()
478 {
479 const int gap = 4;
480
481 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
482 const int columnWidth = settings->columnWidth();
483
484 QRect emptyViewportRect;
485 if (isRightToLeft()) {
486 int x = viewport()->width() - columnWidth + m_contentX;
487 foreach (DolphinColumnWidget* column, m_columns) {
488 column->setGeometry(QRect(x, 0, columnWidth - gap, viewport()->height()));
489 x -= columnWidth;
490 }
491 emptyViewportRect = QRect(0, 0, x + columnWidth - gap, viewport()->height());
492 } else {
493 int x = m_contentX;
494 foreach (DolphinColumnWidget* column, m_columns) {
495 column->setGeometry(QRect(x, 0, columnWidth - gap, viewport()->height()));
496 x += columnWidth;
497 }
498 emptyViewportRect = QRect(x, 0, viewport()->width() - x - gap, viewport()->height());
499 }
500
501 if (emptyViewportRect.isValid()) {
502 m_emptyViewport->show();
503 m_emptyViewport->setGeometry(emptyViewportRect);
504 } else {
505 m_emptyViewport->hide();
506 }
507 }
508
509 void DolphinColumnView::updateScrollBar()
510 {
511 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
512 const int contentWidth = m_columns.count() * settings->columnWidth();
513
514 horizontalScrollBar()->setPageStep(contentWidth);
515 horizontalScrollBar()->setRange(0, contentWidth - viewport()->width());
516 }
517
518 void DolphinColumnView::assureVisibleActiveColumn()
519 {
520 const int viewportWidth = viewport()->width();
521 const int x = activeColumn()->x();
522
523 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
524 const int width = settings->columnWidth();
525
526 if (x + width > viewportWidth) {
527 const int newContentX = m_contentX - x - width + viewportWidth;
528 if (isRightToLeft()) {
529 m_animation->setFrameRange(m_contentX, newContentX);
530 } else {
531 m_animation->setFrameRange(-m_contentX, -newContentX);
532 }
533 if (m_animation->state() != QTimeLine::Running) {
534 m_animation->start();
535 }
536 } else if (x < 0) {
537 const int newContentX = m_contentX - x;
538 if (isRightToLeft()) {
539 m_animation->setFrameRange(m_contentX, newContentX);
540 } else {
541 m_animation->setFrameRange(-m_contentX, -newContentX);
542 }
543 if (m_animation->state() != QTimeLine::Running) {
544 m_animation->start();
545 }
546 }
547 }
548
549 void DolphinColumnView::requestActivation(DolphinColumnWidget* column)
550 {
551 m_controller->setItemView(column);
552 if (column->isActive()) {
553 assureVisibleActiveColumn();
554 } else {
555 int index = 0;
556 foreach (DolphinColumnWidget* currColumn, m_columns) {
557 if (currColumn == column) {
558 setActiveColumnIndex(index);
559 return;
560 }
561 ++index;
562 }
563 }
564 }
565
566 void DolphinColumnView::removeAllColumns()
567 {
568 QList<DolphinColumnWidget*>::iterator start = m_columns.begin() + 1;
569 QList<DolphinColumnWidget*>::iterator end = m_columns.end();
570 for (QList<DolphinColumnWidget*>::iterator it = start; it != end; ++it) {
571 deleteColumn(*it);
572 }
573 m_columns.erase(start, end);
574 m_index = 0;
575 m_columns[0]->setActive(true);
576 assureVisibleActiveColumn();
577 }
578
579 QPoint DolphinColumnView::columnPosition(DolphinColumnWidget* column, const QPoint& point) const
580 {
581 const QPoint topLeft = column->frameGeometry().topLeft();
582 return QPoint(point.x() - topLeft.x(), point.y() - topLeft.y());
583 }
584
585 void DolphinColumnView::deleteColumn(DolphinColumnWidget* column)
586 {
587 if (column != 0) {
588 if (m_controller->itemView() == column) {
589 m_controller->setItemView(0);
590 }
591 column->disconnect();
592 column->deleteLater();
593 }
594 }
595
596 #include "dolphincolumnview.moc"