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