174
174
//----------------------------------------------------------------------------
176
class DiscoListItem : public QObject, public Q3ListViewItem
176
class DiscoListItem : public QObject, public QTreeWidgetItem
180
DiscoListItem(DiscoItem it, DiscoData *d, Q3ListView *parent);
181
DiscoListItem(DiscoItem it, DiscoData *d, Q3ListViewItem *parent);
180
DiscoListItem(DiscoItem it, DiscoData *d, QTreeWidget *parent);
181
DiscoListItem(DiscoItem it, DiscoData *d, QTreeWidgetItem *parent);
182
182
~DiscoListItem();
184
QString text(int columns) const;
185
void setOpen(bool open);
184
void setExpanded(bool expand);
186
185
const DiscoItem &item() const;
188
187
void itemSelected();
220
219
// helper functions
221
220
void init(DiscoItem it, DiscoData *dd);
222
void hideChildIndicator();
223
224
bool autoItemsEnabled() const;
224
225
bool autoInfoEnabled() const;
225
226
DiscoDlg *dlg() const;
228
DiscoListItem::DiscoListItem(DiscoItem it, DiscoData *_d, Q3ListView *parent)
229
: Q3ListViewItem (parent)
229
DiscoListItem::DiscoListItem(DiscoItem it, DiscoData *_d, QTreeWidget *parent)
230
: QTreeWidgetItem (parent)
236
DiscoListItem::DiscoListItem(DiscoItem it, DiscoData *_d, Q3ListViewItem *parent)
237
: Q3ListViewItem (parent)
237
DiscoListItem::DiscoListItem(DiscoItem it, DiscoData *_d, QTreeWidgetItem *parent)
238
: QTreeWidgetItem (parent)
312
bool pixmapOk = false;
313
setText(0, di.name().simplified());
314
setText(1, di.jid().full());
315
setText(2, di.node().simplified());
313
318
if ( !di.identities().isEmpty() ) {
314
319
DiscoItem::Identity id = di.identities().first();
316
321
if ( !id.category.isEmpty() ) {
317
PsiIcon ic = category2icon(id.category, id.type);
322
QIcon icon = category2icon(id.category, id.type).icon();
319
if ( !ic.impix().isNull() ) {
320
setPixmap (0, ic.impix());
324
if ( !icon.isNull() ) {
327
setPixmap(0, PsiIconset::instance()->status(di.jid(), STATUS_ONLINE).impix());
332
setIcon(0, PsiIconset::instance()->status(di.jid(), STATUS_ONLINE).icon());
331
334
if ( isSelected() ) // update actions
332
335
emit d->d->itemUpdated( this );
335
QString DiscoListItem::text (int c) const
338
return di.name().simplified();
340
return di.jid().full();
342
return di.node().simplified();
346
338
QString DiscoListItem::getErrorInfo() const
348
340
return errorInfo;
368
360
return dlg()->ck_autoInfo->isChecked();
371
void DiscoListItem::setOpen (bool o)
363
void DiscoListItem::setExpanded (bool expand)
374
366
if ( !alreadyItems )
377
369
autoItemsChildren();
380
Q3ListViewItem::setOpen(o);
372
QTreeWidgetItem::setExpanded(expand);
383
375
void DiscoListItem::itemSelected()
570
void DiscoListItem::hideChildIndicator()
572
setChildIndicatorPolicy(DontShowIndicator);
573
#if QT_VERSION >= 0x040500
576
Qt::ItemFlags tmp = flags();
578
582
void DiscoListItem::updateItemsFinished(const DiscoList &list)
580
Q3Dict<DiscoListItem> children;
581
DiscoListItem *child = (DiscoListItem *)firstChild();
584
treeWidget()->setUpdatesEnabled(false);
586
QHash<QString, DiscoListItem*> children;
587
DiscoListItem *child = (DiscoListItem *)QTreeWidgetItem::child(0);
588
for ( int i = 1; child; ++i ) {
583
589
children.insert( child->hash(), child );
585
child = (DiscoListItem *)child->nextSibling();
591
child = (DiscoListItem *)QTreeWidgetItem::child(i);
588
594
// add/update items
604
610
// remove all items that are not on new DiscoList
605
children.setAutoDelete( true );
611
qDeleteAll(children);
606
612
children.clear();
608
if ( autoItems && isOpen() )
614
if ( autoItems && isExpanded() )
609
615
autoItemsChildren();
611
// don't forget to remove '+' (or '-') sign in case, that the child list is empty
612
setExpandable ( !list.isEmpty() );
617
if (list.isEmpty()) {
618
hideChildIndicator();
616
621
// root item is initially hidden
617
if ( isRoot && !isVisible() )
622
if ( isRoot && isHidden() )
625
treeWidget()->setUpdatesEnabled(true);
621
628
void DiscoListItem::autoItemsChildren() const
623
630
if ( !autoItemsEnabled() )
626
DiscoListItem *child = (DiscoListItem *)firstChild();
633
DiscoListItem *child = (DiscoListItem *)QTreeWidgetItem::child(0);
634
for ( int i = 1; child; ++i ) {
628
635
child->updateItems(true);
630
child = (DiscoListItem *)child->nextSibling();
637
child = (DiscoListItem *)QTreeWidgetItem::child(i);
661
668
// FIXME: use another method for checking XMPP error-types when Iris will provide one
662
669
if ( error_code==400 || error_code==404 || error_code==405 || error_code==409 ||
663
670
error_code==500 || error_code==501 || error_code==503 || error_code==504 ) {
664
bool pixmapOk = false;
665
672
if ( !di.identities().isEmpty() ) {
666
673
DiscoItem::Identity id = di.identities().first();
667
674
if ( !id.category.isEmpty() ) {
668
PsiIcon ic = category2icon(id.category, id.type, STATUS_ERROR);
675
QIcon icon = category2icon(id.category, id.type, STATUS_ERROR).icon();
670
if ( !ic.impix().isNull() ) {
671
setPixmap (0, ic.impix());
677
if ( !icon.isNull() ) {
677
setPixmap(0, PsiIconset::instance()->status(di.jid(), STATUS_ERROR).impix());
679
repaint(); //for setExpandable() called earlier
684
setIcon(0, PsiIconset::instance()->status(di.jid(), STATUS_ERROR).icon());
682
687
errorInfo=QString("%1").arg(QString(error_str).replace('\n', "<br>"));
695
700
copyItem( item );
697
if ( isRoot && !isVisible() )
702
if ( isRoot && isHidden() )
701
706
//----------------------------------------------------------------------------
703
708
//----------------------------------------------------------------------------
705
class DiscoListView : public Q3ListView
710
class DiscoListView : public QTreeWidget
719
724
DiscoListView::DiscoListView(QWidget *parent)
725
: QTreeWidget(parent)
722
addColumn( tr( "Name" ) );
723
addColumn( tr( "JID" ) );
724
addColumn( tr( "Node" ) );
725
for (int i = 0; i < 3; i++)
726
setColumnWidthMode(i, Q3ListView::Manual);
727
header()->setStretchEnabled(true, 0);
727
installEventFilter(this);
728
setHeaderLabels( QStringList() << tr( "Name" ) << tr( "JID" ) << tr( "Node" ) );
729
// header()->setResizeMode(0, QHeaderView::Stretch);
730
// header()->setResizeMode(1, QHeaderView::ResizeToContents);
731
// header()->setResizeMode(2, QHeaderView::ResizeToContents);
732
header()->setStretchLastSection(false);
733
setRootIsDecorated(false);
730
736
void DiscoListView::resizeEvent(QResizeEvent* e)
732
Q3ListView::resizeEvent(e);
734
setColumnWidth(2, header()->fontMetrics().width(columnText(2)) * 2);
735
float remainingWidth = visibleWidth() - columnWidth(2);
736
setColumnWidth(1, int(remainingWidth * 0.3));
738
header()->adjustHeaderSize();
738
QTreeWidget::resizeEvent(e);
740
QHeaderView* h = header();
741
h->resizeSection(2, h->fontMetrics().width(headerItem()->text(2)) * 2);
742
float remainingWidth = viewport()->width() - h->sectionSize(2);
743
h->resizeSection(1, int(remainingWidth * 0.3));
744
h->resizeSection(0, int(remainingWidth * 0.7));
746
//h->adjustHeaderSize();
829
837
maybeTip(w->mapToGlobal(he->pos()));
832
return Q3ListView::eventFilter(o, e);
840
return QTreeWidget::eventFilter(o, e);
835
843
//----------------------------------------------------------------------------
860
868
// helper class to store browser history
863
Q3ListViewItem *item;
865
History(Q3ListViewItem *it) {
874
Q3ListViewItem *takeItem() {
875
Q3ListViewItem *i = item;
871
History(const XMPP::Jid& _jid, const QString& _node)
891
890
// custom actions, that will be added to toolbar and context menu
892
891
IconAction *actRegister, *actSearch, *actJoin, *actAHCommand, *actVCard, *actAdd;
894
typedef Q3PtrList<History> HistoryList;
893
typedef QList<History*> HistoryList;
895
894
HistoryList backHistory, forwardHistory;
897
896
BusyWidget *busy;
920
918
void disableButtons();
921
919
void enableButtons(const DiscoItem &);
923
void itemSelected (Q3ListViewItem *);
924
void itemDoubleclicked (Q3ListViewItem *);
921
void itemSelected (QTreeWidgetItem *);
922
void itemExpanded (QTreeWidgetItem *);
923
void itemDoubleclicked (QTreeWidgetItem *);
925
924
bool eventFilter (QObject *, QEvent *);
927
926
void setProtocol(int);
943
942
connect(data.tasks, SIGNAL(started()), SLOT(itemUpdateStarted()));
944
943
connect(data.tasks, SIGNAL(finished()), SLOT(itemUpdateFinished()));
945
944
data.d = new DiscoConnector(this);
946
connect(data.d, SIGNAL(itemUpdated(Q3ListViewItem *)), SLOT(itemSelected (Q3ListViewItem *)));
945
connect(data.d, SIGNAL(itemUpdated(QTreeWidgetItem *)), SLOT(itemSelected (QTreeWidgetItem *)));
947
946
data.protocol = DiscoData::Auto;
949
backHistory.setAutoDelete(true);
950
forwardHistory.setAutoDelete(true);
952
948
// mess with widgets
953
949
busy = parent->busy;
954
950
connect(busy, SIGNAL(destroyed(QObject *)), SLOT(objectDestroyed(QObject *)));
956
Q3ListView *lv_discoOld = dlg->lv_disco;
952
QTreeWidget *lv_discoOld = dlg->lv_disco;
957
953
dlg->lv_disco = new DiscoListView(dlg);
958
954
replaceWidget(lv_discoOld, dlg->lv_disco);
960
956
dlg->lv_disco->installEventFilter (this);
961
connect(dlg->lv_disco, SIGNAL(selectionChanged (Q3ListViewItem *)), SLOT(itemSelected (Q3ListViewItem *)));;
962
connect(dlg->lv_disco, SIGNAL(doubleClicked (Q3ListViewItem *)), SLOT(itemDoubleclicked (Q3ListViewItem *)));;
957
connect(dlg->lv_disco, SIGNAL(currentItemChanged (QTreeWidgetItem *, QTreeWidgetItem *)), SLOT(itemSelected (QTreeWidgetItem *)));;
958
connect(dlg->lv_disco, SIGNAL(itemExpanded (QTreeWidgetItem *)), SLOT(itemExpanded (QTreeWidgetItem *)));
959
connect(dlg->lv_disco, SIGNAL(itemDoubleClicked (QTreeWidgetItem *, int)), SLOT(itemDoubleclicked (QTreeWidgetItem *)));;
964
961
// protocol actions
965
962
QSignalMapper *pm = new QSignalMapper(this);
1059
1056
DiscoDlg::Private::~Private()
1058
qDeleteAll(backHistory);
1059
qDeleteAll(forwardHistory);
1061
1060
delete data.tasks;
1064
void DiscoDlg::Private::doDisco(QString _host, QString _node)
1063
void DiscoDlg::Private::doDisco(QString _host, QString _node, bool doHistory)
1066
1065
PsiAccount *pa = data.pa;
1067
1066
if ( !pa->checkConnected(dlg) )
1072
1071
QString host = _host;
1073
1072
if ( host.isEmpty() )
1074
1073
host = dlg->cb_address->currentText();
1075
j = host.stripWhiteSpace();
1076
1075
if ( !j.isValid() )
1079
QString n = _node.stripWhiteSpace();
1078
QString n = _node.trimmed();
1080
1079
if ( n.isEmpty() )
1081
n = dlg->cb_node->currentText().stripWhiteSpace();
1080
n = dlg->cb_node->currentText().trimmed();
1083
1082
// check, whether we need to update history
1084
1083
if ( (jid.full() != j.full()) || (node != n) ) {
1085
Q3ListViewItem *item = dlg->lv_disco->firstChild(); // get the root item
1088
dlg->lv_disco->takeItem( item );
1090
backHistory.append( new History(item) );
1085
backHistory.append(new History(jid, node));
1086
qDeleteAll(forwardHistory);
1091
1087
forwardHistory.clear();
1109
1105
di.setNode( node );
1111
1107
DiscoListItem *root = new DiscoListItem (di, &data, dlg->lv_disco);
1112
root->setVisible (false); // don't confuse users with empty root
1114
root->setOpen(true); // begin browsing
1108
root->setHidden (false); // don't confuse users with empty root
1109
root->setExpanded(true); // begin browsing
1117
1112
void DiscoDlg::Private::updateComboBoxes(Jid j, QString n)
1119
1114
data.pa->psi()->recentBrowseAdd( j.full() );
1120
1115
dlg->cb_address->clear();
1121
dlg->cb_address->insertStringList(data.pa->psi()->recentBrowseList());
1116
dlg->cb_address->addItems(data.pa->psi()->recentBrowseList());
1123
1118
data.pa->psi()->recentNodeAdd( n );
1124
1119
dlg->cb_node->clear();
1125
dlg->cb_node->insertStringList(data.pa->psi()->recentNodeList());
1120
dlg->cb_node->addItems(data.pa->psi()->recentNodeList());
1128
1123
void DiscoDlg::Private::actionStop()
1152
1147
void DiscoDlg::Private::actionBack()
1154
// add current selection to forward history
1155
Q3ListViewItem *item = dlg->lv_disco->firstChild();
1157
dlg->lv_disco->takeItem( item );
1159
forwardHistory.append( new History(item) );
1162
// now, take info from back history...
1163
Q3ListViewItem *i = backHistory.last()->takeItem();
1164
backHistory.removeLast();
1167
backForwardHelper(i);
1149
forwardHistory.append(new History(jid, node));
1150
History *h = backHistory.takeLast();
1151
doDisco(h->jid.full(), h->node, false);
1170
1155
void DiscoDlg::Private::actionForward()
1172
// add current selection to back history
1173
Q3ListViewItem *item = dlg->lv_disco->firstChild();
1175
dlg->lv_disco->takeItem( item );
1177
backHistory.append( new History(item) );
1180
// now, take info from forward history...
1181
Q3ListViewItem *i = forwardHistory.last()->takeItem();
1182
forwardHistory.removeLast();
1185
backForwardHelper(i);
1188
void DiscoDlg::Private::backForwardHelper(Q3ListViewItem *root)
1190
DiscoListItem *i = (DiscoListItem *)root;
1192
jid = i->item().jid();
1193
node = i->item().node();
1195
updateComboBoxes(jid, node);
1197
data.tasks->clear(); // also will call all all necessary functions
1199
updateBackForward();
1201
dlg->lv_disco->insertItem( root );
1203
// fixes multiple selection bug
1204
Q3ListViewItemIterator it( dlg->lv_disco );
1205
while ( it.current() ) {
1206
Q3ListViewItem *item = it.current();
1209
if ( item->isSelected() )
1210
for (int i = 0; i <= 1; i++) // it's boring to write same line twice :-)
1211
dlg->lv_disco->setSelected(item, (bool)i);
1157
backHistory.append(new History(jid, node));
1158
History *h = forwardHistory.takeLast();
1159
doDisco(h->jid.full(), h->node, false);
1215
1163
void DiscoDlg::Private::updateBackForward()
1268
1216
enableButtons ( di );
1271
void DiscoDlg::Private::itemDoubleclicked (Q3ListViewItem *item)
1219
void DiscoDlg::Private::itemExpanded (QTreeWidgetItem *item)
1221
DiscoListItem *it = (DiscoListItem *)item;
1223
it->setExpanded(true);
1226
void DiscoDlg::Private::itemDoubleclicked (QTreeWidgetItem *item)
1273
1228
DiscoListItem *it = (DiscoListItem *)item;
1304
1259
if ( id > 0 ) {
1305
if ( !it->isOpen() ) {
1306
if ( it->isExpandable() || it->childCount() )
1307
it->setOpen( true );
1260
if ( !it->isExpanded() ) {
1261
if ( it->childCount() )
1262
it->setExpanded( true );
1310
it->setOpen( false );
1265
it->setExpanded( false );
1312
1267
emit dlg->featureActivated( Features::feature(id), d.jid(), d.node() );
1359
1314
// prepare popup menu
1362
1317
actBrowse->addTo (&p);
1363
1318
actRefresh->addTo (&p);
1364
1319
actStop->addTo (&p);
1366
1321
// custom actions
1367
p.insertSeparator();
1368
1323
actRegister->addTo(&p);
1369
1324
actSearch->addTo(&p);
1370
1325
actJoin->addTo(&p);
1372
p.insertSeparator();
1373
1328
actAdd->addTo(&p);
1374
1329
actVCard->addTo(&p);
1375
1330
actAHCommand->addTo(&p);
1377
1332
// popup with all available features
1378
Q3PopupMenu *fm = new Q3PopupMenu(&p);
1333
QMenu *fm = new QMenu(&p);
1334
QHash<QAction*, int> actions;
1380
1336
QList<long>::Iterator it = ids.begin();
1381
1337
for ( ; it != ids.end(); ++it)
1382
fm->insertItem(Features::name(*it), *it + 10000); // TODO: add pixmap
1338
actions.insert(fm->addAction(Features::name(*it)), *it + 10000); // TODO: add pixmap
1385
1341
//p.insertSeparator();
1439
1395
d->node = node;
1440
1396
d->data.pa->dialogRegister(this);
1442
setWindowTitle(CAP(caption()));
1398
//setWindowTitle(CAP(caption()));
1443
1399
setWindowIcon(PsiIconset::instance()->transportStatus("transport", STATUS_ONLINE).icon());
1444
1400
X11WM_CLASS("disco");
1451
1407
pb_close->setDefault(false);
1452
1408
pb_close->setAutoDefault(false);
1454
cb_address->insertStringList(pa->psi()->recentBrowseList()); // FIXME
1410
cb_address->addItems(pa->psi()->recentBrowseList()); // FIXME
1455
1411
cb_address->setFocus();
1456
1412
connect(cb_address, SIGNAL(activated(const QString &)), d, SLOT(doDisco()));
1457
cb_address->setCurrentText(d->jid.full());
1413
cb_address->setEditText(d->jid.full());
1459
cb_node->insertStringList(pa->psi()->recentNodeList());
1415
cb_node->addItems(pa->psi()->recentNodeList());
1460
1416
connect(cb_node, SIGNAL(activated(const QString &)), d, SLOT(doDisco()));
1461
cb_node->setCurrentText(node);
1417
cb_node->setCurrentIndex(cb_node->findText(node));
1463
1419
if ( pa->loggedIn() )