]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/dolphincolumnview.cpp
Let the user choose if folders are always shown first in the views of
[dolphin.git] / src / dolphincolumnview.cpp
index 979ff7649fe746b665387d6cbc53c795350117d0..f34be92e9b58e96809a1c3ef9a0eaeb66108cea5 100644 (file)
 
 #include "dolphincolumnview.h"
 
-#include "dolphinmodel.h"
+#include "dolphincolumnwidget.h"
 #include "dolphincontroller.h"
-#include "dolphinsettings.h"
+#include "settings/dolphinsettings.h"
+#include "zoomlevelinfo.h"
 
 #include "dolphin_columnmodesettings.h"
 
-#include <kcolorutils.h>
-#include <kcolorscheme.h>
-#include <kdirlister.h>
+#include <kfilepreviewgenerator.h>
 
-#include <QAbstractProxyModel>
-#include <QApplication>
 #include <QPoint>
 #include <QScrollBar>
 #include <QTimeLine>
 
-/**
- * Represents one column inside the DolphinColumnView and has been
- * extended to respect view options and hovering information.
- */
-class ColumnWidget : public QListView
-{
-public:
-    ColumnWidget(QWidget* parent,
-                 DolphinColumnView* columnView,
-                 const KUrl& url);
-    virtual ~ColumnWidget();
-
-    /** Sets the size of the icons. */
-    void setDecorationSize(const QSize& size);
-
-    /**
-     * An active column is defined as column, which shows the same URL
-     * as indicated by the URL navigator. The active column is usually
-     * drawn in a lighter color. All operations are applied to this column.
-     */
-    void setActive(bool active);
-    bool isActive() const;
-
-    /**
-     * Sets the directory URL of the child column that is shown next to
-     * this column. This property is only used for a visual indication
-     * of the shown directory, it does not trigger a loading of the model.
-     */
-    void setChildUrl(const KUrl& url);
-    const KUrl& childUrl() const;
-
-    /** Sets the directory URL that is shown inside the column widget. */
-    void setUrl(const KUrl& url);
-
-    /** Returns the directory URL that is shown inside the column widget. */
-    inline const KUrl& url() const;
-
-protected:
-    virtual QStyleOptionViewItem viewOptions() const;
-    virtual void dragEnterEvent(QDragEnterEvent* event);
-    virtual void dragLeaveEvent(QDragLeaveEvent* event);
-    virtual void dragMoveEvent(QDragMoveEvent* event);
-    virtual void dropEvent(QDropEvent* event);
-    virtual void paintEvent(QPaintEvent* event);
-    virtual void mousePressEvent(QMouseEvent* event);
-    virtual void keyPressEvent(QKeyEvent* event);
-    virtual void contextMenuEvent(QContextMenuEvent* event);
-    virtual void selectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
-
-private:
-    /** Used by ColumnWidget::setActive(). */
-    void activate();
-
-    /** Used by ColumnWidget::setActive(). */
-    void deactivate();
-
-private:
-    bool m_active;
-    DolphinColumnView* m_view;
-    KUrl m_url;      // URL of the directory that is shown
-    KUrl m_childUrl; // URL of the next column that is shown
-    QStyleOptionViewItem m_viewOptions;
-
-    bool m_dragging;   // TODO: remove this property when the issue #160611 is solved in Qt 4.4
-    QRect m_dropRect;  // TODO: remove this property when the issue #160611 is solved in Qt 4.4
-};
-
-ColumnWidget::ColumnWidget(QWidget* parent,
-                           DolphinColumnView* columnView,
-                           const KUrl& url) :
-    QListView(parent),
-    m_active(true),
-    m_view(columnView),
-    m_url(url),
-    m_childUrl(),
-    m_dragging(false),
-    m_dropRect()
-{
-    setMouseTracking(true);
-    viewport()->setAttribute(Qt::WA_Hover);
-    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
-    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
-    setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
-    setSelectionBehavior(SelectItems);
-    setSelectionMode(QAbstractItemView::ExtendedSelection);
-    setDragDropMode(QAbstractItemView::DragDrop);
-    setDropIndicatorShown(false);
-    setFocusPolicy(Qt::NoFocus);
-
-    // apply the column mode settings to the widget
-    const ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
-    Q_ASSERT(settings != 0);
-
-    m_viewOptions = QListView::viewOptions();
-
-    QFont font(settings->fontFamily(), settings->fontSize());
-    font.setItalic(settings->italicFont());
-    font.setBold(settings->boldFont());
-    m_viewOptions.font = font;
-
-    const int iconSize = settings->iconSize();
-    m_viewOptions.decorationSize = QSize(iconSize, iconSize);
-
-    KFileItemDelegate* delegate = new KFileItemDelegate(this);
-    setItemDelegate(delegate);
-
-    activate();
-
-    connect(this, SIGNAL(entered(const QModelIndex&)),
-            m_view->m_controller, SLOT(emitItemEntered(const QModelIndex&)));
-    connect(this, SIGNAL(viewportEntered()),
-            m_view->m_controller, SLOT(emitViewportEntered()));
-}
-
-ColumnWidget::~ColumnWidget()
-{
-}
-
-void ColumnWidget::setDecorationSize(const QSize& size)
-{
-    m_viewOptions.decorationSize = size;
-    doItemsLayout();
-}
-
-void ColumnWidget::setActive(bool active)
-{
-    if (m_active == active) {
-        return;
-    }
-
-    m_active = active;
-
-    if (active) {
-        activate();
-    } else {
-        deactivate();
-    }
-}
-
-inline bool ColumnWidget::isActive() const
-{
-    return m_active;
-}
-
-inline void ColumnWidget::setChildUrl(const KUrl& url)
-{
-    m_childUrl = url;
-}
-
-inline const KUrl& ColumnWidget::childUrl() const
-{
-    return m_childUrl;
-}
-
-inline void ColumnWidget::setUrl(const KUrl& url)
-{
-    m_url = url;
-}
-
-const KUrl& ColumnWidget::url() const
-{
-    return m_url;
-}
-
-QStyleOptionViewItem ColumnWidget::viewOptions() const
-{
-    return m_viewOptions;
-}
-
-void ColumnWidget::dragEnterEvent(QDragEnterEvent* event)
-{
-    if (event->mimeData()->hasUrls()) {
-        event->acceptProposedAction();
-    }
-
-    m_dragging = true;
-}
-
-void ColumnWidget::dragLeaveEvent(QDragLeaveEvent* event)
-{
-    QListView::dragLeaveEvent(event);
-
-    // TODO: remove this code when the issue #160611 is solved in Qt 4.4
-    m_dragging = false;
-    setDirtyRegion(m_dropRect);
-}
-
-void ColumnWidget::dragMoveEvent(QDragMoveEvent* event)
-{
-    QListView::dragMoveEvent(event);
-
-    // TODO: remove this code when the issue #160611 is solved in Qt 4.4
-    const QModelIndex index = indexAt(event->pos());
-    setDirtyRegion(m_dropRect);
-    m_dropRect = visualRect(index);
-    setDirtyRegion(m_dropRect);
-}
-
-void ColumnWidget::dropEvent(QDropEvent* event)
-{
-    const KUrl::List urls = KUrl::List::fromMimeData(event->mimeData());
-    if (!urls.isEmpty()) {
-        event->acceptProposedAction();
-        m_view->m_controller->indicateDroppedUrls(urls,
-                                                  url(),
-                                                  indexAt(event->pos()),
-                                                  event->source());
-    }
-    QListView::dropEvent(event);
-    m_dragging = false;
-}
-
-void ColumnWidget::paintEvent(QPaintEvent* event)
-{
-    if (!m_childUrl.isEmpty()) {
-        // indicate the shown URL of the next column by highlighting the shown folder item
-        const QModelIndex dirIndex = m_view->m_dolphinModel->indexForUrl(m_childUrl);
-        const QModelIndex proxyIndex = m_view->m_proxyModel->mapFromSource(dirIndex);
-        if (proxyIndex.isValid() && !selectionModel()->isSelected(proxyIndex)) {
-            const QRect itemRect = visualRect(proxyIndex);
-            QPainter painter(viewport());
-            painter.save();
-
-            QColor color = KColorScheme(QPalette::Active, KColorScheme::View).foreground().color();
-            color.setAlpha(32);
-            painter.setPen(Qt::NoPen);
-            painter.setBrush(color);
-            painter.drawRect(itemRect);
-
-            painter.restore();
-        }
-    }
-
-    QListView::paintEvent(event);
-
-    // TODO: remove this code when the issue #160611 is solved in Qt 4.4
-    if (m_dragging) {
-        const QBrush& brush = m_viewOptions.palette.brush(QPalette::Normal, QPalette::Highlight);
-        DolphinController::drawHoverIndication(viewport(), m_dropRect, brush);
-    }
-}
-
-void ColumnWidget::mousePressEvent(QMouseEvent* event)
-{
-    if (!m_active) {
-        m_view->requestActivation(this);
-    }
-
-    QListView::mousePressEvent(event);
-}
-
-void ColumnWidget::keyPressEvent(QKeyEvent* event)
-{
-    QListView::keyPressEvent(event);
-
-    const QItemSelectionModel* selModel = selectionModel();
-    const QModelIndex currentIndex = selModel->currentIndex();
-    const bool triggerItem = currentIndex.isValid()
-                             && (event->key() == Qt::Key_Return)
-                             && (selModel->selectedIndexes().count() <= 1);
-    if (triggerItem) {
-        m_view->m_controller->triggerItem(currentIndex);
-    }
-}
-
-void ColumnWidget::contextMenuEvent(QContextMenuEvent* event)
-{
-    if (!m_active) {
-        m_view->requestActivation(this);
-    }
-
-    QListView::contextMenuEvent(event);
-
-    const QModelIndex index = indexAt(event->pos());
-    if (index.isValid() || m_active) {
-        // Only open a context menu above an item or if the mouse is above
-        // the active column.
-        const QPoint pos = m_view->viewport()->mapFromGlobal(event->globalPos());
-        m_view->m_controller->triggerContextMenuRequest(pos);
-    }
-}
-
-void ColumnWidget::selectionChanged(const QItemSelection& selected, const QItemSelection& deselected)
-{
-    QListView::selectionChanged(selected, deselected);
-
-    QItemSelectionModel* selModel = m_view->selectionModel();
-    selModel->select(selected, QItemSelectionModel::Select);
-    selModel->select(deselected, QItemSelectionModel::Deselect);
-}
-
-void ColumnWidget::activate()
-{
-    if (m_view->hasFocus()) {
-        setFocus(Qt::OtherFocusReason);
-    }
-    m_view->setFocusProxy(this);
-
-    // TODO: Connecting to the signal 'activated()' is not possible, as kstyle
-    // does not forward the single vs. doubleclick to it yet (KDE 4.1?). Hence it is
-    // necessary connecting the signal 'singleClick()' or 'doubleClick'.
-    if (KGlobalSettings::singleClick()) {
-        connect(this, SIGNAL(clicked(const QModelIndex&)),
-                m_view->m_controller, SLOT(triggerItem(const QModelIndex&)));
-    } else {
-        connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
-                m_view->m_controller, SLOT(triggerItem(const QModelIndex&)));
-    }
-
-    const QColor bgColor = KColorScheme(QPalette::Active, KColorScheme::View).background().color();
-    QPalette palette = viewport()->palette();
-    palette.setColor(viewport()->backgroundRole(), bgColor);
-    viewport()->setPalette(palette);
-
-    if (!m_childUrl.isEmpty()) {
-        // assure that the current index is set on the index that represents
-        // the child URL
-        const QModelIndex dirIndex = m_view->m_dolphinModel->indexForUrl(m_childUrl);
-        const QModelIndex proxyIndex = m_view->m_proxyModel->mapFromSource(dirIndex);
-        selectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::Current);
-    }
-
-    update();
-}
-
-void ColumnWidget::deactivate()
-{
-    // TODO: Connecting to the signal 'activated()' is not possible, as kstyle
-    // does not forward the single vs. doubleclick to it yet (KDE 4.1?). Hence it is
-    // necessary connecting the signal 'singleClick()' or 'doubleClick'.
-    if (KGlobalSettings::singleClick()) {
-        disconnect(this, SIGNAL(clicked(const QModelIndex&)),
-                   m_view->m_controller, SLOT(triggerItem(const QModelIndex&)));
-    } else {
-        disconnect(this, SIGNAL(doubleClicked(const QModelIndex&)),
-                   m_view->m_controller, SLOT(triggerItem(const QModelIndex&)));
-    }
-
-    const QPalette palette = m_view->viewport()->palette();
-    viewport()->setPalette(palette);
-
-    selectionModel()->clear();
-    update();
-}
-
-// ---
-
 DolphinColumnView::DolphinColumnView(QWidget* parent, DolphinController* controller) :
     QAbstractItemView(parent),
     m_controller(controller),
