X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fuisupport%2Fbufferview.cpp;h=b5f5a573365559011f5ae2d1e0b270a7919129dd;hp=c06e7d2093b84c3585916746bb66c79a5beb26c1;hb=a4251618e99c35f727c526f8480055d5a9c5e41f;hpb=0abe45a62eb5d9c8e1d8c0e783d77e07e705235b diff --git a/src/uisupport/bufferview.cpp b/src/uisupport/bufferview.cpp index c06e7d20..b5f5a573 100644 --- a/src/uisupport/bufferview.cpp +++ b/src/uisupport/bufferview.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-08 by the Quassel Project * + * Copyright (C) 2005-2010 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -35,46 +35,11 @@ #include "buffersettings.h" #include "buffersyncer.h" #include "client.h" -#include "iconloader.h" +#include "contextmenuactionprovider.h" +#include "graphicalui.h" #include "network.h" #include "networkmodel.h" -#include "networkmodelactionprovider.h" -#include "quasselui.h" -#include "uisettings.h" - -bool TristateDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { - if(event->type() != QEvent::MouseButtonRelease) - return QStyledItemDelegate::editorEvent(event, model, option, index); - - if(!(model->flags(index) & Qt::ItemIsUserCheckable)) - return QStyledItemDelegate::editorEvent(event, model, option, index); - - QVariant value = index.data(Qt::CheckStateRole); - if(!value.isValid()) - return QStyledItemDelegate::editorEvent(event, model, option, index); - - QStyleOptionViewItemV4 viewOpt(option); - initStyleOption(&viewOpt, index); - - QRect checkRect = viewOpt.widget->style()->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &viewOpt, viewOpt.widget); - QMouseEvent *me = static_cast(event); - - if(me->button() != Qt::LeftButton || !checkRect.contains(me->pos())) - return QStyledItemDelegate::editorEvent(event, model, option, index); - - Qt::CheckState state = static_cast(value.toInt()); - if(state == Qt::Unchecked) - state = Qt::PartiallyChecked; - else if(state == Qt::PartiallyChecked) - state = Qt::Checked; - else - state = Qt::Unchecked; - model->setData(index, state, Qt::CheckStateRole); - return true; -} - - - +#include "contextmenuactionprovider.h" /***************************************** * The TreeView showing the Buffers @@ -84,13 +49,13 @@ bool TristateDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, con BufferView::BufferView(QWidget *parent) : QTreeView(parent) { - connect(this, SIGNAL(collapsed(const QModelIndex &)), SLOT(on_collapse(const QModelIndex &))); - connect(this, SIGNAL(expanded(const QModelIndex &)), SLOT(on_expand(const QModelIndex &))); + connect(this, SIGNAL(collapsed(const QModelIndex &)), SLOT(storeExpandedState(const QModelIndex &))); + connect(this, SIGNAL(expanded(const QModelIndex &)), SLOT(storeExpandedState(const QModelIndex &))); setSelectionMode(QAbstractItemView::ExtendedSelection); QAbstractItemDelegate *oldDelegate = itemDelegate(); - TristateDelegate *tristateDelegate = new TristateDelegate(this); + BufferViewDelegate *tristateDelegate = new BufferViewDelegate(this); setItemDelegate(tristateDelegate); delete oldDelegate; } @@ -100,9 +65,17 @@ void BufferView::init() { hideColumn(1); hideColumn(2); setIndentation(10); + expandAll(); - setAnimated(true); + header()->hide(); // nobody seems to use this anyway + + // breaks with Qt 4.8 + if(QString("4.8.0") > qVersion()) // FIXME breaks with Qt versions >= 4.10! + setAnimated(true); + + // FIXME This is to workaround bug #663 + setUniformRowHeights(true); #ifndef QT_NO_DRAGANDDROP setDragEnabled(true); @@ -115,9 +88,11 @@ void BufferView::init() { // activated() fails on X11 and Qtopia at least #if defined Q_WS_QWS || defined Q_WS_X11 + disconnect(this, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(joinChannel(QModelIndex))); connect(this, SIGNAL(doubleClicked(QModelIndex)), SLOT(joinChannel(QModelIndex))); #else // afaik this is better on Mac and Windows + disconnect(this, SIGNAL(activated(QModelIndex)), this, SLOT(joinChannel(QModelIndex))); connect(this, SIGNAL(activated(QModelIndex)), SLOT(joinChannel(QModelIndex))); #endif } @@ -149,6 +124,7 @@ void BufferView::setModel(QAbstractItemModel *model) { header()->addAction(showSection); } + connect(model, SIGNAL(layoutChanged()), this, SLOT(on_layoutChanged())); } void BufferView::setFilteredModel(QAbstractItemModel *model_, BufferViewConfig *config) { @@ -273,8 +249,8 @@ void BufferView::dropEvent(QDropEvent *event) { return QTreeView::dropEvent(event); int res = QMessageBox::question(0, tr("Merge buffers permanently?"), - tr("Do you want to merge the buffer \"%1\" permanently into buffer \"%2\"?\n This cannot be reversed!").arg(Client::networkModel()->bufferName(bufferId2)).arg(Client::networkModel()->bufferName(bufferId1)), - QMessageBox::Yes|QMessageBox::No, QMessageBox::No); + tr("Do you want to merge the buffer \"%1\" permanently into buffer \"%2\"?\n This cannot be reversed!").arg(Client::networkModel()->bufferName(bufferId2)).arg(Client::networkModel()->bufferName(bufferId1)), + QMessageBox::Yes|QMessageBox::No, QMessageBox::No); if(res == QMessageBox::Yes) { Client::mergeBuffersPermanently(bufferId1, bufferId2); } @@ -295,7 +271,9 @@ void BufferView::removeSelectedBuffers(bool permanently) { continue; removedRows << bufferId; + } + foreach(BufferId bufferId, removedRows) { if(permanently) config()->requestRemoveBufferPermanently(bufferId); else @@ -303,17 +281,21 @@ void BufferView::removeSelectedBuffers(bool permanently) { } } -void BufferView::rowsInserted(const QModelIndex & parent, int start, int end) { +void BufferView::rowsInserted(const QModelIndex &parent, int start, int end) { QTreeView::rowsInserted(parent, start, end); // ensure that newly inserted network nodes are expanded per default if(parent.data(NetworkModel::ItemTypeRole) != NetworkModel::NetworkItemType) return; - if(model()->rowCount(parent) == 1 && parent.data(NetworkModel::ItemActiveRole) == true) { - // without updating the parent the expand will have no effect... Qt Bug? - update(parent); - expand(parent); + setExpandedState(parent); +} + +void BufferView::on_layoutChanged() { + int numNets = model()->rowCount(QModelIndex()); + for(int row = 0; row < numNets; row++) { + QModelIndex networkIdx = model()->index(row, 0, QModelIndex()); + setExpandedState(networkIdx); } } @@ -332,38 +314,49 @@ void BufferView::on_configChanged() { if(!networkId.isValid()) continue; - update(networkIdx); - - bool expandNetwork = false; - if(_expandedState.contains(networkId)) - expandNetwork = _expandedState[networkId]; - else - expandNetwork = model()->data(networkIdx, NetworkModel::ItemActiveRole).toBool(); - - if(expandNetwork) - expand(networkIdx); - else - collapse(networkIdx); + setExpandedState(networkIdx); } if(config()) { // update selection to current one Client::bufferModel()->synchronizeView(this); } - - return; } -void BufferView::on_collapse(const QModelIndex &index) { - storeExpandedState(index.data(NetworkModel::NetworkIdRole).value(), false); -} +void BufferView::storeExpandedState(const QModelIndex &networkIdx) { + NetworkId networkId = model()->data(networkIdx, NetworkModel::NetworkIdRole).value(); -void BufferView::on_expand(const QModelIndex &index) { - storeExpandedState(index.data(NetworkModel::NetworkIdRole).value(), true); + int oldState = 0; + if(isExpanded(networkIdx)) + oldState |= WasExpanded; + if(model()->data(networkIdx, NetworkModel::ItemActiveRole).toBool()) + oldState |= WasActive; + + _expandedState[networkId] = oldState; } -void BufferView::storeExpandedState(NetworkId networkId, bool expanded) { - _expandedState[networkId] = expanded; +void BufferView::setExpandedState(const QModelIndex &networkIdx) { + if(model()->data(networkIdx, NetworkModel::ItemTypeRole) != NetworkModel::NetworkItemType) + return; + + if(model()->rowCount(networkIdx) == 0) + return; + + NetworkId networkId = model()->data(networkIdx, NetworkModel::NetworkIdRole).value(); + + bool networkActive = model()->data(networkIdx, NetworkModel::ItemActiveRole).toBool(); + bool expandNetwork = networkActive; + if(_expandedState.contains(networkId)) { + int oldState = _expandedState[networkId]; + if((bool)(oldState & WasActive) == networkActive) + expandNetwork = (bool)(oldState & WasExpanded); + } + + if(expandNetwork != isExpanded(networkIdx)) { + update(networkIdx); + setExpanded(networkIdx, expandNetwork); + } + storeExpandedState(networkIdx); // this call is needed to keep track of the isActive state } void BufferView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { @@ -376,15 +369,7 @@ void BufferView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bott for(int i = topLeft.row(); i <= bottomRight.row(); i++) { QModelIndex networkIdx = topLeft.sibling(i, 0); - if(model()->rowCount(networkIdx) == 0) - continue; - - bool isActive = networkIdx.data(NetworkModel::ItemActiveRole).toBool(); -#ifdef SPUTDEV - if(isExpanded(networkIdx) != isActive) setExpanded(networkIdx, true); -#else - if(isExpanded(networkIdx) != isActive) setExpanded(networkIdx, isActive); -#endif + setExpandedState(networkIdx); } } @@ -416,7 +401,7 @@ void BufferView::addActionsToMenu(QMenu *contextMenu, const QModelIndex &index) indexList.removeAll(index); indexList.prepend(index); - Client::mainUi()->actionProvider()->addActions(contextMenu, indexList, this, "menuActionTriggered", (bool)config()); + GraphicalUi::contextMenuActionProvider()->addActions(contextMenu, indexList, this, "menuActionTriggered", (bool)config()); } void BufferView::addFilterActions(QMenu *contextMenu, const QModelIndex &index) { @@ -426,19 +411,19 @@ void BufferView::addFilterActions(QMenu *contextMenu, const QModelIndex &index) if(!filterActions.isEmpty()) { contextMenu->addSeparator(); foreach(QAction *action, filterActions) { - contextMenu->addAction(action); + contextMenu->addAction(action); } } } } void BufferView::menuActionTriggered(QAction *result) { - NetworkModelActionProvider::ActionType type = (NetworkModelActionProvider::ActionType)result->data().toInt(); + ContextMenuActionProvider::ActionType type = (ContextMenuActionProvider::ActionType)result->data().toInt(); switch(type) { - case NetworkModelActionProvider::HideBufferTemporarily: + case ContextMenuActionProvider::HideBufferTemporarily: removeSelectedBuffers(); break; - case NetworkModelActionProvider::HideBufferPermanently: + case ContextMenuActionProvider::HideBufferPermanently: removeSelectedBuffers(true); break; default: @@ -446,31 +431,58 @@ void BufferView::menuActionTriggered(QAction *result) { } } -void BufferView::wheelEvent(QWheelEvent* event) { - if(UiSettings().value("MouseWheelChangesBuffers", QVariant(true)).toBool() == (bool)(event->modifiers() & Qt::AltModifier)) - return QTreeView::wheelEvent(event); +void BufferView::nextBuffer() { + changeBuffer(Forward); +} - int rowDelta = ( event->delta() > 0 ) ? -1 : 1; +void BufferView::previousBuffer() { + changeBuffer(Backward); +} + +void BufferView::changeBuffer(Direction direction) { QModelIndex currentIndex = selectionModel()->currentIndex(); QModelIndex resultingIndex; - if( model()->hasIndex( currentIndex.row() + rowDelta, currentIndex.column(), currentIndex.parent() ) ) - { - resultingIndex = currentIndex.sibling( currentIndex.row() + rowDelta, currentIndex.column() ); + + if(currentIndex.parent().isValid()) { + //If we are a child node just switch among siblings unless it's the first/last child + resultingIndex = currentIndex.sibling(currentIndex.row() + direction, 0); + + if(!resultingIndex.isValid()) { + QModelIndex parent = currentIndex.parent(); + if(direction == Backward) + resultingIndex = parent; + else + resultingIndex = parent.sibling(parent.row() + direction, 0); } - else //if we scroll into a the parent node... - { - QModelIndex parent = currentIndex.parent(); - QModelIndex aunt = parent.sibling( parent.row() + rowDelta, parent.column() ); - if( rowDelta == -1 ) - resultingIndex = aunt.child( model()->rowCount( aunt ) - 1, 0 ); - else - resultingIndex = aunt.child( 0, 0 ); - if( !resultingIndex.isValid() ) - return; - } + } else { + //If we have a toplevel node, try and get an adjacent child + if(direction == Backward) { + QModelIndex newParent = currentIndex.sibling(currentIndex.row() - 1, 0); + if(model()->hasChildren(newParent)) + resultingIndex = newParent.child(model()->rowCount(newParent) - 1, 0); + else + resultingIndex = newParent; + } else { + if(model()->hasChildren(currentIndex)) + resultingIndex = currentIndex.child(0, 0); + else + resultingIndex = currentIndex.sibling(currentIndex.row() + 1, 0); + } + } + + if(!resultingIndex.isValid()) + return; + selectionModel()->setCurrentIndex( resultingIndex, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows ); selectionModel()->select( resultingIndex, QItemSelectionModel::ClearAndSelect ); +} + +void BufferView::wheelEvent(QWheelEvent* event) { + if(ItemViewSettings().mouseWheelChangesBuffer() == (bool)(event->modifiers() & Qt::AltModifier)) + return QTreeView::wheelEvent(event); + int rowDelta = ( event->delta() > 0 ) ? -1 : 1; + changeBuffer((Direction)rowDelta); } QSize BufferView::sizeHint() const { @@ -490,19 +502,110 @@ QSize BufferView::sizeHint() const { return QSize(columnSize, 50); } + +// **************************************** +// BufferViewDelgate +// **************************************** +class ColorsChangedEvent : public QEvent { +public: + ColorsChangedEvent() : QEvent(QEvent::User) {}; +}; + +BufferViewDelegate::BufferViewDelegate(QObject *parent) + : QStyledItemDelegate(parent) +{ +} + +void BufferViewDelegate::customEvent(QEvent *event) { + if(event->type() != QEvent::User) + return; + + event->accept(); +} + +bool BufferViewDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { + if(event->type() != QEvent::MouseButtonRelease) + return QStyledItemDelegate::editorEvent(event, model, option, index); + + if(!(model->flags(index) & Qt::ItemIsUserCheckable)) + return QStyledItemDelegate::editorEvent(event, model, option, index); + + QVariant value = index.data(Qt::CheckStateRole); + if(!value.isValid()) + return QStyledItemDelegate::editorEvent(event, model, option, index); + + QStyleOptionViewItemV4 viewOpt(option); + initStyleOption(&viewOpt, index); + + QRect checkRect = viewOpt.widget->style()->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &viewOpt, viewOpt.widget); + QMouseEvent *me = static_cast(event); + + if(me->button() != Qt::LeftButton || !checkRect.contains(me->pos())) + return QStyledItemDelegate::editorEvent(event, model, option, index); + + Qt::CheckState state = static_cast(value.toInt()); + if(state == Qt::Unchecked) + state = Qt::PartiallyChecked; + else if(state == Qt::PartiallyChecked) + state = Qt::Checked; + else + state = Qt::Unchecked; + model->setData(index, state, Qt::CheckStateRole); + return true; +} + // ============================== // BufferView Dock // ============================== BufferViewDock::BufferViewDock(BufferViewConfig *config, QWidget *parent) - : QDockWidget(config->bufferViewName(), parent) + : QDockWidget(parent), + _active(false), + _title(config->bufferViewName()) { setObjectName("BufferViewDock-" + QString::number(config->bufferViewId())); toggleViewAction()->setData(config->bufferViewId()); setAllowedAreas(Qt::RightDockWidgetArea|Qt::LeftDockWidgetArea); connect(config, SIGNAL(bufferViewNameSet(const QString &)), this, SLOT(bufferViewRenamed(const QString &))); + updateTitle(); +} + +void BufferViewDock::updateTitle() { + QString title = _title; + if(isActive()) + title.prepend(QString::fromUtf8("• ")); + setWindowTitle(title); +} + +void BufferViewDock::setActive(bool active) { + if(active != isActive()) { + _active = active; + updateTitle(); + if(active) + raise(); // for tabbed docks + } } void BufferViewDock::bufferViewRenamed(const QString &newName) { - setWindowTitle(newName); + _title = newName; + updateTitle(); toggleViewAction()->setText(newName); } + +int BufferViewDock::bufferViewId() const { + BufferView *view = bufferView(); + if(!view) + return 0; + + if(view->config()) + return view->config()->bufferViewId(); + else + return 0; +} + +BufferViewConfig *BufferViewDock::config() const { + BufferView *view = bufferView(); + if(!view) + return 0; + else + return view->config(); +}