+ setDragEnabled(true);
+ setAcceptDrops(true);
+ setDropIndicatorShown(true);
+#endif
+
+ setSortingEnabled(true);
+ sortByColumn(0, Qt::AscendingOrder);
+
+ // 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
+}
+
+
+void BufferView::setModel(QAbstractItemModel *model)
+{
+ delete selectionModel();
+
+ TreeViewTouch::setModel(model);
+ init();
+ // remove old Actions
+ QList<QAction *> oldactions = header()->actions();
+ foreach(QAction *action, oldactions) {
+ header()->removeAction(action);
+ action->deleteLater();
+ }
+
+ if (!model)
+ return;
+
+ QString sectionName;
+ QAction *showSection;
+ for (int i = 1; i < model->columnCount(); i++) {
+ sectionName = (model->headerData(i, Qt::Horizontal, Qt::DisplayRole)).toString();
+ showSection = new QAction(sectionName, header());
+ showSection->setCheckable(true);
+ showSection->setChecked(!isColumnHidden(i));
+ showSection->setProperty("column", i);
+ connect(showSection, SIGNAL(toggled(bool)), this, SLOT(toggleHeader(bool)));
+ header()->addAction(showSection);
+ }
+
+ connect(model, SIGNAL(layoutChanged()), this, SLOT(on_layoutChanged()));
+}
+
+
+void BufferView::setFilteredModel(QAbstractItemModel *model_, BufferViewConfig *config)
+{
+ BufferViewFilter *filter = qobject_cast<BufferViewFilter *>(model());
+ if (filter) {
+ filter->setConfig(config);
+ setConfig(config);
+ return;
+ }
+
+ if (model()) {
+ disconnect(this, 0, model(), 0);
+ disconnect(model(), 0, this, 0);
+ }
+
+ if (!model_) {
+ setModel(model_);
+ }
+ else {
+ BufferViewFilter *filter = new BufferViewFilter(model_, config);
+ setModel(filter);
+ connect(filter, SIGNAL(configChanged()), this, SLOT(on_configChanged()));
+ }
+ setConfig(config);
+}
+
+
+void BufferView::setConfig(BufferViewConfig *config)
+{
+ if (_config == config)
+ return;
+
+ if (_config) {
+ disconnect(_config, 0, this, 0);
+ }
+
+ _config = config;
+ if (config) {
+ 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++) {
+ child = model()->index(i, 0);
+ if (networkId == model()->data(child, NetworkModel::NetworkIdRole).value<NetworkId>())
+ setRootIndex(child);
+ }
+ }
+}
+
+
+void BufferView::joinChannel(const QModelIndex &index)
+{
+ BufferInfo::Type bufferType = (BufferInfo::Type)index.data(NetworkModel::BufferTypeRole).value<int>();
+
+ if (bufferType != BufferInfo::ChannelBuffer)
+ return;
+
+ BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value<BufferInfo>();
+
+ Client::userInput(bufferInfo, QString("/JOIN %1").arg(bufferInfo.bufferName()));
+}
+
+
+void BufferView::keyPressEvent(QKeyEvent *event)
+{
+ if (event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete) {
+ event->accept();
+ removeSelectedBuffers();
+ }
+ TreeViewTouch::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 TreeViewTouch::dropEvent(event);
+
+ QList<QPair<NetworkId, BufferId> > bufferList = Client::networkModel()->mimeDataToBufferList(event->mimeData());
+ if (bufferList.count() != 1)
+ return TreeViewTouch::dropEvent(event);
+
+ BufferId bufferId2 = bufferList[0].second;
+
+ if (index.data(NetworkModel::ItemTypeRole) != NetworkModel::BufferItemType)
+ return TreeViewTouch::dropEvent(event);
+
+ if (index.data(NetworkModel::BufferTypeRole) != BufferInfo::QueryBuffer)
+ return TreeViewTouch::dropEvent(event);
+
+ BufferId bufferId1 = index.data(NetworkModel::BufferIdRole).value<BufferId>();
+ if (bufferId1 == bufferId2)
+ return TreeViewTouch::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;
+
+ BufferId bufferId;
+ QSet<BufferId> removedRows;
+ foreach(QModelIndex index, selectionModel()->selectedIndexes()) {
+ if (index.data(NetworkModel::ItemTypeRole) != NetworkModel::BufferItemType)
+ continue;
+
+ bufferId = index.data(NetworkModel::BufferIdRole).value<BufferId>();
+ if (removedRows.contains(bufferId))
+ continue;
+
+ removedRows << bufferId;
+ }
+
+ foreach(BufferId bufferId, removedRows) {
+ if (permanently)
+ config()->requestRemoveBufferPermanently(bufferId);
+ else
+ config()->requestRemoveBuffer(bufferId);
+ }
+}
+
+
+void BufferView::rowsInserted(const QModelIndex &parent, int start, int end)
+{
+ TreeViewTouch::rowsInserted(parent, start, end);
+
+ // ensure that newly inserted network nodes are expanded per default
+ if (parent.data(NetworkModel::ItemTypeRole) != NetworkModel::NetworkItemType)
+ return;
+
+ 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);
+ }
+}
+
+
+void BufferView::on_configChanged()
+{
+ Q_ASSERT(model());
+
+ // expand all active networks... collapse inactive ones... unless manually changed
+ QModelIndex networkIdx;
+ NetworkId networkId;
+ for (int row = 0; row < model()->rowCount(); row++) {
+ networkIdx = model()->index(row, 0);
+ if (model()->rowCount(networkIdx) == 0)
+ continue;
+
+ networkId = model()->data(networkIdx, NetworkModel::NetworkIdRole).value<NetworkId>();
+ if (!networkId.isValid())
+ continue;
+
+ setExpandedState(networkIdx);
+ }
+
+ if (config()) {
+ // update selection to current one
+ Client::bufferModel()->synchronizeView(this);
+ }
+}
+
+
+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;
+
+ _expandedState[networkId] = oldState;
+}
+
+
+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);
+ }
+
+ if (expandNetwork != isExpanded(networkIdx)) {
+ update(networkIdx);
+ setExpanded(networkIdx, expandNetwork);
+ }
+ storeExpandedState(networkIdx); // this call is needed to keep track of the isActive state
+}
+
+#if QT_VERSION < 0x050000
+void BufferView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
+{
+ TreeViewTouch::dataChanged(topLeft, bottomRight);
+#else
+void BufferView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
+{
+ TreeViewTouch::dataChanged(topLeft, bottomRight, roles);