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