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