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