]> cloud.milkyroute.net Git - dolphin.git/blob - src/dolphincolumnview.cpp
* assure that the columns of the colum-view get dimmed if the colum-view is inactive
[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_animation(0)
51 {
52 Q_ASSERT(controller != 0);
53
54 setAcceptDrops(true);
55 setDragDropMode(QAbstractItemView::DragDrop);
56 setDropIndicatorShown(false);
57 setSelectionMode(ExtendedSelection);
58
59 connect(this, SIGNAL(entered(const QModelIndex&)),
60 controller, SLOT(emitItemEntered(const QModelIndex&)));
61 connect(this, SIGNAL(viewportEntered()),
62 controller, SLOT(emitViewportEntered()));
63 connect(controller, SIGNAL(zoomIn()),
64 this, SLOT(zoomIn()));
65 connect(controller, SIGNAL(zoomOut()),
66 this, SLOT(zoomOut()));
67 connect(controller, SIGNAL(showHiddenFilesChanged(bool)),
68 this, SLOT(slotShowHiddenFilesChanged(bool)));
69 connect(controller, SIGNAL(showPreviewChanged(bool)),
70 this, SLOT(slotShowPreviewChanged(bool)));
71 connect(controller, SIGNAL(activationChanged(bool)),
72 this, SLOT(updateColumnsBackground(bool)));
73
74 connect(horizontalScrollBar(), SIGNAL(valueChanged(int)),
75 this, SLOT(moveContentHorizontally(int)));
76
77 m_animation = new QTimeLine(500, this);
78 connect(m_animation, SIGNAL(frameChanged(int)), horizontalScrollBar(), SLOT(setValue(int)));
79
80 DolphinColumnWidget* column = new DolphinColumnWidget(viewport(), this, m_controller->url());
81 m_columns.append(column);
82 setActiveColumnIndex(0);
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 KUrl DolphinColumnView::rootUrl() const
143 {
144 return m_columns[0]->url();
145 }
146
147 void DolphinColumnView::showColumn(const KUrl& url)
148 {
149 if (!rootUrl().isParentOf(url)) {
150 setRootUrl(url);
151 return;
152 }
153
154 int columnIndex = 0;
155 foreach (DolphinColumnWidget* column, m_columns) {
156 if (column->url() == url) {
157 // the column represents already the requested URL, hence activate it
158 requestActivation(column);
159 return;
160 } else if (!column->url().isParentOf(url)) {
161 // the column is no parent of the requested URL, hence
162 // just delete all remaining columns
163 if (columnIndex > 0) {
164 QList<DolphinColumnWidget*>::iterator start = m_columns.begin() + columnIndex;
165 QList<DolphinColumnWidget*>::iterator end = m_columns.end();
166 for (QList<DolphinColumnWidget*>::iterator it = start; it != end; ++it) {
167 (*it)->deleteLater();
168 }
169 m_columns.erase(start, end);
170
171 const int maxIndex = m_columns.count() - 1;
172 Q_ASSERT(maxIndex >= 0);
173 if (m_index > maxIndex) {
174 m_index = maxIndex;
175 }
176 break;
177 }
178 }
179 ++columnIndex;
180 }
181
182 // Create missing columns. Assuming that the path is "/home/peter/Temp/" and
183 // the target path is "/home/peter/Temp/a/b/c/", then the columns "a", "b" and
184 // "c" will be created.
185 const int lastIndex = m_columns.count() - 1;
186 Q_ASSERT(lastIndex >= 0);
187
188 const KUrl& activeUrl = m_columns[lastIndex]->url();
189 Q_ASSERT(activeUrl.isParentOf(url));
190 Q_ASSERT(activeUrl != url);
191
192 QString path = activeUrl.url(KUrl::AddTrailingSlash);
193 const QString targetPath = url.url(KUrl::AddTrailingSlash);
194
195 columnIndex = lastIndex;
196 int slashIndex = path.count('/');
197 bool hasSubPath = (slashIndex >= 0);
198 while (hasSubPath) {
199 const QString subPath = targetPath.section('/', slashIndex, slashIndex);
200 if (subPath.isEmpty()) {
201 hasSubPath = false;
202 } else {
203 path += subPath + '/';
204 ++slashIndex;
205
206 const KUrl childUrl = KUrl(path);
207 m_columns[columnIndex]->setChildUrl(childUrl);
208 columnIndex++;
209
210 DolphinColumnWidget* column = new DolphinColumnWidget(viewport(), this, childUrl);
211 column->setActive(false);
212
213 m_columns.append(column);
214
215 // Before invoking layoutColumns() the column must be set visible temporary.
216 // To prevent a flickering the initial geometry is set to a hidden position.
217 column->setGeometry(QRect(-1, -1, 1, 1));
218 column->show();
219 layoutColumns();
220 updateScrollBar();
221 }
222 }
223
224 // set the last column as active column without modifying the controller
225 // and hence the history
226 activeColumn()->setActive(false);
227 m_index = columnIndex;
228 activeColumn()->setActive(true);
229 assureVisibleActiveColumn();
230 }
231
232 void DolphinColumnView::selectAll()
233 {
234 activeColumn()->selectAll();
235 }
236
237 bool DolphinColumnView::isIndexHidden(const QModelIndex& index) const
238 {
239 Q_UNUSED(index);
240 return false;//activeColumn()->isIndexHidden(index);
241 }
242
243 QModelIndex DolphinColumnView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
244 {
245 // Parts of this code have been taken from QColumnView::moveCursor().
246 // Copyright (C) 1992-2007 Trolltech ASA.
247
248 Q_UNUSED(modifiers);
249 if (model() == 0) {
250 return QModelIndex();
251 }
252
253 const QModelIndex current = currentIndex();
254 if (isRightToLeft()) {
255 if (cursorAction == MoveLeft) {
256 cursorAction = MoveRight;
257 } else if (cursorAction == MoveRight) {
258 cursorAction = MoveLeft;
259 }
260 }
261
262 switch (cursorAction) {
263 case MoveLeft:
264 if (m_index > 0) {
265 setActiveColumnIndex(m_index - 1);
266 }
267 break;
268
269 case MoveRight:
270 if (m_index < m_columns.count() - 1) {
271 setActiveColumnIndex(m_index + 1);
272 }
273 break;
274
275 default:
276 break;
277 }
278
279 return QModelIndex();
280 }
281
282 void DolphinColumnView::setSelection(const QRect& rect, QItemSelectionModel::SelectionFlags flags)
283 {
284 Q_UNUSED(rect);
285 Q_UNUSED(flags);
286 //activeColumn()->setSelection(rect, flags);
287 }
288
289 QRegion DolphinColumnView::visualRegionForSelection(const QItemSelection& selection) const
290 {
291 Q_UNUSED(selection);
292 return QRegion(); //activeColumn()->visualRegionForSelection(selection);
293 }
294
295 int DolphinColumnView::horizontalOffset() const
296 {
297 return -m_contentX;
298 }
299
300 int DolphinColumnView::verticalOffset() const
301 {
302 return 0;
303 }
304
305 void DolphinColumnView::mousePressEvent(QMouseEvent* event)
306 {
307 m_controller->requestActivation();
308 QAbstractItemView::mousePressEvent(event);
309 }
310
311 void DolphinColumnView::resizeEvent(QResizeEvent* event)
312 {
313 QAbstractItemView::resizeEvent(event);
314 layoutColumns();
315 updateScrollBar();
316 }
317
318 void DolphinColumnView::zoomIn()
319 {
320 if (isZoomInPossible()) {
321 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
322 switch (settings->iconSize()) {
323 case KIconLoader::SizeSmall: settings->setIconSize(KIconLoader::SizeMedium); break;
324 case KIconLoader::SizeMedium: settings->setIconSize(KIconLoader::SizeLarge); break;
325 default: Q_ASSERT(false); break;
326 }
327 updateDecorationSize();
328 }
329 }
330
331 void DolphinColumnView::zoomOut()
332 {
333 if (isZoomOutPossible()) {
334 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
335 switch (settings->iconSize()) {
336 case KIconLoader::SizeLarge: settings->setIconSize(KIconLoader::SizeMedium); break;
337 case KIconLoader::SizeMedium: settings->setIconSize(KIconLoader::SizeSmall); break;
338 default: Q_ASSERT(false); break;
339 }
340 updateDecorationSize();
341 }
342 }
343
344 void DolphinColumnView::moveContentHorizontally(int x)
345 {
346 m_contentX = isRightToLeft() ? +x : -x;
347 layoutColumns();
348 }
349
350 void DolphinColumnView::updateDecorationSize()
351 {
352 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
353 const int iconSize = settings->iconSize();
354
355 foreach (QObject* object, viewport()->children()) {
356 if (object->inherits("QListView")) {
357 DolphinColumnWidget* widget = static_cast<DolphinColumnWidget*>(object);
358 widget->setDecorationSize(QSize(iconSize, iconSize));
359 }
360 }
361
362 m_controller->setZoomInPossible(isZoomInPossible());
363 m_controller->setZoomOutPossible(isZoomOutPossible());
364
365 doItemsLayout();
366 }
367
368 void DolphinColumnView::updateColumnsBackground(bool active)
369 {
370 if (active == m_active) {
371 return;
372 }
373
374 m_active = active;
375
376 // dim the background of the viewport
377 QColor color = KColorScheme(QPalette::Active, KColorScheme::View).background().color();
378 color.setAlpha(150);
379
380 QPalette palette;
381 palette.setColor(viewport()->backgroundRole(), color);
382 viewport()->setPalette(palette);
383
384 foreach (DolphinColumnWidget* column, m_columns) {
385 column->updateBackground();
386 }
387 }
388
389 void DolphinColumnView::slotShowHiddenFilesChanged(bool show)
390 {
391 foreach (DolphinColumnWidget* column, m_columns) {
392 column->setShowHiddenFiles(show);
393 }
394 }
395
396 void DolphinColumnView::slotShowPreviewChanged(bool show)
397 {
398 foreach (DolphinColumnWidget* column, m_columns) {
399 column->setShowPreview(show);
400 }
401 }
402
403 bool DolphinColumnView::isZoomInPossible() const
404 {
405 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
406 return settings->iconSize() < KIconLoader::SizeLarge;
407 }
408
409 bool DolphinColumnView::isZoomOutPossible() const
410 {
411 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
412 return settings->iconSize() > KIconLoader::SizeSmall;
413 }
414
415 void DolphinColumnView::setActiveColumnIndex(int index)
416 {
417 if (m_index == index) {
418 return;
419 }
420
421 const bool hasActiveColumn = (m_index >= 0);
422 if (hasActiveColumn) {
423 m_columns[m_index]->setActive(false);
424 }
425
426 m_index = index;
427 m_columns[m_index]->setActive(true);
428
429 m_controller->setUrl(m_columns[m_index]->url());
430
431 assureVisibleActiveColumn();
432 }
433
434 void DolphinColumnView::layoutColumns()
435 {
436 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
437 const int columnWidth = settings->columnWidth();
438 if (isRightToLeft()) {
439 int x = viewport()->width() - columnWidth + m_contentX;
440 foreach (DolphinColumnWidget* column, m_columns) {
441 column->setGeometry(QRect(x, 0, columnWidth, viewport()->height()));
442 x -= columnWidth;
443 }
444 } else {
445 int x = m_contentX;
446 foreach (DolphinColumnWidget* column, m_columns) {
447 column->setGeometry(QRect(x, 0, columnWidth, viewport()->height()));
448 x += columnWidth;
449 }
450 }
451 }
452
453 void DolphinColumnView::updateScrollBar()
454 {
455 int contentWidth = 0;
456 foreach (DolphinColumnWidget* column, m_columns) {
457 contentWidth += column->width();
458 }
459
460 horizontalScrollBar()->setPageStep(contentWidth);
461 horizontalScrollBar()->setRange(0, contentWidth - viewport()->width());
462 }
463
464 void DolphinColumnView::assureVisibleActiveColumn()
465 {
466 const int viewportWidth = viewport()->width();
467 const int x = activeColumn()->x();
468 const int width = activeColumn()->width();
469 if (x + width > viewportWidth) {
470 const int newContentX = m_contentX - x - width + viewportWidth;
471 if (isRightToLeft()) {
472 m_animation->setFrameRange(m_contentX, newContentX);
473 } else {
474 m_animation->setFrameRange(-m_contentX, -newContentX);
475 }
476 m_animation->start();
477 } else if (x < 0) {
478 const int newContentX = m_contentX - x;
479 if (isRightToLeft()) {
480 m_animation->setFrameRange(m_contentX, newContentX);
481 } else {
482 m_animation->setFrameRange(-m_contentX, -newContentX);
483 }
484 m_animation->start();
485 }
486 }
487
488 void DolphinColumnView::requestActivation(DolphinColumnWidget* column)
489 {
490 if (column->isActive()) {
491 assureVisibleActiveColumn();
492 } else {
493 int index = 0;
494 foreach (DolphinColumnWidget* currColumn, m_columns) {
495 if (currColumn == column) {
496 setActiveColumnIndex(index);
497 return;
498 }
499 ++index;
500 }
501 }
502 }
503
504 void DolphinColumnView::removeAllColumns()
505 {
506 QList<DolphinColumnWidget*>::iterator start = m_columns.begin() + 1;
507 QList<DolphinColumnWidget*>::iterator end = m_columns.end();
508 for (QList<DolphinColumnWidget*>::iterator it = start; it != end; ++it) {
509 (*it)->deleteLater();
510 }
511 m_columns.erase(start, end);
512 m_index = 0;
513 m_columns[0]->setActive(true);
514 assureVisibleActiveColumn();
515 }
516
517 #include "dolphincolumnview.moc"