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