-    m_restoreActiveColumnFocus(false),
+    m_active(false),
     m_index(-1),
     m_contentX(0),
     m_columns(),
+    m_emptyViewport(0),
     m_animation(0),
-    m_dolphinModel(0),
-    m_proxyModel(0)
+    m_nameFilter()
 {
     Q_ASSERT(controller != 0);
 
@@ -399,38 +49,44 @@ DolphinColumnView::DolphinColumnView(QWidget* parent, DolphinController* control
     setDragDropMode(QAbstractItemView::DragDrop);
     setDropIndicatorShown(false);
     setSelectionMode(ExtendedSelection);
+    setFocusPolicy(Qt::NoFocus);
+    setFrameShape(QFrame::NoFrame);
+    setLayoutDirection(Qt::LeftToRight);
 
-    connect(this, SIGNAL(entered(const QModelIndex&)),
-            controller, SLOT(emitItemEntered(const QModelIndex&)));
     connect(this, SIGNAL(viewportEntered()),
             controller, SLOT(emitViewportEntered()));
-    connect(controller, SIGNAL(zoomIn()),
-            this, SLOT(zoomIn()));
-    connect(controller, SIGNAL(zoomOut()),
-            this, SLOT(zoomOut()));
-    connect(controller, SIGNAL(urlChanged(const KUrl&)),
-            this, SLOT(showColumn(const KUrl&)));
+    connect(controller, SIGNAL(zoomLevelChanged(int)),
+            this, SLOT(setZoomLevel(int)));
+    connect(controller, SIGNAL(activationChanged(bool)),
+            this, SLOT(updateColumnsBackground(bool)));
+
+    const DolphinView* view = controller->dolphinView();
+    connect(view, SIGNAL(sortingChanged(DolphinView::Sorting)),
+            this, SLOT(slotSortingChanged(DolphinView::Sorting)));
+    connect(view, SIGNAL(sortOrderChanged(Qt::SortOrder)),
+            this, SLOT(slotSortOrderChanged(Qt::SortOrder)));
+    connect(view, SIGNAL(sortFoldersFirstChanged(bool)),
+            this, SLOT(slotSortFoldersFirstChanged(bool)));
+    connect(view, SIGNAL(showHiddenFilesChanged()),
+            this, SLOT(slotShowHiddenFilesChanged()));
+    connect(view, SIGNAL(showPreviewChanged()),
+            this, SLOT(slotShowPreviewChanged()));
 
     connect(horizontalScrollBar(), SIGNAL(valueChanged(int)),
             this, SLOT(moveContentHorizontally(int)));
 
-    ColumnWidget* column = new ColumnWidget(viewport(), this, m_controller->url());
-    m_columns.append(column);
-    setActiveColumnIndex(0);
-
-    updateDecorationSize();
-
     m_animation = new QTimeLine(500, this);
     connect(m_animation, SIGNAL(frameChanged(int)), horizontalScrollBar(), SLOT(setValue(int)));
 
-    // dim the background of the viewport
-    QColor bgColor = KColorScheme(QPalette::Active, KColorScheme::View).background().color();
-    const QColor fgColor = KColorScheme(QPalette::Active, KColorScheme::View).foreground().color();
-    bgColor = KColorUtils::mix(bgColor, fgColor, 0.04);
+    DolphinColumnWidget* column = new DolphinColumnWidget(viewport(), this, m_controller->url());
+    m_columns.append(column);
+    setActiveColumnIndex(0);
 
-    QPalette palette = viewport()->palette();
-    palette.setColor(viewport()->backgroundRole(), bgColor);
-    viewport()->setPalette(palette);
+    m_emptyViewport = new QFrame(viewport());
+    m_emptyViewport->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
+
+    updateDecorationSize(view->showPreview());
+    updateColumnsBackground(true);
 }
 
 DolphinColumnView::~DolphinColumnView()
@@ -439,10 +95,8 @@ DolphinColumnView::~DolphinColumnView()
 
 QModelIndex DolphinColumnView::indexAt(const QPoint& point) const
 {
-    foreach (ColumnWidget* column, m_columns) {
-        const QPoint topLeft = column->frameGeometry().topLeft();
-        const QPoint adjustedPoint(point.x() - topLeft.x(), point.y() - topLeft.y());
-        const QModelIndex index = column->indexAt(adjustedPoint);
+    foreach (DolphinColumnWidget* column, m_columns) {
+        const QModelIndex index = column->indexAt(columnPosition(column, point));
         if (index.isValid()) {
             return index;
         }
@@ -451,6 +105,18 @@ QModelIndex DolphinColumnView::indexAt(const QPoint& point) const
     return QModelIndex();
 }
 
+KFileItem DolphinColumnView::itemAt(const QPoint& point) const
+{
+    foreach (DolphinColumnWidget* column, m_columns) {
+        KFileItem item = column->itemAt(columnPosition(column, point));
+        if (!item.isNull()) {
+            return item;
+        }
+    }
+
+    return KFileItem();
+}
+
 void DolphinColumnView::scrollTo(const QModelIndex& index, ScrollHint hint)
 {
     activeColumn()->scrollTo(index, hint);
@@ -461,90 +127,74 @@ QRect DolphinColumnView::visualRect(const QModelIndex& index) const
     return activeColumn()->visualRect(index);
 }
 
-void DolphinColumnView::setModel(QAbstractItemModel* model)
+void DolphinColumnView::invertSelection()
 {
-    if (m_dolphinModel != 0) {
-        m_dolphinModel->disconnect(this);
-    }
+    QItemSelectionModel* selectionModel = activeColumn()->selectionModel();
+    const QAbstractItemModel* itemModel = selectionModel->model();
 
-    m_proxyModel = static_cast<QAbstractProxyModel*>(model);
-    m_dolphinModel = static_cast<DolphinModel*>(m_proxyModel->sourceModel());
-    connect(m_dolphinModel, SIGNAL(expand(const QModelIndex&)),
-            this, SLOT(triggerReloadColumns(const QModelIndex&)));
+    const QModelIndex topLeft = itemModel->index(0, 0);
+    const QModelIndex bottomRight = itemModel->index(itemModel->rowCount() - 1,
+                                                     itemModel->columnCount() - 1);
 
-    activeColumn()->setModel(model);
-    QAbstractItemView::setModel(model);
+    const QItemSelection selection(topLeft, bottomRight);
+    selectionModel->select(selection, QItemSelectionModel::Toggle);
 }
 
 void DolphinColumnView::reload()
 {
-    // Due to the reloading of the model all columns will be reset to show
-    // the same content as the first column. As this is not wanted, all columns
-    // except of the first column are temporary hidden until the root index can
-    // be updated again.
-    m_restoreActiveColumnFocus = false;
-    QList<ColumnWidget*>::iterator start = m_columns.begin() + 1;
-    QList<ColumnWidget*>::iterator end = m_columns.end();
-    for (QList<ColumnWidget*>::iterator it = start; it != end; ++it) {
-        ColumnWidget* column = (*it);
-        if (column->isActive() && column->hasFocus()) {
-            // because of hiding the column, it will lose the focus
-            // -> remember that the focus should be restored after reloading
-            m_restoreActiveColumnFocus = true;
-        }
-        column->hide();
-   }
+    foreach (DolphinColumnWidget* column, m_columns) {
+        column->reload();
+    }
+}
 
-    // all columns are hidden, now reload the directory lister
-    KDirLister* dirLister = m_dolphinModel->dirLister();
-    connect(dirLister, SIGNAL(completed()),
-            this, SLOT(expandToActiveUrl()));
-    const KUrl rootUrl = m_columns[0]->url();
-    dirLister->openUrl(rootUrl, false, true);
+void DolphinColumnView::setRootUrl(const KUrl& url)
+{
+    removeAllColumns();
+    m_columns[0]->setUrl(url);
 }
 
-void DolphinColumnView::showColumn(const KUrl& url)
+void DolphinColumnView::setNameFilter(const QString& nameFilter)
 {
-    const KUrl& rootUrl = m_columns[0]->url();
-    if (!rootUrl.isParentOf(url)) {
-        // the URL is no child URL of the column view, hence clear all columns
-        // and reset the root column
-        QList<ColumnWidget*>::iterator start = m_columns.begin() + 1;
-        QList<ColumnWidget*>::iterator end = m_columns.end();
-        for (QList<ColumnWidget*>::iterator it = start; it != end; ++it) {
-            (*it)->deleteLater();
+    if (nameFilter != m_nameFilter) {
+        m_nameFilter = nameFilter;
+        foreach (DolphinColumnWidget* column, m_columns) {
+            column->setNameFilter(nameFilter);
         }
-        m_columns.erase(start, end);
-        m_index = 0;
-        m_columns[0]->setActive(true);
-        m_columns[0]->setUrl(url);
-        assureVisibleActiveColumn();
-        return;
     }
+}
+
+QString DolphinColumnView::nameFilter() const
+{
+    return m_nameFilter;
+}
+
+KUrl DolphinColumnView::rootUrl() const
+{
+    return m_columns[0]->url();
+}
 
-    KDirLister* dirLister = m_dolphinModel->dirLister();
-    const KUrl dirListerUrl = dirLister->url();
-    if (dirListerUrl != rootUrl) {
-        // It is possible that root URL of the directory lister is adjusted
-        // after creating the column widget (e. g. when restoring the history
-        // having a different root URL than the controller indicates).
-        m_columns[0]->setUrl(dirListerUrl);
+void DolphinColumnView::showColumn(const KUrl& url)
+{
+    if (!rootUrl().isParentOf(url)) {
+        setRootUrl(url);
+        return;
     }
 
     int columnIndex = 0;
-    foreach (ColumnWidget* column, m_columns) {
+    foreach (DolphinColumnWidget* column, m_columns) {
         if (column->url() == url) {
             // the column represents already the requested URL, hence activate it
             requestActivation(column);
+            layoutColumns();
             return;
         } else if (!column->url().isParentOf(url)) {
             // the column is no parent of the requested URL, hence
             // just delete all remaining columns
             if (columnIndex > 0) {
-                QList<ColumnWidget*>::iterator start = m_columns.begin() + columnIndex;
-                QList<ColumnWidget*>::iterator end = m_columns.end();
-                for (QList<ColumnWidget*>::iterator it = start; it != end; ++it) {
-                    (*it)->deleteLater();
+                QList<DolphinColumnWidget*>::iterator start = m_columns.begin() + columnIndex;
+                QList<DolphinColumnWidget*>::iterator end = m_columns.end();
+                for (QList<DolphinColumnWidget*>::iterator it = start; it != end; ++it) {
+                    deleteColumn(*it);
                 }
                 m_columns.erase(start, end);
 
@@ -584,17 +234,14 @@ void DolphinColumnView::showColumn(const KUrl& url)
             ++slashIndex;
 
             const KUrl childUrl = KUrl(path);
-            const QModelIndex dirIndex = m_dolphinModel->indexForUrl(KUrl(path));
-            const QModelIndex proxyIndex = m_proxyModel->mapFromSource(dirIndex);
-
             m_columns[columnIndex]->setChildUrl(childUrl);
             columnIndex++;
 
-            ColumnWidget* column = new ColumnWidget(viewport(), this, childUrl);
-            column->setVerticalScrollMode(ColumnWidget::ScrollPerPixel);
-            column->setHorizontalScrollMode(ColumnWidget::ScrollPerPixel);
-            column->setModel(model());
-            column->setRootIndex(proxyIndex);
+            DolphinColumnWidget* column = new DolphinColumnWidget(viewport(), this, childUrl);
+            const QString filter = nameFilter();
+            if (!filter.isEmpty()) {
+                column->setNameFilter(filter);
+            }
             column->setActive(false);
 
             m_columns.append(column);
@@ -605,10 +252,6 @@ void DolphinColumnView::showColumn(const KUrl& url)
             column->show();
             layoutColumns();
             updateScrollBar();
-
-            // the layout is finished, now let the column be invisible until it
-            // gets a valid root index due to expandToActiveUrl()
-            column->hide();
         }
     }
 
@@ -617,8 +260,27 @@ void DolphinColumnView::showColumn(const KUrl& url)
     activeColumn()->setActive(false);
     m_index = columnIndex;
     activeColumn()->setActive(true);
+    assureVisibleActiveColumn();
+}
+
+void DolphinColumnView::editItem(const KFileItem& item)
+{
+    activeColumn()->editItem(item);
+}
+
+KFileItemList DolphinColumnView::selectedItems() const
+{
+    return activeColumn()->selectedItems();
+}
 
-    expandToActiveUrl();
+QMimeData* DolphinColumnView::selectionMimeData() const
+{
+    return activeColumn()->selectionMimeData();
+}
+
+void DolphinColumnView::selectAll()
+{
+    activeColumn()->selectAll();
 }
 
 bool DolphinColumnView::isIndexHidden(const QModelIndex& index) const
@@ -650,12 +312,14 @@ QModelIndex DolphinColumnView::moveCursor(CursorAction cursorAction, Qt::Keyboar
     case MoveLeft:
         if (m_index > 0) {
             setActiveColumnIndex(m_index - 1);
+            m_controller->triggerUrlChangeRequest(activeColumn()->url());
         }
         break;
 
     case MoveRight:
         if (m_index < m_columns.count() - 1) {
             setActiveColumnIndex(m_index + 1);
+            m_controller->triggerUrlChangeRequest(m_columns[m_index]->url());
         }
         break;
 
@@ -670,13 +334,12 @@ void DolphinColumnView::setSelection(const QRect& rect, QItemSelectionModel::Sel
 {
     Q_UNUSED(rect);
     Q_UNUSED(flags);
-    //activeColumn()->setSelection(rect, flags);
 }
 
 QRegion DolphinColumnView::visualRegionForSelection(const QItemSelection& selection) const
 {
     Q_UNUSED(selection);
-    return QRegion(); //activeColumn()->visualRegionForSelection(selection);
+    return QRegion();
 }
 
 int DolphinColumnView::horizontalOffset() const
@@ -691,7 +354,7 @@ int DolphinColumnView::verticalOffset() const
 
 void DolphinColumnView::mousePressEvent(QMouseEvent* event)
 {
-    m_controller->triggerActivation();
+    m_controller->requestActivation();
     QAbstractItemView::mousePressEvent(event);
 }
 
@@ -700,119 +363,115 @@ void DolphinColumnView::resizeEvent(QResizeEvent* event)
     QAbstractItemView::resizeEvent(event);
     layoutColumns();
     updateScrollBar();
+    assureVisibleActiveColumn();
 }
 
-void DolphinColumnView::zoomIn()
+void DolphinColumnView::wheelEvent(QWheelEvent* event)
 {
-    if (isZoomInPossible()) {
-        ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
-        // TODO: get rid of K3Icon sizes
-        switch (settings->iconSize()) {
-        case K3Icon::SizeSmall:  settings->setIconSize(K3Icon::SizeMedium); break;
-        case K3Icon::SizeMedium: settings->setIconSize(K3Icon::SizeLarge); break;
-        default: Q_ASSERT(false); break;
-        }
-        updateDecorationSize();
+    // let Ctrl+wheel events propagate to the DolphinView for icon zooming
+    if ((event->modifiers() & Qt::ControlModifier) == Qt::ControlModifier) {
+        event->ignore();
+    } else {
+        QAbstractItemView::wheelEvent(event);
     }
 }
 
-void DolphinColumnView::zoomOut()
+void DolphinColumnView::setZoomLevel(int level)
 {
-    if (isZoomOutPossible()) {
-        ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
-        // TODO: get rid of K3Icon sizes
-        switch (settings->iconSize()) {
-        case K3Icon::SizeLarge:  settings->setIconSize(K3Icon::SizeMedium); break;
-        case K3Icon::SizeMedium: settings->setIconSize(K3Icon::SizeSmall); break;
-        default: Q_ASSERT(false); break;
-        }
-        updateDecorationSize();
+    const int size = ZoomLevelInfo::iconSizeForZoomLevel(level);
+    ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
+
+    const bool showPreview = m_controller->dolphinView()->showPreview();
+    if (showPreview) {
+        settings->setPreviewSize(size);
+    } else {
+        settings->setIconSize(size);
     }
+
+    updateDecorationSize(showPreview);
 }
 
 void DolphinColumnView::moveContentHorizontally(int x)
 {
-    m_contentX = -x;
+    m_contentX = isRightToLeft() ? +x : -x;
     layoutColumns();
 }
 
-void DolphinColumnView::updateDecorationSize()
+void DolphinColumnView::updateDecorationSize(bool showPreview)
 {
     ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
-    const int iconSize = settings->iconSize();
+    const int iconSize = showPreview ? settings->previewSize() : settings->iconSize();
+    const QSize size(iconSize, iconSize);
+    setIconSize(size);
 
     foreach (QObject* object, viewport()->children()) {
         if (object->inherits("QListView")) {
-            ColumnWidget* widget = static_cast<ColumnWidget*>(object);
-            widget->setDecorationSize(QSize(iconSize, iconSize));
+            DolphinColumnWidget* widget = static_cast<DolphinColumnWidget*>(object);
+            widget->setDecorationSize(size);
         }
     }
 
-    m_controller->setZoomInPossible(isZoomInPossible());
-    m_controller->setZoomOutPossible(isZoomOutPossible());
-
     doItemsLayout();
 }
 
-void DolphinColumnView::expandToActiveUrl()
+void DolphinColumnView::updateColumnsBackground(bool active)
 {
-    const int lastIndex = m_columns.count() - 1;
-    Q_ASSERT(lastIndex >= 0);
-    const KUrl& activeUrl = m_columns[lastIndex]->url();
-    const KUrl rootUrl = m_dolphinModel->dirLister()->url();
-    const bool expand = rootUrl.isParentOf(activeUrl)
-                        && !rootUrl.equals(activeUrl, KUrl::CompareWithoutTrailingSlash);
-    if (expand) {
-        m_dolphinModel->expandToUrl(activeUrl);
-        reloadColumns();
+    if (active == m_active) {
+        return;
+    }
+
+    m_active = active;
+
+    // dim the background of the viewport
+    const QPalette::ColorRole role = viewport()->backgroundRole();
+    QColor background = viewport()->palette().color(role);
+    background.setAlpha(0);  // make background transparent
+
+    QPalette palette = viewport()->palette();
+    palette.setColor(role, background);
+    viewport()->setPalette(palette);
+
+    foreach (DolphinColumnWidget* column, m_columns) {
+        column->updateBackground();
     }
 }
 
-void DolphinColumnView::triggerReloadColumns(const QModelIndex& index)
+void DolphinColumnView::slotSortingChanged(DolphinView::Sorting sorting)
 {
-    Q_UNUSED(index);
-    // the reloading of the columns may not be done in the context of this slot
-    QMetaObject::invokeMethod(this, "reloadColumns", Qt::QueuedConnection);
+    foreach (DolphinColumnWidget* column, m_columns) {
+        column->setSorting(sorting);
+    }
 }
 
-void DolphinColumnView::reloadColumns()
+void DolphinColumnView::slotSortOrderChanged(Qt::SortOrder order)
 {
-    const int end = m_columns.count() - 2; // next to last column
-    for (int i = 0; i <= end; ++i) {
-        ColumnWidget* nextColumn = m_columns[i + 1];
-
-        KDirLister* dirLister = m_dolphinModel->dirLister();
-        dirLister->updateDirectory(nextColumn->url());
+    foreach (DolphinColumnWidget* column, m_columns) {
+        column->setSortOrder(order);
+    }
+}
 
-        const QModelIndex rootIndex = nextColumn->rootIndex();
-        if (rootIndex.isValid()) {
-            nextColumn->show();
-        } else {
-            const QModelIndex dirIndex = m_dolphinModel->indexForUrl(m_columns[i]->childUrl());
-            const QModelIndex proxyIndex = m_proxyModel->mapFromSource(dirIndex);
-            if (proxyIndex.isValid()) {
-                nextColumn->setRootIndex(proxyIndex);
-                nextColumn->show();
-                if (nextColumn->isActive() && m_restoreActiveColumnFocus) {
-                    nextColumn->setFocus();
-                    m_restoreActiveColumnFocus = false;
-                }
-            }
-        }
+void DolphinColumnView::slotSortFoldersFirstChanged(bool foldersFirst)
+{
+    foreach (DolphinColumnWidget* column, m_columns) {
+        column->setSortFoldersFirst(foldersFirst);
     }
-    assureVisibleActiveColumn();
 }
 
-bool DolphinColumnView::isZoomInPossible() const
+void DolphinColumnView::slotShowHiddenFilesChanged()
 {
-    ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
-    return settings->iconSize() < K3Icon::SizeLarge;
+    const bool show = m_controller->dolphinView()->showHiddenFiles();
+    foreach (DolphinColumnWidget* column, m_columns) {
+        column->setShowHiddenFiles(show);
+    }
 }
 
-bool DolphinColumnView::isZoomOutPossible() const
+void DolphinColumnView::slotShowPreviewChanged()
 {
-    ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
-    return settings->iconSize() > K3Icon::SizeSmall;
+    const bool show = m_controller->dolphinView()->showPreview();
+    updateDecorationSize(show);
+    foreach (DolphinColumnWidget* column, m_columns) {
+        column->setShowPreview(show);
+    }
 }
 
 void DolphinColumnView::setActiveColumnIndex(int index)
@@ -829,26 +488,45 @@ void DolphinColumnView::setActiveColumnIndex(int index)
     m_index = index;
     m_columns[m_index]->setActive(true);
 
-    m_controller->setUrl(m_columns[m_index]->url());
+    assureVisibleActiveColumn();
 }
 
 void DolphinColumnView::layoutColumns()
 {
-    int x = m_contentX;
+    const int gap = 4;
+
     ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
     const int columnWidth = settings->columnWidth();
-    foreach (ColumnWidget* column, m_columns) {
-        column->setGeometry(QRect(x, 0, columnWidth, viewport()->height()));
-        x += columnWidth;
+
+    QRect emptyViewportRect;
+    if (isRightToLeft()) {
+        int x = viewport()->width() - columnWidth + m_contentX;
+        foreach (DolphinColumnWidget* column, m_columns) {
+            column->setGeometry(QRect(x, 0, columnWidth - gap, viewport()->height()));
+            x -= columnWidth;
+        }
+        emptyViewportRect = QRect(0, 0, x + columnWidth - gap, viewport()->height());
+    } else {
+        int x = m_contentX;
+        foreach (DolphinColumnWidget* column, m_columns) {
+            column->setGeometry(QRect(x, 0, columnWidth - gap, viewport()->height()));
+            x += columnWidth;
+        }
+        emptyViewportRect = QRect(x, 0, viewport()->width() - x - gap, viewport()->height());
+    }
+
+    if (emptyViewportRect.isValid()) {
+        m_emptyViewport->show();
+        m_emptyViewport->setGeometry(emptyViewportRect);
+    } else {
+        m_emptyViewport->hide();
     }
 }
 
 void DolphinColumnView::updateScrollBar()
 {
-    int contentWidth = 0;
-    foreach (ColumnWidget* column, m_columns) {
-        contentWidth += column->width();
-    }
+    ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
+    const int contentWidth = m_columns.count() * settings->columnWidth();
 
     horizontalScrollBar()->setPageStep(contentWidth);
     horizontalScrollBar()->setRange(0, contentWidth - viewport()->width());
@@ -858,31 +536,43 @@ void DolphinColumnView::assureVisibleActiveColumn()
 {
     const int viewportWidth = viewport()->width();
     const int x = activeColumn()->x();
-    const int width = activeColumn()->width();
+
+    ColumnModeSettings* settings = DolphinSettings::instance().columnModeSettings();
+    const int width = settings->columnWidth();
+
     if (x + width > viewportWidth) {
-        int newContentX = m_contentX - x - width + viewportWidth;
-        if (newContentX > 0) {
-            newContentX = 0;
+        const int newContentX = m_contentX - x - width + viewportWidth;
+        if (isRightToLeft()) {
+            m_animation->setFrameRange(m_contentX, newContentX);
+        } else {
+            m_animation->setFrameRange(-m_contentX, -newContentX);
+        }
+        if (m_animation->state() != QTimeLine::Running) {
+           m_animation->start();
         }
-        m_animation->setFrameRange(-m_contentX, -newContentX);
-        m_animation->start();
     } else if (x < 0) {
         const int newContentX = m_contentX - x;
-        m_animation->setFrameRange(-m_contentX, -newContentX);
-        m_animation->start();
+        if (isRightToLeft()) {
+            m_animation->setFrameRange(m_contentX, newContentX);
+        } else {
+            m_animation->setFrameRange(-m_contentX, -newContentX);
+        }
+        if (m_animation->state() != QTimeLine::Running) {
+           m_animation->start();
+        }
     }
 }
 
-void DolphinColumnView::requestActivation(ColumnWidget* column)
+void DolphinColumnView::requestActivation(DolphinColumnWidget* column)
 {
+    m_controller->setItemView(column);
     if (column->isActive()) {
         assureVisibleActiveColumn();
     } else {
         int index = 0;
-        foreach (ColumnWidget* currColumn, m_columns) {
+        foreach (DolphinColumnWidget* currColumn, m_columns) {
             if (currColumn == column) {
                 setActiveColumnIndex(index);
-                assureVisibleActiveColumn();
                 return;
             }
             ++index;
@@ -890,4 +580,42 @@ void DolphinColumnView::requestActivation(ColumnWidget* column)
     }
 }
 
+void DolphinColumnView::removeAllColumns()
+{
+    QList<DolphinColumnWidget*>::iterator start = m_columns.begin() + 1;
+    QList<DolphinColumnWidget*>::iterator end = m_columns.end();
+    for (QList<DolphinColumnWidget*>::iterator it = start; it != end; ++it) {
+        deleteColumn(*it);
+    }
+    m_columns.erase(start, end);
+    m_index = 0;
+    m_columns[0]->setActive(true);
+    assureVisibleActiveColumn();
+}
+
+QPoint DolphinColumnView::columnPosition(DolphinColumnWidget* column, const QPoint& point) const
+{
+    const QPoint topLeft = column->frameGeometry().topLeft();
+    return QPoint(point.x() - topLeft.x(), point.y() - topLeft.y());
+}
+
+void DolphinColumnView::deleteColumn(DolphinColumnWidget* column)
+{
+    if (column != 0) {
+        if (m_controller->itemView() == column) {
+            m_controller->setItemView(0);
+        }
+        // deleteWhenNotDragSource(column) does not necessarily delete column,
+        // and we want its preview generator destroyed immediately.
+        column->m_previewGenerator->deleteLater();
+        column->m_previewGenerator = 0;
+        column->hide();
+        // Prevent automatic destruction of column when this DolphinColumnView
+        // is destroyed.
+        column->setParent(0);
+        column->disconnect();
+        emit requestColumnDeletion(column);
+    }
+}
+
 #include "dolphincolumnview.moc"