~ubuntu-branches/ubuntu/quantal/psi/quantal

« back to all changes in this revision

Viewing changes to src/discodlg.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2008-04-14 18:57:30 UTC
  • mfrom: (2.1.9 hardy)
  • Revision ID: james.westby@ubuntu.com-20080414185730-528re3zp0m2hdlhi
Tags: 0.11-8
* added CONFIG -= link_prl to .pro files and removed dependencies
  which are made unnecessary by this change
* Fix segfault when closing last chat tab with qt4.4
  (This is from upstream svn, rev. 1101) (Closes: Bug#476122)

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
 
21
21
#include "discodlg.h"
22
22
 
23
 
#include <qlistview.h>
24
 
#include <qcombobox.h>
25
 
#include <qcheckbox.h>
26
 
#include <qmessagebox.h>
27
 
#include <qaction.h>
28
 
#include <qstatusbar.h>
29
 
#include <qpopupmenu.h>
30
 
#include <qsignalmapper.h>
31
 
#include <qpushbutton.h>
32
 
#include <qdragobject.h>
33
 
#include <qtooltip.h>
34
 
#include <qtoolbutton.h>
35
 
 
36
 
#include "im.h"
 
23
#include <q3listview.h>
 
24
#include <q3popupmenu.h>
 
25
#include <Q3PtrList>
 
26
 
 
27
#include <QComboBox>
 
28
#include <QCheckBox>
 
29
#include <QMessageBox>
 
30
#include <QAction>
 
31
#include <QSignalMapper>
 
32
#include <QPushButton>
 
33
#include <QToolButton>
 
34
#include <QToolBar>
 
35
#include <QScrollBar>
 
36
 
 
37
#include <QActionGroup>
 
38
#include <QEvent>
 
39
#include <QList>
 
40
#include <QContextMenuEvent>
 
41
 
37
42
#include "xmpp_tasks.h"
38
43
 
39
 
#include "psitoolbar.h"
40
44
#include "tasklist.h"
41
45
#include "psiaccount.h"
42
46
#include "psicon.h"
43
47
#include "busywidget.h"
44
48
#include "common.h"
45
49
#include "iconaction.h"
 
50
#include "psiiconset.h"
 
51
#include "psitooltip.h"
 
52
#include "stretchwidget.h"
 
53
#include "psioptions.h"
 
54
#include "accountlabel.h"
 
55
 
 
56
//----------------------------------------------------------------------------
 
57
 
 
58
PsiIcon category2icon(const QString &category, const QString &type, int status=STATUS_ONLINE)
 
59
{
 
60
        // TODO: update this to http://www.jabber.org/registrar/disco-categories.html#gateway
 
61
 
 
62
        // still have to add more options...
 
63
        if ( category == "service" || category == "gateway" ) {
 
64
                QString trans;
 
65
 
 
66
                if (type == "aim")
 
67
                        trans = "aim";
 
68
                else if (type == "icq")
 
69
                        trans = "icq";
 
70
                else if (type == "msn")
 
71
                        trans = "msn";
 
72
                else if (type == "yahoo")
 
73
                        trans = "yahoo";
 
74
                else if (type == "gadu-gadu" || type == "x-gadugadu")
 
75
                        trans = "gadugadu";
 
76
                else if (type == "sms")
 
77
                        trans = "sms";
 
78
                else
 
79
                        trans = "transport";
 
80
 
 
81
                return PsiIconset::instance()->transportStatus(trans, status);
 
82
 
 
83
                // irc
 
84
                // jud
 
85
                // pager
 
86
                // jabber
 
87
                // serverlist
 
88
                // smtp
 
89
        }
 
90
        else if ( category == "conference" ) {
 
91
                if (type == "public" || type == "private" || type == "text" || type == "irc")
 
92
                        return IconsetFactory::icon("psi/groupChat");
 
93
                else if (type == "url")
 
94
                        return IconsetFactory::icon("psi/www");
 
95
                // irc
 
96
                // list
 
97
                // topic
 
98
        }
 
99
        else if ( category == "validate" ) {
 
100
                if (type == "xml")
 
101
                        return IconsetFactory::icon("psi/xml");
 
102
                // grammar
 
103
                // spell
 
104
        }
 
105
        else if ( category == "user" || category == "client" ) {
 
106
                // client
 
107
                // forward
 
108
                // inbox
 
109
                // portable
 
110
                // voice
 
111
                return PsiIconset::instance()->status(STATUS_ONLINE);
 
112
        }
 
113
        // application
 
114
           // bot
 
115
           // calendar
 
116
           // editor
 
117
           // fileserver
 
118
           // game
 
119
           // whiteboard
 
120
        // headline
 
121
           // logger
 
122
           // notice
 
123
           // rss
 
124
           // stock
 
125
        // keyword
 
126
           // dictionary
 
127
           // dns
 
128
           // software
 
129
           // thesaurus
 
130
           // web
 
131
           // whois
 
132
        // render
 
133
           // en2ru
 
134
           // ??2??
 
135
           // tts
 
136
        return PsiIcon();
 
137
}
46
138
 
47
139
//----------------------------------------------------------------------------
48
140
// DiscoData -- a shared data struct
57
149
        : QObject(parent) {}
58
150
 
59
151
signals:
60
 
        void itemUpdated(QListViewItem *);
 
152
        void itemUpdated(Q3ListViewItem *);
61
153
 
62
154
private:
63
155
        friend class DiscoListItem;
79
171
};
80
172
 
81
173
//----------------------------------------------------------------------------
82
 
// ProtocolAction
83
 
