1 /***************************************************************************
2 * Copyright (C) 2007-2009 by Peter Penz <peter.penz19@gmail.com> *
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. *
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. *
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 ***************************************************************************/
20 #include "dolphincolumnviewcontainer.h"
22 #include "dolphin_columnmodesettings.h"
24 #include "dolphincolumnview.h"
25 #include "dolphinviewcontroller.h"
26 #include "dolphinsortfilterproxymodel.h"
27 #include "draganddrophelper.h"
28 #include "settings/dolphinsettings.h"
29 #include "viewmodecontroller.h"
36 DolphinColumnViewContainer::DolphinColumnViewContainer(QWidget
* parent
,
37 DolphinViewController
* dolphinViewController
,
38 const ViewModeController
* viewModeController
) :
40 m_dolphinViewController(dolphinViewController
),
41 m_viewModeController(viewModeController
),
50 m_assureVisibleActiveColumnTimer(0)
52 Q_ASSERT(dolphinViewController
);
53 Q_ASSERT(viewModeController
);
56 setFocusPolicy(Qt::NoFocus
);
57 setFrameShape(QFrame::NoFrame
);
58 setLayoutDirection(Qt::LeftToRight
);
60 connect(viewModeController
, SIGNAL(activationChanged(bool)),
61 this, SLOT(updateColumnsBackground(bool)));
63 connect(horizontalScrollBar(), SIGNAL(valueChanged(int)),
64 this, SLOT(moveContentHorizontally(int)));
66 m_animation
= new QTimeLine(500, this);
67 connect(m_animation
, SIGNAL(frameChanged(int)), horizontalScrollBar(), SLOT(setValue(int)));
69 m_activeUrlTimer
= new QTimer(this);
70 m_activeUrlTimer
->setSingleShot(true);
71 m_activeUrlTimer
->setInterval(200);
72 connect(m_activeUrlTimer
, SIGNAL(timeout()),
73 this, SLOT(updateActiveUrl()));
75 // Assuring that the active column gets fully visible is done with a small delay. This
76 // prevents that for temporary activations an animation gets started (e. g. when clicking
77 // on any folder of the parent column, the child column gets activated).
78 m_assureVisibleActiveColumnTimer
= new QTimer(this);
79 m_assureVisibleActiveColumnTimer
->setSingleShot(true);
80 m_assureVisibleActiveColumnTimer
->setInterval(200);
81 connect(m_assureVisibleActiveColumnTimer
, SIGNAL(timeout()),
82 this, SLOT(slotAssureVisibleActiveColumn()));
84 DolphinColumnView
* column
= new DolphinColumnView(viewport(), this, viewModeController
->url());
85 m_columns
.append(column
);
86 requestActivation(column
);
88 m_emptyViewport
= new QFrame(viewport());
89 m_emptyViewport
->setFrameStyle(QFrame::StyledPanel
| QFrame::Sunken
);
91 updateColumnsBackground(true);
94 DolphinColumnViewContainer::~DolphinColumnViewContainer()
100 KUrl
DolphinColumnViewContainer::rootUrl() const
102 return m_columns
[0]->url();
105 QAbstractItemView
* DolphinColumnViewContainer::activeColumn() const
107 return m_columns
[m_index
];
110 void DolphinColumnViewContainer::showColumn(const KUrl
& url
)
112 if (!rootUrl().isParentOf(url
)) {
114 m_columns
[0]->setUrl(url
);
119 foreach (DolphinColumnView
* column
, m_columns
) {
120 if (column
->url().equals(url
, KUrl::CompareWithoutTrailingSlash
)) {
121 // the column represents already the requested URL, hence activate it
122 requestActivation(column
);
125 } else if (!column
->url().isParentOf(url
)) {
126 // the column is no parent of the requested URL, hence
127 // just delete all remaining columns
128 if (columnIndex
> 0) {
129 QList
<DolphinColumnView
*>::iterator start
= m_columns
.begin() + columnIndex
;
130 QList
<DolphinColumnView
*>::iterator end
= m_columns
.end();
131 for (QList
<DolphinColumnView
*>::iterator it
= start
; it
!= end
; ++it
) {
134 m_columns
.erase(start
, end
);
136 const int maxIndex
= m_columns
.count() - 1;
137 Q_ASSERT(maxIndex
>= 0);
138 if (m_index
> maxIndex
) {
147 // Create missing columns. Assuming that the path is "/home/peter/Temp/" and
148 // the target path is "/home/peter/Temp/a/b/c/", then the columns "a", "b" and
149 // "c" will be created.
150 const int lastIndex
= m_columns
.count() - 1;
151 Q_ASSERT(lastIndex
>= 0);
153 const KUrl
& activeUrl
= m_columns
[lastIndex
]->url();
154 Q_ASSERT(activeUrl
.isParentOf(url
));
155 Q_ASSERT(activeUrl
!= url
);
157 QString path
= activeUrl
.url(KUrl::AddTrailingSlash
);
158 const QString targetPath
= url
.url(KUrl::AddTrailingSlash
);
160 columnIndex
= lastIndex
;
161 int slashIndex
= path
.count('/');
162 bool hasSubPath
= (slashIndex
>= 0);
164 const QString subPath
= targetPath
.section('/', slashIndex
, slashIndex
);
165 if (subPath
.isEmpty()) {
168 path
+= subPath
+ '/';
171 const KUrl childUrl
= KUrl(path
);
172 m_columns
[columnIndex
]->setChildUrl(childUrl
);
175 DolphinColumnView
* column
= new DolphinColumnView(viewport(), this, childUrl
);
176 m_columns
.append(column
);
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));
186 requestActivation(m_columns
[columnIndex
]);
189 void DolphinColumnViewContainer::mousePressEvent(QMouseEvent
* event
)
191 m_dolphinViewController
->requestActivation();
192 QScrollArea::mousePressEvent(event
);
195 void DolphinColumnViewContainer::keyPressEvent(QKeyEvent
* event
)
197 if (event
->key() == Qt::Key_Left
) {
199 requestActivation(m_columns
[m_index
- 1]);
202 QScrollArea::keyPressEvent(event
);
206 void DolphinColumnViewContainer::resizeEvent(QResizeEvent
* event
)
208 QScrollArea::resizeEvent(event
);
210 assureVisibleActiveColumn();
213 void DolphinColumnViewContainer::wheelEvent(QWheelEvent
* event
)
215 // let Ctrl+wheel events propagate to the DolphinView for icon zooming
216 if ((event
->modifiers() & Qt::ControlModifier
) == Qt::ControlModifier
) {
219 QScrollArea::wheelEvent(event
);
223 void DolphinColumnViewContainer::moveContentHorizontally(int x
)
225 m_contentX
= isRightToLeft() ? +x
: -x
;
229 void DolphinColumnViewContainer::updateColumnsBackground(bool active
)
231 if (active
== m_active
) {
237 // dim the background of the viewport
238 const QPalette::ColorRole role
= viewport()->backgroundRole();
239 QColor background
= viewport()->palette().color(role
);
240 background
.setAlpha(0); // make background transparent
242 QPalette palette
= viewport()->palette();
243 palette
.setColor(role
, background
);
244 viewport()->setPalette(palette
);
246 foreach (DolphinColumnView
* column
, m_columns
) {
247 column
->updateBackground();
251 void DolphinColumnViewContainer::updateActiveUrl()
253 const KUrl activeUrl
= m_columns
[m_index
]->url();
254 m_dolphinViewController
->requestUrlChange(activeUrl
);
257 void DolphinColumnViewContainer::slotAssureVisibleActiveColumn()
259 const int viewportWidth
= viewport()->width();
260 const int x
= activeColumn()->x();
262 // When a column that is partly visible gets activated,
263 // it is useful to also assure that the neighbor column is partly visible.
264 // This allows the user to scroll to the first/last column without using the
265 // scrollbar and drag & drop operations to invisible columns.
266 const int neighborColumnGap
= 3 * style()->pixelMetric(QStyle::PM_ScrollBarExtent
, 0, verticalScrollBar());
268 const int width
= activeColumn()->maximumWidth();
269 if (x
+ width
> viewportWidth
) {
270 const int newContentX
= m_contentX
- x
- width
+ viewportWidth
;
271 if (isRightToLeft()) {
272 m_animation
->setFrameRange(m_contentX
, newContentX
+ neighborColumnGap
);
274 m_animation
->setFrameRange(-m_contentX
, -newContentX
+ neighborColumnGap
);
276 if (m_animation
->state() != QTimeLine::Running
) {
277 m_animation
->start();
280 const int newContentX
= m_contentX
- x
;
281 if (isRightToLeft()) {
282 m_animation
->setFrameRange(m_contentX
, newContentX
- neighborColumnGap
);
284 m_animation
->setFrameRange(-m_contentX
, -newContentX
- neighborColumnGap
);
286 if (m_animation
->state() != QTimeLine::Running
) {
287 m_animation
->start();
292 void DolphinColumnViewContainer::assureVisibleActiveColumn()
294 m_assureVisibleActiveColumnTimer
->start();
297 void DolphinColumnViewContainer::layoutColumns()
299 // Layout the position of the columns corresponding to their maximum width
300 QRect emptyViewportRect
;
301 if (isRightToLeft()) {
302 int columnWidth
= m_columns
[0]->maximumWidth();
303 int x
= viewport()->width() - columnWidth
+ m_contentX
;
304 foreach (DolphinColumnView
* column
, m_columns
) {
305 columnWidth
= column
->maximumWidth();
306 column
->setGeometry(QRect(x
, 0, columnWidth
, viewport()->height()));
309 emptyViewportRect
= QRect(0, 0, x
+ columnWidth
, viewport()->height());
312 foreach (DolphinColumnView
* column
, m_columns
) {
313 const int columnWidth
= column
->maximumWidth();
314 column
->setGeometry(QRect(x
, 0, columnWidth
, viewport()->height()));
317 emptyViewportRect
= QRect(x
, 0, viewport()->width() - x
, viewport()->height());
320 // Show an empty viewport if the columns don't cover the whole viewport
321 if (emptyViewportRect
.isValid()) {
322 m_emptyViewport
->show();
323 m_emptyViewport
->setGeometry(emptyViewportRect
);
325 m_emptyViewport
->hide();
328 // Update the horizontal position indicator
329 int contentWidth
= 0;
330 foreach (DolphinColumnView
* column
, m_columns
) {
331 contentWidth
+= column
->maximumWidth();
334 const int scrollBarMax
= contentWidth
- viewport()->width();
335 const bool updateScrollBar
= (horizontalScrollBar()->pageStep() != contentWidth
)
336 || (horizontalScrollBar()->maximum() != scrollBarMax
);
337 if (updateScrollBar
) {
338 horizontalScrollBar()->setPageStep(contentWidth
);
339 horizontalScrollBar()->setRange(0, scrollBarMax
);
343 void DolphinColumnViewContainer::requestActivation(DolphinColumnView
* column
)
345 if (m_dolphinViewController
->itemView() != column
) {
346 m_dolphinViewController
->setItemView(column
);
348 if (focusProxy() != column
) {
349 setFocusProxy(column
);
352 if (!column
->isActive()) {
353 // Deactivate the currently active column
355 m_columns
[m_index
]->setActive(false);
358 // Get the index of the column that should get activated
360 foreach (DolphinColumnView
* currColumn
, m_columns
) {
361 if (currColumn
== column
) {
367 Q_ASSERT(index
!= m_index
);
368 Q_ASSERT(index
< m_columns
.count());
370 // Activate the requested column
372 m_columns
[m_index
]->setActive(true);
374 m_activeUrlTimer
->start(); // calls slot updateActiveUrl()
377 assureVisibleActiveColumn();
380 void DolphinColumnViewContainer::removeAllColumns()
382 QList
<DolphinColumnView
*>::iterator start
= m_columns
.begin() + 1;
383 QList
<DolphinColumnView
*>::iterator end
= m_columns
.end();
384 for (QList
<DolphinColumnView
*>::iterator it
= start
; it
!= end
; ++it
) {
387 m_columns
.erase(start
, end
);
389 m_columns
[0]->setActive(true);
390 assureVisibleActiveColumn();
393 void DolphinColumnViewContainer::deleteColumn(DolphinColumnView
* column
)
399 if (m_dolphinViewController
->itemView() == column
) {
400 m_dolphinViewController
->setItemView(0);
402 // deleteWhenNotDragSource(column) does not necessarily delete column,
403 // and we want its preview generator destroyed immediately.
405 // Prevent automatic destruction of column when this DolphinColumnViewContainer
407 column
->setParent(0);
408 column
->disconnect();
410 if (DragAndDropHelper::instance().isDragSource(column
)) {
411 // The column is a drag source (the feature "Open folders
412 // during drag operations" is used). Deleting the view
413 // during an ongoing drag operation is not allowed, so
414 // this will postponed.
416 // the old stored view is obviously not the drag source anymore
417 m_dragSource
->deleteLater();
420 m_dragSource
= column
;
427 #include "dolphincolumnviewcontainer.moc"