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