/***************************************************************************
- * Copyright (C) 2005-08 by the Quassel Project *
+ * Copyright (C) 2005-09 by the Quassel Project *
* devel@quassel-irc.org *
* *
* This program is free software; you can redistribute it and/or modify *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
+#include "bufferview.h"
+
+#include <QApplication>
#include <QAction>
#include <QFlags>
#include <QHeaderView>
#include <QMessageBox>
#include <QSet>
-#include "bufferview.h"
-
#include "action.h"
#include "buffermodel.h"
#include "bufferviewfilter.h"
#include "buffersyncer.h"
#include "client.h"
#include "iconloader.h"
-#include "mappedselectionmodel.h"
#include "network.h"
#include "networkmodel.h"
#include "networkmodelactionprovider.h"
*****************************************/
// Please be carefull when reimplementing methods which are used to inform the view about changes to the data
// to be on the safe side: call QTreeView's method aswell
-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 &)));
+BufferView::BufferView(QWidget *parent)
+ : QTreeView(parent)
+{
+ 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();
+ BufferViewDelegate *tristateDelegate = new BufferViewDelegate(this);
+ setItemDelegate(tristateDelegate);
+ delete oldDelegate;
}
void BufferView::init() {
- setIndentation(10);
header()->setContextMenuPolicy(Qt::ActionsContextMenu);
hideColumn(1);
hideColumn(2);
+ setIndentation(10);
expandAll();
setAnimated(true);
connect(config, SIGNAL(networkIdSet(const NetworkId &)), this, SLOT(setRootIndexForNetworkId(const NetworkId &)));
setRootIndexForNetworkId(config->networkId());
} else {
+ setIndentation(10);
setRootIndex(QModelIndex());
}
}
void BufferView::setRootIndexForNetworkId(const NetworkId &networkId) {
if(!networkId.isValid() || !model()) {
+ setIndentation(10);
setRootIndex(QModelIndex());
} else {
+ setIndentation(5);
int networkCount = model()->rowCount();
QModelIndex child;
for(int i = 0; i < networkCount; i++) {
QTreeView::keyPressEvent(event);
}
+void BufferView::dropEvent(QDropEvent *event) {
+ QModelIndex index = indexAt(event->pos());
+
+ QRect indexRect = visualRect(index);
+ QPoint cursorPos = event->pos();
+
+ // check if we're really _on_ the item and not indicating a move to just above or below the item
+ const int margin = 2;
+ if(cursorPos.y() - indexRect.top() < margin
+ || indexRect.bottom() - cursorPos.y() < margin)
+ return QTreeView::dropEvent(event);
+
+ QList< QPair<NetworkId, BufferId> > bufferList = Client::networkModel()->mimeDataToBufferList(event->mimeData());
+ if(bufferList.count() != 1)
+ return QTreeView::dropEvent(event);
+
+ NetworkId networkId = bufferList[0].first;
+ BufferId bufferId2 = bufferList[0].second;
+
+ if(index.data(NetworkModel::ItemTypeRole) != NetworkModel::BufferItemType)
+ return QTreeView::dropEvent(event);
+
+ if(index.data(NetworkModel::BufferTypeRole) != BufferInfo::QueryBuffer)
+ return QTreeView::dropEvent(event);
+
+ if(index.data(NetworkModel::NetworkIdRole).value<NetworkId>() != networkId)
+ return QTreeView::dropEvent(event);
+
+ BufferId bufferId1 = index.data(NetworkModel::BufferIdRole).value<BufferId>();
+ if(bufferId1 == bufferId2)
+ 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);
+ if(res == QMessageBox::Yes) {
+ Client::mergeBuffersPermanently(bufferId1, bufferId2);
+ }
+}
+
void BufferView::removeSelectedBuffers(bool permanently) {
if(!config())
return;
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);
}
- // update selection to current one
- MappedSelectionModel *mappedSelectionModel = qobject_cast<MappedSelectionModel *>(selectionModel());
- if(!config() || !mappedSelectionModel)
- return;
+ if(config()) {
+ // update selection to current one
+ Client::bufferModel()->synchronizeView(this);
+ }
- mappedSelectionModel->mappedSetCurrentIndex(Client::bufferModel()->standardSelectionModel()->currentIndex(), QItemSelectionModel::Current);
- mappedSelectionModel->mappedSelect(Client::bufferModel()->standardSelectionModel()->selection(), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
+ return;
}
-void BufferView::on_collapse(const QModelIndex &index) {
- storeExpandedState(index.data(NetworkModel::NetworkIdRole).value<NetworkId>(), false);
-}
+void BufferView::storeExpandedState(const QModelIndex &networkIdx) {
+ NetworkId networkId = model()->data(networkIdx, NetworkModel::NetworkIdRole).value<NetworkId>();
+
+ int oldState = 0;
+ if(isExpanded(networkIdx))
+ oldState |= WasExpanded;
+ if(model()->data(networkIdx, NetworkModel::ItemActiveRole).toBool())
+ oldState |= WasActive;
-void BufferView::on_expand(const QModelIndex &index) {
- storeExpandedState(index.data(NetworkModel::NetworkIdRole).value<NetworkId>(), true);
+ _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<NetworkId>();
+
+ 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);
+ }
+
+ storeExpandedState(networkIdx); // this call is needed to keep track of the isActive state
+ if(expandNetwork != isExpanded(networkIdx))
+ setExpanded(networkIdx, expandNetwork);
}
void BufferView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) {
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);
}
}
QModelIndex index = indexAt(event->pos());
if(!index.isValid())
index = rootIndex();
- if(!index.isValid())
- return;
QMenu contextMenu(this);
- addActionsToMenu(&contextMenu, index);
+
+ if(index.isValid()) {
+ addActionsToMenu(&contextMenu, index);
+ }
+
+ addFilterActions(&contextMenu, index);
+
if(!contextMenu.actions().isEmpty())
contextMenu.exec(QCursor::pos());
-
}
void BufferView::addActionsToMenu(QMenu *contextMenu, const QModelIndex &index) {
- Client::mainUi()->actionProvider()->addActions(contextMenu, index, this, "menuActionTriggered", (bool)config());
+ QModelIndexList indexList = selectedIndexes();
+ // make sure the item we clicked on is first
+ indexList.removeAll(index);
+ indexList.prepend(index);
+
+ Client::mainUi()->actionProvider()->addActions(contextMenu, indexList, this, "menuActionTriggered", (bool)config());
+}
+
+void BufferView::addFilterActions(QMenu *contextMenu, const QModelIndex &index) {
+ BufferViewFilter *filter = qobject_cast<BufferViewFilter *>(model());
+ if(filter) {
+ QList<QAction *> filterActions = filter->actions(index);
+ if(!filterActions.isEmpty()) {
+ contextMenu->addSeparator();
+ foreach(QAction *action, filterActions) {
+ contextMenu->addAction(action);
+ }
+ }
+ }
}
void BufferView::menuActionTriggered(QAction *result) {
return QSize(columnSize, 50);
}
+
+// ****************************************
+// BufferViewDelgate
+// ****************************************
+BufferViewDelegate::BufferViewDelegate(QObject *parent)
+ : QStyledItemDelegate(parent)
+{
+ UiSettings s("QtUiStyle/Colors");
+ _FgColorHighlightActivity = s.value("highlightActivityFG", QVariant(QColor(Qt::magenta))).value<QColor>();
+ _FgColorNewMessageActivity = s.value("newMessageActivityFG", QVariant(QColor(Qt::green))).value<QColor>();
+ _FgColorOtherActivity = s.value("otherActivityFG", QVariant(QColor(Qt::darkGreen))).value<QColor>();
+}
+
+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<QMouseEvent*>(event);
+
+ if(me->button() != Qt::LeftButton || !checkRect.contains(me->pos()))
+ return QStyledItemDelegate::editorEvent(event, model, option, index);
+
+ Qt::CheckState state = static_cast<Qt::CheckState>(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;
+}
+
+void BufferViewDelegate::initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const {
+ QStyledItemDelegate::initStyleOption(option, index);
+
+ BufferInfo::ActivityLevel activity = (BufferInfo::ActivityLevel)index.data(NetworkModel::BufferActivityRole).toInt();
+
+ if(activity & BufferInfo::Highlight) {
+ option->palette.setColor(QPalette::Text, _FgColorHighlightActivity);
+ return;
+ }
+ if(activity & BufferInfo::NewMessage) {
+ option->palette.setColor(QPalette::Text, _FgColorNewMessageActivity);
+ return;
+ }
+ if(activity & BufferInfo::OtherActivity) {
+ option->palette.setColor(QPalette::Text, _FgColorOtherActivity);
+ return;
+ }
+
+ if(!index.data(NetworkModel::ItemActiveRole).toBool() || index.data(NetworkModel::UserAwayRole).toBool()) {
+ option->palette.setColor(QPalette::Text, QPalette().color(QPalette::Dark));
+ }
+}
+
+
// ==============================
// BufferView Dock
// ==============================
connect(config, SIGNAL(bufferViewNameSet(const QString &)), this, SLOT(bufferViewRenamed(const QString &)));
}
-BufferViewDock::BufferViewDock(QWidget *parent)
- : QDockWidget(tr("All Buffers"), parent)
-{
- setObjectName("BufferViewDock--1");
- toggleViewAction()->setData((int)-1);
- setAllowedAreas(Qt::RightDockWidgetArea|Qt::LeftDockWidgetArea);
-}
-
void BufferViewDock::bufferViewRenamed(const QString &newName) {
setWindowTitle(newName);
toggleViewAction()->setText(newName);