//----------------------------------------------------------------------------
84
 
 
85
 
class ProtocolAction : public QAction
86
 
{
87
 
        Q_OBJECT
88
 
public:
89
 
        ProtocolAction(QString text, QString toolTip, QObject *parent, QSignalMapper *sm, int parm);
90
 
 
91
 
        bool addTo(QWidget *w);
92
 
 
93
 
public slots:
94
 
        void setOn(bool);
95
 
private:
96
 
        QToolButton *btn;
97
 
};
98
 
 
99
 
ProtocolAction::ProtocolAction(QString text, QString toolTip, QObject *parent, QSignalMapper *sm, int parm)
100
 
: QAction(text, text, 0, parent)
101
 
{
102
 
        setText( text );
103
 
        setToggleAction(true);
104
 
        setToolTip(toolTip);
105
 
        connect(this, SIGNAL(activated()), sm, SLOT(map()));
106
 
        sm->setMapping(this, parm);
107
 
        btn = 0;
108
 
}
109
 
 
110
 
bool ProtocolAction::addTo(QWidget *w)
111
 
{
112
 
        if ( w->inherits("QToolBar") ) {
113
 
                if ( btn )
114
 
                        delete btn;
115
 
                QCString bname = name() + QCString("_action_button");
116
 
                btn = new QToolButton ( w, bname );
117
 
 
118
 
                btn->setToggleButton ( isToggleAction() );
119
 
                btn->setOn( isOn() );
120
 
                btn->setTextLabel ( text() );
121
 
                btn->setEnabled ( isEnabled() );
122
 
                btn->setUsesTextLabel( true );
123
 
                QToolTip::add(btn, toolTip());
124
 
 
125
 
                connect(btn, SIGNAL(toggled(bool)), this, SLOT(setOn(bool)));
126
 
 
127
 
                return true;
128
 
        }
129
 
 
130
 
        return false;
131
 
}
132
 
 
133
 
void ProtocolAction::setOn(bool b)
134
 
{
135
 
        if ( btn ) {
136
 
                if ( b )
137
 
                        emit activated();
138
 
                btn->setOn(b);
139
 
        }
140
 
 
141
 
        QAction::setOn(b);
142
 
}
143
 
 
144
 
//----------------------------------------------------------------------------
145
174
// DiscoListItem
146
175
//----------------------------------------------------------------------------
147
176
 
148
 
class DiscoListItem : public QObject, public QListViewItem
 
177
class DiscoListItem : public QObject, public Q3ListViewItem
149
178
{
150
179
        Q_OBJECT
151
180
public:
152
 
        DiscoListItem(DiscoItem it, DiscoData *d, QListView *parent);
153
 
        DiscoListItem(DiscoItem it, DiscoData *d, QListViewItem *parent);
 
181
        DiscoListItem(DiscoItem it, DiscoData *d, Q3ListView *parent);
 
182
        DiscoListItem(DiscoItem it, DiscoData *d, Q3ListViewItem *parent);
154
183
        ~DiscoListItem();
155
184
 
156
185
        QString text(int columns) const;
162
191
public slots: // the two are used internally by class, and also called by DiscoDlg::Private::refresh()
163
192
        void updateInfo();
164
193
        void updateItems(bool parentAutoItems = false);
 
194
        QString getErrorInfo() const;
165
195
 
166
196
private slots:
167
197
        void discoItemsFinished();
179
209
        bool alreadyItems, alreadyInfo;
180
210
        bool autoItems; // used in updateItemsFinished
181
211
        bool autoInfo;
 
212
        QString errorInfo;
182
213
 
183
214
        void copyItem(const DiscoItem &);
184
215
        void updateInfo(const DiscoItem &);
195
226
        DiscoDlg *dlg() const;
196
227
};
197
228
 
198
 
DiscoListItem::DiscoListItem(DiscoItem it, DiscoData *_d, QListView *parent)
199
 
: QListViewItem (parent)
 
229
DiscoListItem::DiscoListItem(DiscoItem it, DiscoData *_d, Q3ListView *parent)
 
230
: Q3ListViewItem (parent)
200
231
{
201
232
        isRoot = true;
202
233
 
203
234
        init(it, _d);
204
235
}
205
236
 
206
 
DiscoListItem::DiscoListItem(DiscoItem it, DiscoData *_d, QListViewItem *parent)
207
 
: QListViewItem (parent)
 
237
DiscoListItem::DiscoListItem(DiscoItem it, DiscoData *_d, Q3ListViewItem *parent)
 
238
: Q3ListViewItem (parent)
208
239
{
209
240
        isRoot = false;
210
241
 
232
263
                if ( !isRoot )
233
264
                        autoInfo = true;
234
265
        }
235
 
 
236
 
        //setDragEnabled(true); // EXPERIMENTAL
237
266
}
238
267
 
239
268
void DiscoListItem::copyItem(const DiscoItem &it)
244
273
                di.setNode ( it.node() );
245
274
        if ( !(!di.name().isEmpty() && it.name().isEmpty()) )
246
275
                di.setName ( it.name() );
 
276
        
 
277
        if ( di.name().isEmpty() && !di.jid().full().isEmpty() ) // use JID in the Name column
 
278
                di.setName ( di.jid().full() );
247
279
 
248
280
        di.setAction ( it.action() );
249
281
 
283
315
                DiscoItem::Identity id = di.identities().first();
284
316
 
