]> cloud.milkyroute.net Git - dolphin.git/blob - src/dolphincolumnview.cpp
Revert my last commit, it's not quite working
[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 assureVisibleActiveColumn();
345 }
346
347 void DolphinColumnView::zoomIn()
348 {
349 if (isZoomInPossible()) {
350 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
351 switch (settings->iconSize()) {
352 case KIconLoader::SizeSmall: settings->setIconSize(KIconLoader::SizeMedium); break;
353 case KIconLoader::SizeMedium: settings->setIconSize(KIconLoader::SizeLarge); break;
354 default: Q_ASSERT(false); break;
355 }
356 updateDecorationSize();
357 }
358 }
359
360 void DolphinColumnView::zoomOut()
361 {
362 if (isZoomOutPossible()) {
363 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
364 switch (settings->iconSize()) {
365 case KIconLoader::SizeLarge: settings->setIconSize(KIconLoader::SizeMedium); break;
366 case KIconLoader::SizeMedium: settings->setIconSize(KIconLoader::SizeSmall); break;
367 default: Q_ASSERT(false); break;
368 }
369 updateDecorationSize();
370 }
371 }
372
373 void DolphinColumnView::moveContentHorizontally(int x)
374 {
375 m_contentX = isRightToLeft() ? +x : -x;
376 layoutColumns();
377 }
378
379 void DolphinColumnView::updateDecorationSize()
380 {
381 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
382 const int iconSize = settings->iconSize();
383
384 foreach (QObject* object, viewport()->children()) {
385 if (object->inherits("QListView")) {
386 DolphinColumnWidget* widget = static_cast<DolphinColumnWidget*>(object);
387 widget->setDecorationSize(QSize(iconSize, iconSize));
388 }
389 }
390
391 m_controller->setZoomInPossible(isZoomInPossible());
392 m_controller->setZoomOutPossible(isZoomOutPossible());
393
394 doItemsLayout();
395 }
396
397 void DolphinColumnView::updateColumnsBackground(bool active)
398 {
399 if (active == m_active) {
400 return;
401 }
402
403 m_active = active;
404
405 // dim the background of the viewport
406 QPalette palette;
407 palette.setColor(viewport()->backgroundRole(), QColor(0, 0, 0, 0));
408 viewport()->setPalette(palette);
409
410 foreach (DolphinColumnWidget* column, m_columns) {
411 column->updateBackground();
412 }
413 }
414
415 void DolphinColumnView::slotShowHiddenFilesChanged()
416 {
417 const bool show = m_controller->dolphinView()->showHiddenFiles();
418 foreach (DolphinColumnWidget* column, m_columns) {
419 column->setShowHiddenFiles(show);
420 }
421 }
422
423 void DolphinColumnView::slotShowPreviewChanged()
424 {
425 const bool show = m_controller->dolphinView()->showPreview();
426 foreach (DolphinColumnWidget* column, m_columns) {
427 column->setShowPreview(show);
428 }
429 }
430
431 bool DolphinColumnView::isZoomInPossible() const
432 {
433 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
434 return settings->iconSize() < KIconLoader::SizeLarge;
435 }
436
437 bool DolphinColumnView::isZoomOutPossible() const
438 {
439 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
440 return settings->iconSize() > KIconLoader::SizeSmall;
441 }
442
443 void DolphinColumnView::setActiveColumnIndex(int index)
444 {
445 if (m_index == index) {
446 return;
447 }
448
449 const bool hasActiveColumn = (m_index >= 0);
450 if (hasActiveColumn) {
451 m_columns[m_index]->setActive(false);
452 }
453
454 m_index = index;
455 m_columns[m_index]->setActive(true);
456
457 assureVisibleActiveColumn();
458 }
459
460 void DolphinColumnView::layoutColumns()
461 {
462 const int gap = 4;
463
464 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
465 const int columnWidth = settings->columnWidth();
466
467 QRect emptyViewportRect;
468 if (isRightToLeft()) {
469 int x = viewport()->width() - columnWidth + m_contentX;
470 foreach (DolphinColumnWidget* column, m_columns) {
471 column->setGeometry(QRect(x, 0, columnWidth - gap, viewport()->height()));
472 x -= columnWidth;
473 }
474 emptyViewportRect = QRect(0, 0, x + columnWidth - gap, viewport()->height());
475 } else {
476 int x = m_contentX;
477 foreach (DolphinColumnWidget* column, m_columns) {
478 column->setGeometry(QRect(x, 0, columnWidth - gap, viewport()->height()));
479 x += columnWidth;
480 }
481 emptyViewportRect = QRect(x, 0, viewport()->width() - x - gap, viewport()->height());
482 }
483
484 if (emptyViewportRect.isValid()) {
485 m_emptyViewport->show();
486 m_emptyViewport->setGeometry(emptyViewportRect);
487 } else {
488 m_emptyViewport->hide();
489 }
490 }
491
492 void DolphinColumnView::updateScrollBar()
493 {
494 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
495 const int contentWidth = m_columns.count() * settings->columnWidth();
496
497 horizontalScrollBar()->setPageStep(contentWidth);
498 horizontalScrollBar()->setRange(0, contentWidth - viewport()->width());
499 }
500
501 void DolphinColumnView::assureVisibleActiveColumn()
502 {
503 const int viewportWidth = viewport()->width();
504 const int x = activeColumn()->x();
505
506 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
507 const int width = settings->columnWidth();
508
509 if (x + width > viewportWidth) {
510 const int newContentX = m_contentX - x - width + viewportWidth;
511 if (isRightToLeft()) {
512 m_animation->setFrameRange(m_contentX, newContentX);
513 } else {
514 m_animation->setFrameRange(-m_contentX, -newContentX);
515 }
516 m_animation->start();
517 } else if (x < 0) {
518 const int newContentX = m_contentX - x;
519 if (isRightToLeft()) {
520 m_animation->setFrameRange(m_contentX, newContentX);
521 } else {
522 m_animation->setFrameRange(-m_contentX, -newContentX);
523 }
524 m_animation->start();
525 }
526 }
527
528 void DolphinColumnView::requestActivation(DolphinColumnWidget* column)
529 {
530 if (column->isActive()) {
531 assureVisibleActiveColumn();
532 } else {
533 int index = 0;
534 foreach (DolphinColumnWidget* currColumn, m_columns) {
535 if (currColumn == column) {
536 setActiveColumnIndex(index);
537 return;
538 }
539 ++index;
540 }
541 }
542 }
543
544 void DolphinColumnView::removeAllColumns()
545 {
546 QList<DolphinColumnWidget*>::iterator start = m_columns.begin() + 1;
547 QList<DolphinColumnWidget*>::iterator end = m_columns.end();
548 for (QList<DolphinColumnWidget*>::iterator it = start; it != end; ++it) {
549 (*it)->deleteLater();
550 }
551 m_columns.erase(start, end);
552 m_index = 0;
553 m_columns[0]->setActive(true);
554 assureVisibleActiveColumn();
555 }
556
557 #include "dolphincolumnview.moc"