* 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 "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<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;
+}
+
+
+
+
/*****************************************
* The TreeView showing the Buffers
*****************************************/
// 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) {
+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 &)));
setSelectionMode(QAbstractItemView::ExtendedSelection);
+
+ QAbstractItemDelegate *oldDelegate = itemDelegate();
+ TristateDelegate *tristateDelegate = new TristateDelegate(this);
+ setItemDelegate(tristateDelegate);
+ delete oldDelegate;
}
void BufferView::init() {
- setIndentation(10);
header()->setContextMenuPolicy(Qt::ActionsContextMenu);
hideColumn(1);
hideColumn(2);
+ setIndentation(5);
expandAll();
setAnimated(true);
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());
}
+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) {
NetworkModelActionProvider::ActionType type = (NetworkModelActionProvider::ActionType)result->data().toInt();
switch(type) {
inline BufferViewConfig *config() { return _config; }
void addActionsToMenu(QMenu *menu, const QModelIndex &index);
+ void addFilterActions(QMenu *contextMenu, const QModelIndex &index);
public slots:
void setRootIndexForNetworkId(const NetworkId &networkId);
void storeExpandedState(NetworkId networkId, bool expanded);
};
+// ******************************
+// TristateDelgate
+// ******************************
+#include <QStyledItemDelegate>
+
+class TristateDelegate : public QStyledItemDelegate {
+ Q_OBJECT
+
+public:
+ TristateDelegate(QObject *parent = 0) : QStyledItemDelegate(parent) {}
+ bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index);
+};
+
+
// ==============================
// BufferView Dock
// ==============================
_sortOrder(Qt::AscendingOrder),
_userOfflineIcon(SmallIcon("user-offline")),
_userAwayIcon(SmallIcon("user-away")),
- _userOnlineIcon(SmallIcon("user-online"))
+ _userOnlineIcon(SmallIcon("user-online")),
+ _editMode(false),
+ _enableEditMode(tr("Edit Mode"), this)
{
setConfig(config);
setSourceModel(model);
connect(this, SIGNAL(_dataChanged(const QModelIndex &, const QModelIndex &)),
this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex)));
+ _enableEditMode.setCheckable(true);
+ _enableEditMode.setChecked(_editMode);
+ connect(&_enableEditMode, SIGNAL(toggled(bool)), this, SLOT(enableEditMode(bool)));
+
BufferSettings bufferSettings;
_showUserStateIcons = bufferSettings.showUserStateIcons();
bufferSettings.notify("ShowUserStateIcons", this, SLOT(showUserStateIconsChanged()));
emit configChanged();
}
+QList<QAction *> BufferViewFilter::actions(const QModelIndex &index) {
+ Q_UNUSED(index)
+ QList<QAction *> actionList;
+ actionList << &_enableEditMode;
+ return actionList;
+}
+
+void BufferViewFilter::enableEditMode(bool enable) {
+ if(_editMode == enable) {
+ return;
+ }
+ _editMode = enable;
+
+ if(!config())
+ return;
+
+ if(enable == false) {
+ int numBuffers = config()->bufferList().count();
+ QSet<BufferId>::const_iterator iter;
+ for(iter = _toAdd.constBegin(); iter != _toAdd.constEnd(); iter++) {
+ if(config()->bufferList().contains(*iter))
+ continue;
+ config()->requestAddBuffer(*iter, numBuffers);
+ }
+ for(iter = _toTempRemove.constBegin(); iter != _toTempRemove.constEnd(); iter++) {
+ if(config()->temporarilyRemovedBuffers().contains(*iter))
+ continue;
+ config()->requestRemoveBuffer(*iter);
+ }
+ for(iter = _toRemove.constBegin(); iter != _toRemove.constEnd(); iter++) {
+ if(config()->removedBuffers().contains(*iter))
+ continue;
+ config()->requestRemoveBufferPermanently(*iter);
+ }
+ }
+ _toAdd.clear();
+ _toTempRemove.clear();
+ _toRemove.clear();
+
+ invalidate();
+}
+
+
Qt::ItemFlags BufferViewFilter::flags(const QModelIndex &index) const {
Qt::ItemFlags flags = mapToSource(index).flags();
- if(_config && (index == QModelIndex() || index.parent() == QModelIndex()))
- flags |= Qt::ItemIsDropEnabled;
+ if(_config) {
+ if(index == QModelIndex() || index.parent() == QModelIndex()) {
+ flags |= Qt::ItemIsDropEnabled;
+ } else if(_editMode) {
+ flags |= Qt::ItemIsUserCheckable | Qt::ItemIsTristate;
+ }
+ }
return flags;
}
int activityLevel = source_bufferIndex.data(NetworkModel::BufferActivityRole).toInt();
- if(!config()->bufferList().contains(bufferId)) {
+ if(!config()->bufferList().contains(bufferId) && !_editMode) {
// add the buffer if...
if(config()->isInitialized() && !config()->removedBuffers().contains(bufferId) // it hasn't been manually removed and either
&& ((config()->addNewBuffersAutomatically() && !config()->temporarilyRemovedBuffers().contains(bufferId)) // is totally unknown to us (a new buffer)...
}
bool BufferViewFilter::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const {
- int itemType = source_left.data(NetworkModel::ItemTypeRole).toInt();
+ int leftItemType = source_left.data(NetworkModel::ItemTypeRole).toInt();
+ int rightItemType = source_right.data(NetworkModel::ItemTypeRole).toInt();
+ int itemType = leftItemType & rightItemType;
switch(itemType) {
case NetworkModel::NetworkItemType:
return networkLessThan(source_left, source_right);
BufferId leftBufferId = source_left.data(NetworkModel::BufferIdRole).value<BufferId>();
BufferId rightBufferId = source_right.data(NetworkModel::BufferIdRole).value<BufferId>();
if(config()) {
- return config()->bufferList().indexOf(leftBufferId) < config()->bufferList().indexOf(rightBufferId);
+ int leftPos = config()->bufferList().indexOf(leftBufferId);
+ int rightPos = config()->bufferList().indexOf(rightBufferId);
+ if(leftPos == -1 && rightPos == -1)
+ return QSortFilterProxyModel::lessThan(source_left, source_right);
+ if(leftPos == -1 || rightPos == -1)
+ return !(leftPos < rightPos);
+ return leftPos < rightPos;
} else
return bufferIdLessThan(leftBufferId, rightBufferId);
}
return icon(index);
case Qt::ForegroundRole:
return foreground(index);
+ case Qt::CheckStateRole:
+ return checkedState(index);
default:
return QSortFilterProxyModel::data(index, role);
}
return _FgColorNoActivity;
}
+QVariant BufferViewFilter::checkedState(const QModelIndex &index) const {
+ if(!_editMode || !config())
+ return QVariant();
+
+ BufferId bufferId = index.data(NetworkModel::BufferIdRole).value<BufferId>();
+ if(_toAdd.contains(bufferId))
+ return Qt::Checked;
+
+ if(_toTempRemove.contains(bufferId))
+ return Qt::PartiallyChecked;
+
+ if(_toRemove.contains(bufferId))
+ return Qt::Unchecked;
+
+ if(config()->bufferList().contains(bufferId))
+ return Qt::Checked;
+
+ if(config()->temporarilyRemovedBuffers().contains(bufferId))
+ return Qt::PartiallyChecked;
+
+ return Qt::Unchecked;
+}
+
+bool BufferViewFilter::setData(const QModelIndex &index, const QVariant &value, int role) {
+ switch(role) {
+ case Qt::CheckStateRole:
+ return setCheckedState(index, Qt::CheckState(value.toInt()));
+ default:
+ return QSortFilterProxyModel::setData(index, value, role);
+ }
+}
+
+bool BufferViewFilter::setCheckedState(const QModelIndex &index, Qt::CheckState state) {
+ BufferId bufferId = index.data(NetworkModel::BufferIdRole).value<BufferId>();
+ if(!bufferId.isValid())
+ return false;
+
+ switch(state) {
+ case Qt::Unchecked:
+ _toAdd.remove(bufferId);
+ _toTempRemove.remove(bufferId);
+ _toRemove << bufferId;
+ break;
+ case Qt::PartiallyChecked:
+ _toAdd.remove(bufferId);
+ _toTempRemove << bufferId;
+ _toRemove.remove(bufferId);
+ break;
+ case Qt::Checked:
+ _toAdd << bufferId;
+ _toTempRemove.remove(bufferId);
+ _toRemove.remove(bufferId);
+ break;
+ default:
+ return false;
+ }
+ emit dataChanged(index, index);
+ return true;
+}
+
void BufferViewFilter::checkPreviousCurrentForRemoval(const QModelIndex ¤t, const QModelIndex &previous) {
Q_UNUSED(current);
if(previous.isValid())
#ifndef BUFFERVIEWFILTER_H_
#define BUFFERVIEWFILTER_H_
+#include <QAction>
#include <QColor>
#include <QDropEvent>
#include <QFlags>
QVariant data(const QModelIndex &index, int role) const;
QVariant icon(const QModelIndex &index) const;
QVariant foreground(const QModelIndex &index) const;
+ QVariant checkedState(const QModelIndex &index) const;
+
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+ bool setCheckedState(const QModelIndex &index, Qt::CheckState state);
void setConfig(BufferViewConfig *config);
inline BufferViewConfig *config() const { return _config; }
virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
+ QList<QAction *> actions(const QModelIndex &index);
+
public slots:
void checkPreviousCurrentForRemoval(const QModelIndex ¤t, const QModelIndex &previous);
void checkItemForRemoval(const QModelIndex &index) { checkItemsForRemoval(index, index); }
private slots:
void configInitialized();
void showUserStateIconsChanged();
+ void enableEditMode(bool enable);
private:
QPointer<BufferViewConfig> _config;
QPixmap _userOnlineIcon;
bool _showUserStateIcons;
+ bool _editMode;
+ QAction _enableEditMode;
+ QSet<BufferId> _toAdd;
+ QSet<BufferId> _toTempRemove;
+ QSet<BufferId> _toRemove;
+
void loadColors();
bool filterAcceptBuffer(const QModelIndex &) const;