]> cloud.milkyroute.net Git - dolphin.git/blob - src/dolphincolumnviewcontainer.cpp
restore zooming functionality
[dolphin.git] / src / dolphincolumnviewcontainer.cpp
1 /***************************************************************************
2 * Copyright (C) 2007-2009 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 "dolphincolumnviewcontainer.h"
21
22 #include "dolphincolumnview.h"
23 #include "dolphincontroller.h"
24 #include "dolphinsortfilterproxymodel.h"
25 #include "settings/dolphinsettings.h"
26
27 #include "dolphin_columnmodesettings.h"
28
29 #include <kfilepreviewgenerator.h>
30
31 #include <QPoint>
32 #include <QScrollBar>
33 #include <QTimeLine>
34
35 DolphinColumnViewContainer::DolphinColumnViewContainer(QWidget* parent, DolphinController* controller) :
36 QScrollArea(parent),
37 m_controller(controller),
38 m_active(false),
39 m_index(-1),
40 m_contentX(0),
41 m_columns(),
42 m_emptyViewport(0),
43 m_animation(0),
44 m_nameFilter()
45 {
46 Q_ASSERT(controller != 0);
47
48 setAcceptDrops(true);
49 setFocusPolicy(Qt::NoFocus);
50 setFrameShape(QFrame::NoFrame);
51 setLayoutDirection(Qt::LeftToRight);
52
53 connect(this, SIGNAL(viewportEntered()),
54 controller, SLOT(emitViewportEntered()));
55 connect(controller, SIGNAL(activationChanged(bool)),
56 this, SLOT(updateColumnsBackground(bool)));
57
58 connect(horizontalScrollBar(), SIGNAL(valueChanged(int)),
59 this, SLOT(moveContentHorizontally(int)));
60
61 m_animation = new QTimeLine(500, this);
62 connect(m_animation, SIGNAL(frameChanged(int)), horizontalScrollBar(), SLOT(setValue(int)));
63
64 DolphinColumnView* column = new DolphinColumnView(viewport(), this, m_controller->url());
65 m_columns.append(column);
66 setActiveColumnIndex(0);
67
68 m_emptyViewport = new QFrame(viewport());
69 m_emptyViewport->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
70
71 updateColumnsBackground(true);
72 }
73
74 DolphinColumnViewContainer::~DolphinColumnViewContainer()
75 {
76 }
77
78 void DolphinColumnViewContainer::setNameFilter(const QString& nameFilter)
79 {
80 if (nameFilter != m_nameFilter) {
81 m_nameFilter = nameFilter;
82 foreach (DolphinColumnView* column, m_columns) {
83 DolphinSortFilterProxyModel* proxyModel = static_cast<DolphinSortFilterProxyModel*>(column->model());
84 proxyModel->setFilterRegExp(nameFilter);
85 }
86 }
87 }
88
89 QString DolphinColumnViewContainer::nameFilter() const
90 {
91 return m_nameFilter;
92 }
93
94 KUrl DolphinColumnViewContainer::rootUrl() const
95 {
96 return m_columns[0]->url();
97 }
98
99 QAbstractItemView* DolphinColumnViewContainer::activeColumn() const
100 {
101 return m_columns[m_index];
102 }
103
104 bool DolphinColumnViewContainer::showColumn(const KUrl& url)
105 {
106 if (!rootUrl().isParentOf(url)) {
107 removeAllColumns();
108 m_columns[0]->setUrl(url);
109 return false;
110 }
111
112 int columnIndex = 0;
113 foreach (DolphinColumnView* column, m_columns) {
114 if (column->url() == url) {
115 // the column represents already the requested URL, hence activate it
116 requestActivation(column);
117 layoutColumns();
118 return false;
119 } else if (!column->url().isParentOf(url)) {
120 // the column is no parent of the requested URL, hence
121 // just delete all remaining columns
122 if (columnIndex > 0) {
123 QList<DolphinColumnView*>::iterator start = m_columns.begin() + columnIndex;
124 QList<DolphinColumnView*>::iterator end = m_columns.end();
125 for (QList<DolphinColumnView*>::iterator it = start; it != end; ++it) {
126 deleteColumn(*it);
127 }
128 m_columns.erase(start, end);
129
130 const int maxIndex = m_columns.count() - 1;
131 Q_ASSERT(maxIndex >= 0);
132 if (m_index > maxIndex) {
133 m_index = maxIndex;
134 }
135 break;
136 }
137 }
138 ++columnIndex;
139 }
140
141 // Create missing columns. Assuming that the path is "/home/peter/Temp/" and
142 // the target path is "/home/peter/Temp/a/b/c/", then the columns "a", "b" and
143 // "c" will be created.
144 const int lastIndex = m_columns.count() - 1;
145 Q_ASSERT(lastIndex >= 0);
146
147 const KUrl& activeUrl = m_columns[lastIndex]->url();
148 Q_ASSERT(activeUrl.isParentOf(url));
149 Q_ASSERT(activeUrl != url);
150
151 QString path = activeUrl.url(KUrl::AddTrailingSlash);
152 const QString targetPath = url.url(KUrl::AddTrailingSlash);
153
154 columnIndex = lastIndex;
155 int slashIndex = path.count('/');
156 bool hasSubPath = (slashIndex >= 0);
157 while (hasSubPath) {
158 const QString subPath = targetPath.section('/', slashIndex, slashIndex);
159 if (subPath.isEmpty()) {
160 hasSubPath = false;
161 } else {
162 path += subPath + '/';
163 ++slashIndex;
164
165 const KUrl childUrl = KUrl(path);
166 m_columns[columnIndex]->setChildUrl(childUrl);
167 columnIndex++;
168
169 DolphinColumnView* column = new DolphinColumnView(viewport(), this, childUrl);
170 if (!m_nameFilter.isEmpty()) {
171 DolphinSortFilterProxyModel* proxyModel = static_cast<DolphinSortFilterProxyModel*>(column->model());
172 proxyModel->setFilterRegExp(m_nameFilter);
173 }
174 column->setActive(false);
175
176 m_columns.append(column);
177
178 // Before invoking layoutColumns() the column must be set visible temporary.
179 // To prevent a flickering the initial geometry is set to a hidden position.
180 column->setGeometry(QRect(-1, -1, 1, 1));
181 column->show();
182 layoutColumns();
183 updateScrollBar();
184 }
185 }
186
187 // set the last column as active column without modifying the controller
188 // and hence the history
189 m_columns[m_index]->setActive(false);
190 m_index = columnIndex;
191 m_columns[m_index]->setActive(true);
192 assureVisibleActiveColumn();
193
194 return true;
195 }
196
197 void DolphinColumnViewContainer::mousePressEvent(QMouseEvent* event)
198 {
199 m_controller->requestActivation();
200 QScrollArea::mousePressEvent(event);
201 }
202
203 void DolphinColumnViewContainer::resizeEvent(QResizeEvent* event)
204 {
205 QScrollArea::resizeEvent(event);
206 layoutColumns();
207 updateScrollBar();
208 assureVisibleActiveColumn();
209 }
210
211 void DolphinColumnViewContainer::wheelEvent(QWheelEvent* event)
212 {
213 // let Ctrl+wheel events propagate to the DolphinView for icon zooming
214 if ((event->modifiers() & Qt::ControlModifier) == Qt::ControlModifier) {
215 event->ignore();
216 } else {
217 QScrollArea::wheelEvent(event);
218 }
219 }
220
221 void DolphinColumnViewContainer::moveContentHorizontally(int x)
222 {
223 m_contentX = isRightToLeft() ? +x : -x;
224 layoutColumns();
225 }
226
227 void DolphinColumnViewContainer::updateColumnsBackground(bool active)
228 {
229 if (active == m_active) {
230 return;
231 }
232
233 m_active = active;
234
235 // dim the background of the viewport
236 const QPalette::ColorRole role = viewport()->backgroundRole();
237 QColor background = viewport()->palette().color(role);
238 background.setAlpha(0); // make background transparent
239
240 QPalette palette = viewport()->palette();
241 palette.setColor(role, background);
242 viewport()->setPalette(palette);
243
244 foreach (DolphinColumnView* column, m_columns) {
245 column->updateBackground();
246 }
247 }
248
249 void DolphinColumnViewContainer::setActiveColumnIndex(int index)
250 {
251 if (m_index == index) {
252 return;
253 }
254
255 const bool hasActiveColumn = (m_index >= 0);
256 if (hasActiveColumn) {
257 m_columns[m_index]->setActive(false);
258 }
259
260 m_index = index;
261 m_columns[m_index]->setActive(true);
262
263 assureVisibleActiveColumn();
264 }
265
266 void DolphinColumnViewContainer::layoutColumns()
267 {
268 const int gap = 4;
269
270 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
271 const int columnWidth = settings->columnWidth();
272
273 QRect emptyViewportRect;
274 if (isRightToLeft()) {
275 int x = viewport()->width() - columnWidth + m_contentX;
276 foreach (DolphinColumnView* column, m_columns) {
277 column->setGeometry(QRect(x, 0, columnWidth - gap, viewport()->height()));
278 x -= columnWidth;
279 }
280 emptyViewportRect = QRect(0, 0, x + columnWidth - gap, viewport()->height());
281 } else {
282 int x = m_contentX;
283 foreach (DolphinColumnView* column, m_columns) {
284 column->setGeometry(QRect(x, 0, columnWidth - gap, viewport()->height()));
285 x += columnWidth;
286 }
287 emptyViewportRect = QRect(x, 0, viewport()->width() - x - gap, viewport()->height());
288 }
289
290 if (emptyViewportRect.isValid()) {
291 m_emptyViewport->show();
292 m_emptyViewport->setGeometry(emptyViewportRect);
293 } else {
294 m_emptyViewport->hide();
295 }
296 }
297
298 void DolphinColumnViewContainer::updateScrollBar()
299 {
300 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
301 const int contentWidth = m_columns.count() * settings->columnWidth();
302
303 horizontalScrollBar()->setPageStep(contentWidth);
304 horizontalScrollBar()->setRange(0, contentWidth - viewport()->width());
305 }
306
307 void DolphinColumnViewContainer::assureVisibleActiveColumn()
308 {
309 const int viewportWidth = viewport()->width();
310 const int x = activeColumn()->x();
311
312 ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
313 const int width = settings->columnWidth();
314
315 if (x + width > viewportWidth) {
316 const int newContentX = m_contentX - x - width + viewportWidth;
317 if (isRightToLeft()) {
318 m_animation->setFrameRange(m_contentX, newContentX);
319 } else {
320 m_animation->setFrameRange(-m_contentX, -newContentX);
321 }
322 if (m_animation->state() != QTimeLine::Running) {
323 m_animation->start();
324 }
325 } else if (x < 0) {
326 const int newContentX = m_contentX - x;
327 if (isRightToLeft()) {
328 m_animation->setFrameRange(m_contentX, newContentX);
329 } else {
330 m_animation->setFrameRange(-m_contentX, -newContentX);
331 }
332 if (m_animation->state() != QTimeLine::Running) {
333 m_animation->start();
334 }
335 }
336 }
337
338 void DolphinColumnViewContainer::requestActivation(DolphinColumnView* column)
339 {
340 m_controller->setItemView(column);
341 if (column->isActive()) {
342 assureVisibleActiveColumn();
343 } else {
344 int index = 0;
345 foreach (DolphinColumnView* currColumn, m_columns) {
346 if (currColumn == column) {
347 setActiveColumnIndex(index);
348 return;
349 }
350 ++index;
351 }
352 }
353 }
354
355 void DolphinColumnViewContainer::removeAllColumns()
356 {
357 QList<DolphinColumnView*>::iterator start = m_columns.begin() + 1;
358 QList<DolphinColumnView*>::iterator end = m_columns.end();
359 for (QList<DolphinColumnView*>::iterator it = start; it != end; ++it) {
360 deleteColumn(*it);
361 }
362 m_columns.erase(start, end);
363 m_index = 0;
364 m_columns[0]->setActive(true);
365 assureVisibleActiveColumn();
366 }
367
368 QPoint DolphinColumnViewContainer::columnPosition(DolphinColumnView* column, const QPoint& point) const
369 {
370 const QPoint topLeft = column->frameGeometry().topLeft();
371 return QPoint(point.x() - topLeft.x(), point.y() - topLeft.y());
372 }
373
374 void DolphinColumnViewContainer::deleteColumn(DolphinColumnView* column)
375 {
376 if (column != 0) {
377 if (m_controller->itemView() == column) {
378 m_controller->setItemView(0);
379 }
380 // deleteWhenNotDragSource(column) does not necessarily delete column,
381 // and we want its preview generator destroyed immediately.
382 column->m_previewGenerator->deleteLater();
383 column->m_previewGenerator = 0;
384 column->hide();
385 // Prevent automatic destruction of column when this DolphinColumnViewContainer
386 // is destroyed.
387 column->setParent(0);
388 column->disconnect();
389 emit requestColumnDeletion(column);
390 }
391 }
392
393 #include "dolphincolumnviewcontainer.moc"