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