285
317
                if ( !id.category.isEmpty() ) {
286
 
                        Icon ic = category2icon(id.category, id.type);
 
318
                        PsiIcon ic = category2icon(id.category, id.type);
287
319
 
288
320
                        if ( !ic.impix().isNull() ) {
289
 
                                setPixmap (0, ic.impix().pixmap());
 
321
                                setPixmap (0, ic.impix());
290
322
                                pixmapOk = true;
291
323
                        }
292
324
                }
293
325
        }
294
326
 
295
327
        if ( !pixmapOk )
296
 
                setPixmap (0, is->status(di.jid(), STATUS_ONLINE));
 
328
                setPixmap(0, PsiIconset::instance()->status(di.jid(), STATUS_ONLINE).impix());
297
329
 
298
330
        repaint();
299
331
 
304
336
QString DiscoListItem::text (int c) const
305
337
{
306
338
        if (c == 0)
307
 
                return di.name();
 
339
                return di.name().simplified();
308
340
        else if (c == 1)
309
341
                return di.jid().full();
310
342
        else if (c == 2)
311
 
                return di.node();
 
343
                return di.node().simplified();
312
344
        return "";
313
345
}
314
346
 
 
347
QString DiscoListItem::getErrorInfo() const
 
348
{
 
349
        return errorInfo;
 
350
}
 
351
 
315
352
const DiscoItem &DiscoListItem::item() const
316
353
{
317
354
        return di;
319
356
 
320
357
DiscoDlg *DiscoListItem::dlg() const
321
358
{
322
 
        return (DiscoDlg *)listView()->parent()->parent();
 
359
        return (DiscoDlg *)listView()->parent();
323
360
}
324
361
 
325
362
bool DiscoListItem::autoItemsEnabled() const
341
378
                        autoItemsChildren();
342
379
        }
343
380
 
344
 
        QListViewItem::setOpen(o);
 
381
        Q3ListViewItem::setOpen(o);
345
382
}
346
383
 
347
384
void DiscoListItem::itemSelected()
399
436
        }
400
437
        else if ( !autoItems ) {
401
438
                QString error = jt->statusString();
402
 
                QMessageBox::critical(dlg(), tr("Error"), tr("There was an error getting items for <b>%1</b>.\nReason: %2").arg(di.jid().full()).arg(error));
 
439
                QMessageBox::critical(dlg(), tr("Error"), tr("There was an error getting items for <b>%1</b>.<br>Reason: %2").arg(di.jid().full()).arg(QString(error).replace('\n', "<br>")));
403
440
        }
404
441
 
405
442
        alreadyItems = true;
461
498
        }
462
499
        else if ( !autoItems ) {
463
500
                QString error = jt->statusString();
464
 
                QMessageBox::critical(dlg(), tr("Error"), tr("There was an error browsing items for <b>%1</b>.\nReason: %2").arg(di.jid().full()).arg(error));
 
501
                QMessageBox::critical(dlg(), tr("Error"), tr("There was an error browsing items for <b>%1</b>.<br>Reason: %2").arg(di.jid().full()).arg(QString(error).replace('\n', "<br>")));
465
502
        }
466
503
 
467
504
        alreadyItems = true;
525
562
        }
526
563
        else if ( !autoItems ) {
527
564
                QString error = jt->statusString();
528
 
                QMessageBox::critical(dlg(), tr("Error"), tr("There was an error getting agents for <b>%1</b>.\nReason: %2").arg(di.jid().full()).arg(error));
 
565
                QMessageBox::critical(dlg(), tr("Error"), tr("There was an error getting agents for <b>%1</b>.<br>Reason: %2").arg(di.jid().full()).arg(QString(error).replace('\n', "<br>")));
529
566
        }
530
567
 
531
568
        alreadyItems = true;
541
578
 
542
579
void DiscoListItem::updateItemsFinished(const DiscoList &list)
543
580
{
544
 
        QDict<DiscoListItem> children;
 
581
        Q3Dict<DiscoListItem> children;
545
582
        DiscoListItem *child = (DiscoListItem *)firstChild();
546
583
        while ( child ) {
547
584
                children.insert( child->hash(), child );
614
651
        if ( jt->success() ) {
615
652
                updateInfo( jt->item() );
616
653
        }
617
 
        else if ( !autoInfo && d->protocol != DiscoData::Auto ) {
618
 
                QString error = jt->statusString();
619
 
                QMessageBox::critical(dlg(), tr("Error"), tr("There was an error getting item's info for <b>%1</b>.\nReason: %2").arg(di.jid().full()).arg(error));
 
654
        else {
 
655
                QString error_str = jt->statusString();
 
656
                int error_code = jt->statusCode();
 
657
                setExpandable(false);
 
658
 
 
659
                // we change the icon for the items with disco#info returning type=="cancel" || type=="wait" error codes
 
660
                // based on http://www.jabber.org/jeps/jep-0086.html
 
661
 
 
662
                // FIXME: use another method for checking XMPP error-types when Iris will provide one
 
663
                if ( error_code==400 || error_code==404 || error_code==405 || error_code==409 ||
 
664
                     error_code==500 || error_code==501 || error_code==503 || error_code==504 ) {
 
665
                        bool pixmapOk = false;
 
666
                        if ( !di.identities().isEmpty() ) {
 
667
                                DiscoItem::Identity id = di.identities().first();
 
668
                                if ( !id.category.isEmpty() ) {
 
669
                                        PsiIcon ic = category2icon(id.category, id.type, STATUS_ERROR);
 
670
 
 
671
                                        if ( !ic.impix().isNull() ) {
 
672
                                                setPixmap (0, ic.impix());
 
673
                                                pixmapOk = true;
 
674
                                        }
 
675
                                }
 
676
                        }
 
677
                        if ( !pixmapOk )
 
678
                                setPixmap(0, PsiIconset::instance()->status(di.jid(), STATUS_ERROR).impix());
 
679
                } else {
 
680
                        repaint(); //for setExpandable() called earlier
 
681
                }
 
682
 
 
683
                errorInfo=QString("%1").arg(QString(error_str).replace('\n', "<br>"));
 
684
 
 
685
                if ( !autoInfo && d->protocol != DiscoData::Auto ) {    
 
686
                        QMessageBox::critical(dlg(), tr("Error"), tr("There was an error getting item's info for <b>%1</b>.<br>Reason: %2").arg(di.jid().full()).arg(QString(error_str).replace('\n', "<br>")));
 
687
                }
620
688
        }
621
689
 
622
690
        alreadyInfo = true;
635
703
// DiscoList
636
704
//----------------------------------------------------------------------------
637
705
 
638
 
class DiscoListView : public QListView, public QToolTip
 
706
class DiscoListView : public Q3ListView
639
707
{
640
708
        Q_OBJECT
641
709
public:
642
710
        DiscoListView(QWidget *parent);
643
711
 
644
712
protected:
645
 
        void maybeTip(const QPoint &);
646
 
        QDragObject *dragObject();
 
713
        bool maybeTip(const QPoint &);
 
714
 
 
715
        // reimplemented
 
716
        bool eventFilter(QObject* o, QEvent* e);
 
717
        void resizeEvent(QResizeEvent*);
647
718
};
648
719
 
649
720
DiscoListView::DiscoListView(QWidget *parent)
650
 
: QListView(parent), QToolTip(viewport())
 
721
: Q3ListView(parent)
651
722
{
652
723
        addColumn( tr( "Name" ) );
653
724
        addColumn( tr( "JID" ) );
654
725
        addColumn( tr( "Node" ) );
655
 
}
656
 
 
657
 
void DiscoListView::maybeTip(const QPoint &pos)
658
 
{
659
 
        DiscoListItem *i = (DiscoListItem *)itemAt(pos);
 
726
        for (int i = 0; i < 3; i++)
 
727
                setColumnWidthMode(i, Q3ListView::Manual);
 
728
        header()->setStretchEnabled(true, 0);
 
729
}
 
730
 
 
731
void DiscoListView::resizeEvent(QResizeEvent* e)
 
732
{
 
733
        Q3ListView::resizeEvent(e);
 
734
 
 
735
        setColumnWidth(2, header()->fontMetrics().width(columnText(2)) * 2);
 
736
        float remainingWidth = visibleWidth() - columnWidth(2);
 
737
        setColumnWidth(1, int(remainingWidth * 0.3));
 
738
 
 
739
        header()->adjustHeaderSize();
 
740
}
 
741
 
 
742
/**
 
743
 * \param pos should be in global coordinate system.
 
744
 */
 
745
bool DiscoListView::maybeTip(const QPoint &pos)
 
746
{
 
747
        DiscoListItem* i = (DiscoListItem*)itemAt(viewport()->mapFromGlobal(pos));
660
748
        if(!i)
661
 
                return;
 
749
                return false;
662
750
 
663
751
        // NAME <JID> (Node "NODE")
664
752
        //
674
762
        QString text = "<qt><nobr>";
675
763
        DiscoItem item = i->item();
676
764
 
677
 
        if ( !item.name().isEmpty() )
 
765
        if ( item.name()!=item.jid().full() )
678
766
                text += item.name() + " ";
679
767
 
680
768
        text += "&lt;" + item.jid().full() + "&gt;";
682
770
        if ( !item.node().isEmpty() )
683
771
                text += " (" + tr("Node") + " \"" + item.node() + "\")";
684
772
 
685
 
        text += "<nobr>";
 
773
        text += "</nobr>";
686
774
 
687
775
        if ( !item.identities().isEmpty() || !item.features().list().isEmpty() )
688
776
                text += "<br>\n";
694
782
                DiscoItem::Identities::ConstIterator it = item.identities().begin();
695
783
                for ( ; it != item.identities().end(); ++it) {
696
784
                        text += "<br>";
697
 
                        Icon icon( category2icon((*it).category, (*it).type) );
 
785
                        PsiIcon icon( category2icon((*it).category, (*it).type) );
698
786
                        if ( !icon.name().isEmpty() )
699
787
                                text += "<icon name=\"" + icon.name() + "\"> ";
700
788
                        text += (*it).name;
722
810
                }
723
811
        }
724
812
 
 
813
        QString errorInfo=i->getErrorInfo();
 
814
        if ( !errorInfo.isEmpty() ) {
 
815
                text += "<br>\n<br>\n<b>" + tr("Error:") + "</b>\n";
 
816
                text += errorInfo;
 
817
        }
 
818
 
725
819
        text += "</qt>";
726
820
        QRect r( itemRect(i) );
727
 
        tip(r, text);
 
821
        PsiToolTip::showText(pos, text, this);
 
822
        return true;
728
823
}
729
824
 
730
 
QDragObject *DiscoListView::dragObject()
 
825
bool DiscoListView::eventFilter(QObject* o, QEvent* e)
731
826
{
732
 
        DiscoListItem *i = (DiscoListItem *)selectedItem();
733
 
        if(!i)
734
 
                return 0;
735
 
 
736
 
        QDragObject *d = new QTextDrag(i->item().jid().full(), this);
737
 
        d->setPixmap(IconsetFactory::icon("status/online"), QPoint(8,8));
738
 
        return d;
 
827
        if (e->type() == QEvent::ToolTip && o->isWidgetType()) {
 
828
                QWidget*    w  = static_cast<QWidget*>(o);
 
829
                QHelpEvent* he = static_cast<QHelpEvent*>(e);
 
830
                maybeTip(w->mapToGlobal(he->pos()));
 
831
                return true;
 
832
        }
 
833
        return Q3ListView::eventFilter(o, e);
739
834
}
740
835
 
741
836
//----------------------------------------------------------------------------
747
842
        Q_OBJECT
748
843
 
749
844
private:
750
 
        // helper class for use in toolbar
751
 
        class StretchWidget : public QWidget
 
845
        class ProtocolAction : public QAction
752
846
        {
753
847
        public:
754
 
                StretchWidget(QWidget *parent)
755
 
                : QWidget(parent)
 
848
                ProtocolAction(QString text, QString toolTip, QObject *parent, QSignalMapper *sm, int parm)
 
849
                        : QAction(text, parent)
756
850
                {
757
 
                        setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
 
851
                        setText(text);
 
852
                        setIconText(text);
 
853
        
 
854
                        setCheckable(true);
 
855
                        setToolTip(toolTip);
 
856
                        connect(this, SIGNAL(activated()), sm, SLOT(map()));
 
857
                        sm->setMapping(this, parm);
758
858
                }
759
859
        };
760
860
 
761
861
        // helper class to store browser history
762
862
        class History {
763
863
        private:
764
 
                QListViewItem *item;
 
864
                Q3ListViewItem *item;
765
865
        public:
766
 
                History(QListViewItem *it) {
 
866
                History(Q3ListViewItem *it) {
767
867
                        item = it;
768
868
                }
769
869
 
772
872
                                delete item;
773
873
                }
774
874
 
775
 
                QListViewItem *takeItem() {
776
 
                        QListViewItem *i = item;
 
875
                Q3ListViewItem *takeItem() {
 
876
                        Q3ListViewItem *i = item;
777
877
                        item = 0;
778
878
                        return i;
779
879
                }
786
886
 
787
887
        DiscoData data;
788
888
 
789
 
        PsiToolBar *toolBar;
 
889
        QToolBar *toolBar;
790
890
        IconAction *actBrowse, *actBack, *actForward, *actRefresh, *actStop;
791
891
 
792
892
        // custom actions, that will be added to toolbar and context menu
793
 
        IconAction *actRegister, *actSearch, *actJoin, *actVCard, *actAdd;
 
893
        IconAction *actRegister, *actSearch, *actJoin, *actAHCommand, *actVCard, *actAdd;
794
894
 
795
 
        typedef QPtrList<History> HistoryList;
 
895
        typedef Q3PtrList<History> HistoryList;
796
896
        HistoryList backHistory, forwardHistory;
797
897
 
798
898
        BusyWidget *busy;
811
911
        void actionBack();
812
912
        void actionForward();
813
913
        void updateBackForward();
814
 
        void backForwardHelper(QListViewItem *);
 
914
        void backForwardHelper(Q3ListViewItem *);
815
915
 
816
916
        void updateComboBoxes(Jid j, QString node);
817
917
 
821
921
        void disableButtons();
822
922
        void enableButtons(const DiscoItem &);
823
923
 
824
 
        void itemSelected (QListViewItem *);
825
 
        void itemDoubleclicked (QListViewItem *);
 
924
        void itemSelected (Q3ListViewItem *);
 
925
        void itemDoubleclicked (Q3ListViewItem *);
826
926
        bool eventFilter (QObject *, QEvent *);
827
927
 
828
928
        void setProtocol(int);
844
944
        connect(data.tasks, SIGNAL(started()),  SLOT(itemUpdateStarted()));
845
945
        connect(data.tasks, SIGNAL(finished()), SLOT(itemUpdateFinished()));
846
946
        data.d = new DiscoConnector(this);
847
 
        connect(data.d, SIGNAL(itemUpdated(QListViewItem *)), SLOT(itemSelected (QListViewItem *)));
 
947
        connect(data.d, SIGNAL(itemUpdated(Q3ListViewItem *)), SLOT(itemSelected (Q3ListViewItem *)));
848
948
        data.protocol = DiscoData::Auto;
849
949
 
850
950
        backHistory.setAutoDelete(true);
854
954
        busy = parent->busy;
855
955
        connect(busy, SIGNAL(destroyed(QObject *)), SLOT(objectDestroyed(QObject *)));
856
956
 
857
 
        QListView *lv_discoOld = dlg->lv_disco;
858
 
        dlg->lv_disco = new DiscoListView(dlg->centralWidget());
 
957
        Q3ListView *lv_discoOld = dlg->lv_disco;
 
958
        dlg->lv_disco = new DiscoListView(dlg);
859
959
        replaceWidget(lv_discoOld, dlg->lv_disco);
860
960
 
861
961
        dlg->lv_disco->installEventFilter (this);
862
 
        connect(dlg->lv_disco, SIGNAL(selectionChanged (QListViewItem *)), SLOT(itemSelected (QListViewItem *)));;
863
 
        connect(dlg->lv_disco, SIGNAL(doubleClicked (QListViewItem *)),    SLOT(itemDoubleclicked (QListViewItem *)));;
 
962
        connect(dlg->lv_disco, SIGNAL(selectionChanged (Q3ListViewItem *)), SLOT(itemSelected (Q3ListViewItem *)));;
 
963
        connect(dlg->lv_disco, SIGNAL(doubleClicked (Q3ListViewItem *)),    SLOT(itemDoubleclicked (Q3ListViewItem *)));;
864
964
 
865
965
        // protocol actions
866
966
        QSignalMapper *pm = new QSignalMapper(this);
868
968
        QActionGroup *protocolActions = new QActionGroup (this);
869
969
        protocolActions->setExclusive(true);
870
970
 
871
 
        ProtocolAction *autoProtocol = new ProtocolAction (tr("Auto"), tr("Automatically determine protocol"), protocolActions, pm, DiscoData::Auto);
872
 
        ProtocolAction *discoProtocol = new ProtocolAction ("D", tr("Service Discovery"), protocolActions, pm, DiscoData::Disco);
873
 
        ProtocolAction *browseProtocol = new ProtocolAction ("B", tr("Browse Services"), protocolActions, pm, DiscoData::Browse);
874
 
        ProtocolAction *agentsProtocol = new ProtocolAction ("A", tr("Browse Agents"), protocolActions, pm, DiscoData::Agents);
875
 
        autoProtocol->setOn(true);
 
971
        ProtocolAction *autoProtocol = NULL, *discoProtocol = NULL, *browseProtocol = NULL, *agentsProtocol = NULL;
 
972
        if (PsiOptions::instance()->getOption("options.ui.show-deprecated.service-discovery.protocol-selector").toBool()) {
 
973
                autoProtocol = new ProtocolAction (tr("Auto"), tr("Automatically determine protocol"), protocolActions, pm, DiscoData::Auto);
 
974
                discoProtocol = new ProtocolAction ("D", tr("Service Discovery"), protocolActions, pm, DiscoData::Disco);
 
975
                browseProtocol = new ProtocolAction ("B", tr("Browse Services"), protocolActions, pm, DiscoData::Browse);
 
976
                agentsProtocol = new ProtocolAction ("A", tr("Browse Agents"), protocolActions, pm, DiscoData::Agents);
 
977
                autoProtocol->setChecked(true);
 
978
        }
876
979
 
877
980
        // create actions
878
981
        actBrowse = new IconAction (tr("Browse"), "psi/jabber", tr("&Browse"), 0, dlg);
898
1001
        actJoin = new IconAction (tr("Join"), "psi/groupChat", tr("&Join"), 0, dlg);
899
1002
        connect (actJoin, SIGNAL(activated()), sm, SLOT(map()));
900
1003
        sm->setMapping(actJoin, Features::FID_Groupchat);
 
1004
        actAHCommand = new IconAction (tr("Execute command"), "psi/command", tr("&Execute command"), 0, dlg);
 
1005
        connect (actAHCommand, SIGNAL(activated()), sm, SLOT(map()));
 
1006
        sm->setMapping(actAHCommand, Features::FID_AHCommand);
901
1007
        actVCard = new IconAction (tr("vCard"), "psi/vCard", tr("&vCard"), 0, dlg);
902
1008
        connect (actVCard, SIGNAL(activated()), sm, SLOT(map()));
903
1009
        sm->setMapping(actVCard, Features::FID_VCard);
906
1012
        sm->setMapping(actAdd, Features::FID_Add);
907
1013
 
908
1014
        // create toolbar
909
 
        toolBar = new PsiToolBar(dlg);
910
 
        toolBar->setCustomizeable( false );
 
1015
        toolBar = new QToolBar(tr("Service Discovery toolbar"), dlg);
 
1016
        toolBar->setIconSize(QSize(16,16));
 
1017
        toolBar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
 
1018
        replaceWidget(dlg->toolBarPlaceholder, toolBar);
911
1019
 
912
 
        actBack->addTo(toolBar);
913
 
        actBrowse->addTo(toolBar);
914
 
        actForward->addTo(toolBar);
 
1020
        toolBar->addAction(actBack);
 
1021
        toolBar->addAction(actBrowse);
 
1022
        toolBar->addAction(actForward);
915
1023
 
916
1024
        toolBar->addSeparator();
917
 
        actRefresh->addTo(toolBar);
918
 
        actStop->addTo(toolBar);
 
1025
        toolBar->addAction(actRefresh);
 
1026
        toolBar->addAction(actStop);
919
1027
 
920
1028
        // custom actions
921
1029
        toolBar->addSeparator();
922
 
        actRegister->addTo(toolBar);
923
 
        actSearch->addTo(toolBar);
924
 
        actJoin->addTo(toolBar);
 
1030
        toolBar->addAction(actRegister);
 
1031
        toolBar->addAction(actSearch);
 
1032
        toolBar->addAction(actJoin);
 
1033
        toolBar->addAction(actAHCommand);
925
1034
 
926
1035
        toolBar->addSeparator();
927
 
        actAdd->addTo(toolBar);
928
 
        actVCard->addTo(toolBar);
 
1036
        toolBar->addAction(actAdd);
 
1037
        toolBar->addAction(actVCard);
 
1038
        toolBar->addAction(actAHCommand);
929
1039
 
930
1040
        // select protocol
931
 
        toolBar->addSeparator();
932
 
        autoProtocol->addTo(toolBar);
933
 
        discoProtocol->addTo(toolBar);
934
 
        browseProtocol->addTo(toolBar);
935
 
        agentsProtocol->addTo(toolBar);
 
1041
        if (PsiOptions::instance()->getOption("options.ui.show-deprecated.service-discovery.protocol-selector").toBool()) {
 
1042
                toolBar->addSeparator();
 
1043
                toolBar->addAction(autoProtocol);
 
1044
                toolBar->addAction(discoProtocol);
 
1045
                toolBar->addAction(browseProtocol);
 
1046
                toolBar->addAction(agentsProtocol);
 
1047
        }
936
1048
 
937
 
        toolBar->setStretchableWidget(new StretchWidget(toolBar));
938
 
        pa->accountLabel(toolBar, true);
 
1049
        toolBar->addWidget(new StretchWidget(toolBar));
 
1050
        AccountLabel* lb_ident = new AccountLabel(toolBar);
 
1051
        lb_ident->setAccount(pa);
 
1052
        lb_ident->setShowJid(false);
 
1053
        toolBar->addWidget(lb_ident);
939
1054
 
940
1055
        // misc stuff
941
1056
        disableButtons();
969
1084
 
970
1085
        // check, whether we need to update history
971
1086
        if ( (jid.full() != j.full()) || (node != n) ) {
972
 
                QListViewItem *item = dlg->lv_disco->firstChild(); // get the root item
 
1087
                Q3ListViewItem *item = dlg->lv_disco->firstChild(); // get the root item
973
1088
 
974
1089
                if ( item ) {
975
1090
                        dlg->lv_disco->takeItem( item );
1039
1154
void DiscoDlg::Private::actionBack()
1040
1155
{
1041
1156
        // add current selection to forward history
1042
 
        QListViewItem *item = dlg->lv_disco->firstChild();
 
1157
        Q3ListViewItem *item = dlg->lv_disco->firstChild();
1043
1158
        if ( item ) {
1044
1159
                dlg->lv_disco->takeItem( item );
1045
1160
 
1047
1162
        }
1048
1163
 
1049
1164
        // now, take info from back history...
1050
 
        QListViewItem *i = backHistory.last()->takeItem();
 
1165
        Q3ListViewItem *i = backHistory.last()->takeItem();
1051
1166
        backHistory.removeLast();
1052
1167
 
1053
1168
        // and restore view
1057
1172
void DiscoDlg::Private::actionForward()
1058
1173
{
1059
1174
        // add current selection to back history
1060
 
        QListViewItem *item = dlg->lv_disco->firstChild();
 
1175
        Q3ListViewItem *item = dlg->lv_disco->firstChild();
1061
1176
        if ( item ) {
1062
1177
                dlg->lv_disco->takeItem( item );
1063
1178
 
1065
1180
        }
1066
1181
 
1067
1182
        // now, take info from forward history...
1068
 
        QListViewItem *i = forwardHistory.last()->takeItem();
 
1183
        Q3ListViewItem *i = forwardHistory.last()->takeItem();
1069
1184
        forwardHistory.removeLast();
1070
1185
 
1071
1186
        // and restore view
1072
1187
        backForwardHelper(i);
1073
1188
}
1074
1189
 
1075
 
void DiscoDlg::Private::backForwardHelper(QListViewItem *root)
 
1190
void DiscoDlg::Private::backForwardHelper(Q3ListViewItem *root)
1076
1191
{
1077
1192
        DiscoListItem *i = (DiscoListItem *)root;
1078
1193
 
1088
1203
        dlg->lv_disco->insertItem( root );
1089
1204
 
1090
1205
        // fixes multiple selection bug
1091
 
        QListViewItemIterator it( dlg->lv_disco );
 
1206
        Q3ListViewItemIterator it( dlg->lv_disco );
1092
1207
        while ( it.current() ) {
1093
 
                QListViewItem *item = it.current();
 
1208
                Q3ListViewItem *item = it.current();
1094
1209
                ++it;
1095
1210
 
1096
1211
                if ( item->isSelected() )
1138
1253
        actJoin->setEnabled( f.canGroupchat() );
1139
1254
        actAdd->setEnabled( itemSelected );
1140
1255
        actVCard->setEnabled( f.haveVCard() );
 
1256
        actAHCommand->setEnabled( f.canCommand() );
1141
1257
}
1142
1258
 
1143
 
void DiscoDlg::Private::itemSelected (QListViewItem *item)
 
1259
void DiscoDlg::Private::itemSelected (Q3ListViewItem *item)
1144
1260
{
1145
1261
        DiscoListItem *it = (DiscoListItem *)item;
1146
1262
        if ( !it ) {
1154
1270
        enableButtons ( di );
1155
1271
}
1156
1272
 
1157
 
void DiscoDlg::Private::itemDoubleclicked (QListViewItem *item)
 
1273
void DiscoDlg::Private::itemDoubleclicked (Q3ListViewItem *item)
1158
1274
{
1159
1275
        DiscoListItem *it = (DiscoListItem *)item;
1160
1276
        if ( !it )
1165
1281
 
1166
1282
        // set the prior state of item
1167
1283
        // FIXME: causes minor flickering
1168
 
        if ( f.canGroupchat() || f.canRegister() || f.canSearch() ) {
1169
 
                if ( !it->isOpen() ) {
1170
 
                        if ( it->isExpandable() || it->childCount() )
1171
 
                                it->setOpen( true );
1172
 
                }
1173
 
                else {
1174
 
                        it->setOpen( false );
1175
 
                }
1176
 
        }
1177
 
 
1178
1284
        long id = 0;
1179
1285
 
1180
1286
        // trigger default action
1181
 
        if ( f.canGroupchat() ) {
1182
 
                id = Features::FID_Groupchat;
 
1287
        if (f.canCommand() ) {
 
1288
                id = Features::FID_AHCommand;
1183
1289
        }
1184
 
        else {
 
1290
        if (!d.identities().isEmpty()) {
1185
1291
                // FIXME: check the category and type for JUD!
1186
1292
                DiscoItem::Identity ident = d.identities().first();
1187
1293
                bool searchFirst = ident.category == "service" && ident.type == "jud";
1189
1295
                if ( searchFirst && f.canSearch() ) {
1190
1296
                        id = Features::FID_Search;
1191
1297
                }
1192
 
                else {
1193
 
                        if ( f.canRegister() )
 
1298
                else if ( ident.category == "conference" &&  f.canGroupchat() ) {
 
1299
                        id = Features::FID_Groupchat;
 
1300
                }
 
1301
                else if ( f.canRegister() ) {
1194
1302
                                id = Features::FID_Register;
1195
1303
                }
1196
1304
        }
1197
1305
 
1198
 
        if ( id > 0 )
 
1306
        if ( id > 0 ) {
 
1307
                if ( !it->isOpen() ) {
 
1308
                        if ( it->isExpandable() || it->childCount() )
 
1309
                                it->setOpen( true );
 
1310
                }
 
1311
                else {
 
1312
                        it->setOpen( false );
 
1313
                }
1199
1314
                emit dlg->featureActivated( Features::feature(id), d.jid(), d.node() );
 
1315
        }
1200
1316
}
1201
1317
 
1202
1318
bool DiscoDlg::Private::eventFilter (QObject *object, QEvent *event)
1210
1326
                                return true;
1211
1327
 
1212
1328
                        // prepare features list
1213
 
                        QValueList<long> idFeatures;
 
1329
                        QList<long> idFeatures;
1214
1330
                        QStringList features = it->item().features().list();
1215
1331
                        {       // convert all features to their IDs
1216
1332
                                QStringList::Iterator it = features.begin();
1222
1338
                                //qHeapSort(idFeatures);
1223
1339
                        }
1224
1340
 
1225
 
                        QValueList<long> ids;
 
1341
                        QList<long> ids;
1226
1342
                        {       // ensure, that there's in no duplicated IDs inside. FIXME: optimize this, anyone?
1227
1343
                                long id = 0, count = 0;
1228
 
                                QValueList<long>::Iterator it;
 
1344
                                QList<long>::Iterator it;
1229
1345
                                while ( count < (long)idFeatures.count() ) {
1230
1346
                                        bool found = false;
1231
1347
 
1243
1359
                        }
1244
1360
 
1245
1361
                        // prepare popup menu
1246
 
                        QPopupMenu p;
 
1362
                        Q3PopupMenu p;
1247
1363
 
1248
1364
                        actBrowse->addTo (&p);
1249
1365
                        actRefresh->addTo (&p);
1258
1374
                        p.insertSeparator();
1259
1375
                        actAdd->addTo(&p);
1260
1376
                        actVCard->addTo(&p);
 
1377
                        actAHCommand->addTo(&p);
1261
1378
 
1262
1379
                        // popup with all available features
1263
 
                        QPopupMenu *fm = new QPopupMenu(&p);
 
1380
                        Q3PopupMenu *fm = new Q3PopupMenu(&p);
1264
1381
                        {
1265
 
                                QValueList<long>::Iterator it = ids.begin();
 
1382
                                QList<long>::Iterator it = ids.begin();
1266
1383
                                for ( ; it != ids.end(); ++it)
1267
1384
                                        fm->insertItem(Features::name(*it), *it + 10000); // TODO: add pixmap
1268
1385
                        }
1310
1427
//----------------------------------------------------------------------------
1311
1428
 
1312
1429
DiscoDlg::DiscoDlg(PsiAccount *pa, const Jid &jid, const QString &node)
1313
 
: DiscoUI (0, 0, WDestructiveClose)
 
1430
        : QDialog(0)
1314
1431
{
 
1432
        setAttribute(Qt::WA_DeleteOnClose);
 
1433
        setupUi(this);
1315
1434
        // restore options
1316
1435
        ck_autoItems->setChecked(option.discoItems);
1317
1436
        ck_autoInfo->setChecked(option.discoInfo);
1321
1440
        d->jid  = jid;
1322
1441
        d->node = node;
1323
1442
 
1324
 
        setCaption(CAP(caption()));
1325
 
        setIcon(is->transportStatus("transport", STATUS_ONLINE));
 
1443
        setWindowTitle(CAP(caption()));
 
1444
        setWindowIcon(PsiIconset::instance()->transportStatus("transport", STATUS_ONLINE).icon());
1326
1445
        X11WM_CLASS("disco");
1327
1446
 
1328
 
        statusBar()->hide();
1329
 
 
1330
 
        pb_browse->setDefault(true);
1331
1447
        connect (pb_browse, SIGNAL(clicked()), d, SLOT(doDisco()));
1332
 
 
1333
 
 
1334
 
        cb_address->setInsertionPolicy(QComboBox::NoInsertion);
 
1448
        pb_browse->setDefault(false);
 
1449
        pb_browse->setAutoDefault(false);
 
1450
 
 
1451
        connect(pb_close, SIGNAL(clicked()), this, SLOT(close()));
 
1452
        pb_close->setDefault(false);
 
1453
        pb_close->setAutoDefault(false);
 
1454
 
1335
1455
        cb_address->insertStringList(pa->psi()->recentBrowseList()); // FIXME
1336
1456
        cb_address->setFocus();
1337
1457
        connect(cb_address, SIGNAL(activated(const QString &)), d, SLOT(doDisco()));
1338
1458
        cb_address->setCurrentText(d->jid.full());
1339
1459
 
1340
 
        cb_node->setInsertionPolicy(QComboBox::NoInsertion);
1341
1460
        cb_node->insertStringList(pa->psi()->recentNodeList());
1342
1461
        connect(cb_node, SIGNAL(activated(const QString &)), d, SLOT(doDisco()));
1343
1462
        cb_node->setCurrentText(node);