source: psi/trunk/src/options/optionsdlg.cpp@ 172

Last change on this file since 172 was 2, checked in by dmik, 19 years ago

Imported original Psi 0.10 sources from Affinix

File size: 15.2 KB
Line 
1#include "optionsdlg.h"
2#include "optionstab.h"
3#include "common.h"
4#include "psicon.h"
5#include "fancylabel.h"
6#include "iconwidget.h"
7
8#include <qlayout.h>
9#include <qlabel.h>
10#include <qlistview.h>
11#include <qwidgetstack.h>
12#include <qheader.h>
13#include <qobjectlist.h>
14#include <qpen.h>
15#include <qpainter.h>
16
17// tabs
18#include "opt_application.h"
19#include "opt_appearance.h"
20#include "opt_chat.h"
21#include "opt_events.h"
22#include "opt_status.h"
23#include "opt_iconset.h"
24#include "opt_groupchat.h"
25#include "opt_sound.h"
26#include "opt_advanced.h"
27
28#include "opt_lookfeel.h"
29
30//----------------------------------------------------------------------------
31// FancyItem
32//----------------------------------------------------------------------------
33
34class FancyItem : public QListViewItem
35{
36public:
37 FancyItem(QListView *, QListViewItem *after);
38
39 void setup();
40 int width(const QFontMetrics &, const QListView *lv, int c) const;
41 void paintFocus(QPainter *, const QColorGroup &, const QRect &);
42 void paintCell(QPainter *p, const QColorGroup &, int c, int width, int align);
43};
44
45FancyItem::FancyItem(QListView *lv, QListViewItem *after)
46: QListViewItem(lv, after)
47{
48}
49
50void FancyItem::setup()
51{
52 QListView *lv = listView();
53 int ph = 0;
54 for(int i = 0; i < lv->columns(); ++i) {
55 if(pixmap(i))
56 ph = QMAX(ph, pixmap(i)->height());
57 }
58 int y = QMAX(ph, lv->fontMetrics().height());
59 y += 8;
60 setHeight(y);
61}
62
63int FancyItem::width(const QFontMetrics &fm, const QListView *, int c) const
64{
65 int x = 0;
66 const QPixmap *pix = pixmap(c);
67 if(pix)
68 x += pix->width();
69 else
70 x += 16;
71 x += 8;
72 x += fm.width(text(c));
73 x += 8;
74 return x;
75}
76
77void FancyItem::paintFocus(QPainter *, const QColorGroup &, const QRect &)
78{
79 // re-implimented to do nothing. selection is enough of a focus
80}
81
82void FancyItem::paintCell(QPainter *p, const QColorGroup &cg, int c, int w, int)
83{
84 int h = height();
85 QFontMetrics fm(p->font());
86 if(isSelected())
87 p->fillRect(0, 0, w, h-1, cg.highlight());
88 else
89 p->fillRect(0, 0, w, h, cg.base());
90
91 int x = 0;
92 const QPixmap *pix = pixmap(c);
93 if(pix) {
94 p->drawPixmap(4, (h - pix->height()) / 2, *pix);
95 x += pix->width();
96 }
97 else
98 x += 16;
99 x += 8;
100 int y = ((h - fm.height()) / 2) + fm.ascent();
101 p->setPen(isSelected() ? cg.highlightedText() : cg.text());
102 p->drawText(x, y, text(c));
103
104 p->setPen(QPen(QColor(0xE0, 0xE0, 0xE0), 0, DotLine));
105 p->drawLine(0, h-1, w-1, h-1);
106}
107
108//----------------------------------------------------------------------------
109// OptionsTabBase
110//----------------------------------------------------------------------------
111
112//class OptionsTabBase : public OptionsTab
113//{
114// Q_OBJECT
115//public:
116// OptionsTabBase(QObject *parent, QCString id, QCString parentId, QString iconName, QString name, QString desc)
117// : OptionsTab(parent, id, parentId, name, desc, iconName)
118// {
119// w = new QWidget();
120// QGridLayout *layout = new QGridLayout(w, 0, 2, 0, 5);
121// layout->setAutoAdd(true);
122// }
123// ~OptionsTabBase()
124// {
125// w->deleteLater();
126// }
127//
128// QWidget *widget() { return w; }
129//
130//public slots:
131// void tabAdded(OptionsTab *tab);
132//
133//private:
134// QWidget *w;
135//};
136//
137//void OptionsTabBase::tabAdded(OptionsTab *tab)
138//{
139// //qWarning("OptionsTabBase::tabAdded(): id = %s, tab_id = %s", (const char *)id(), (const char *)tab->id());
140// QLabel *name = new QLabel(w);
141// name->setText("<b>" + tab->name() + "</b>");
142// name->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
143//
144// IconLabel *desc = new IconLabel(w);
145// desc->setText(tab->desc());
146// desc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
147//}
148
149//----------------------------------------------------------------------------
150// OptionsDlg::Private
151//----------------------------------------------------------------------------
152
153class OptionsDlg::Private : public QObject
154{
155 Q_OBJECT
156public:
157 Private(OptionsDlg *dlg, PsiCon *_psi, const Options &_opt);
158
159public slots:
160 void doApply();
161
162private slots:
163 void itemSelected(QListViewItem *);
164 void openTab(QString id);
165 void dataChanged();
166 void noDirtySlot(bool);
167 void createTabs();
168 void createChangedMap();
169
170 //void addWidgetChangedSignal(QString widgetName, QCString signal);
171 void connectDataChanged(QWidget *);
172
173public:
174 OptionsDlg *dlg;
175 PsiCon *psi;
176 Options opt;
177 bool dirty, noDirty;
178 QDict<QWidget> id2widget;
179 QPtrList<OptionsTab> tabs;
180
181 QMap<QString, QCString> changedMap;
182};
183
184OptionsDlg::Private::Private(OptionsDlg *d, PsiCon *_psi, const Options &_opt)
185{
186 dlg = d;
187 psi = _psi;
188 opt = _opt; // option
189 noDirty = false;
190 dirty = false;
191
192 dlg->lb_pageTitle->setScaledContents(32, 32);
193
194 dlg->lv_tabs->setSorting( -1 );
195 dlg->lv_tabs->header()->hide();
196 connect(dlg->lv_tabs, SIGNAL(selectionChanged(QListViewItem *)), SLOT(itemSelected(QListViewItem *)));
197
198 createTabs();
199 createChangedMap();
200
201 // fill the QListView
202 QPtrListIterator<OptionsTab> it ( tabs );
203 OptionsTab *opttab;
204 for ( ; it.current(); ++it) {
205 opttab = it.current();
206 //qWarning("Adding tab %s...", (const char *)opttab->id());
207 opttab->setData(psi, dlg);
208 connect(opttab, SIGNAL(dataChanged()), SLOT(dataChanged()));
209 //connect(opttab, SIGNAL(addWidgetChangedSignal(QString, QCString)), SLOT(addWidgetChangedSignal(QString, QCString)));
210 connect(opttab, SIGNAL(noDirty(bool)), SLOT(noDirtySlot(bool)));
211 connect(opttab, SIGNAL(connectDataChanged(QWidget *)), SLOT(connectDataChanged(QWidget *)));
212
213 // search for parent
214 QListViewItem *parent = 0, *prev = 0;
215 QString parentId = opttab->parentId();
216 if ( !parentId.isEmpty() ) {
217 QListViewItemIterator it2( dlg->lv_tabs );
218 for ( ; it2.current(); ++it2) {
219 //qWarning("Searching the QListView %s...", it2.current()->text(1).latin1());
220 if ( it2.current()->text(1) == parentId ) {
221 //qWarning("...done");
222 parent = it2.current();
223
224 // notify the parent about the child
225 QPtrListIterator<OptionsTab> it3 ( tabs );
226 OptionsTab *opttab2;
227 for ( ; it3.current(); ++it3) {
228 opttab2 = it3.current();
229 //qWarning("Searching tabs %s...", (const char *)opttab2->id());
230 if ( opttab2->id() == opttab->parentId() ) {
231 //qWarning("...done");
232 opttab2->tabAdded( opttab );
233 break;
234 }
235 }
236
237 parent->setOpen( true );
238 break;
239 }
240 }
241 }
242 //qWarning("****************");
243
244 // search for previous item
245 QListViewItem *top;
246 if ( parent )
247 top = parent->firstChild();
248 else
249 top = dlg->lv_tabs->firstChild();
250 prev = top;
251 while ( prev ) {
252 if ( !prev->nextSibling() )
253 break;
254 prev = prev->nextSibling();
255 }
256
257 if ( opttab->id().isEmpty() )
258 continue;
259
260 // create tab
261 QListViewItem *item;
262 //if ( parent )
263 // item = new FancyItem(parent, prev);
264 //else
265 item = new FancyItem(dlg->lv_tabs, prev);
266
267 item->setText(0, opttab->tabName());
268 if ( opttab->tabIcon() )
269 item->setPixmap(0, opttab->tabIcon()->impix().pixmap());
270 item->setText(1, opttab->id());
271
272 // create separator
273 //if ( !parent ) {
274 // new ListItemSeparator(dlg->lv_tabs, item);
275 //}
276 }
277
278 // fix the width of the listview based on the largest item
279 int largestWidth = 0;
280 QFontMetrics fm(dlg->lv_tabs->font());
281 for(QListViewItem *i = dlg->lv_tabs->firstChild(); i; i = i->nextSibling())
282 largestWidth = QMAX(largestWidth, i->width(fm, dlg->lv_tabs, 0));
283 dlg->lv_tabs->setFixedWidth(largestWidth + 32);
284
285 openTab( "application" );
286
287 dirty = false;
288 dlg->pb_apply->setEnabled(false);
289}
290
291void OptionsDlg::Private::createTabs()
292{
293 // tabs - base
294 /*tabs.append( new OptionsTabGeneral(this) );
295 //tabs.append( new OptionsTabBase(this, "general", "", "psi/psi16", tr("General"), tr("General preferences list")) );
296 tabs.append( new OptionsTabEvents(this) );
297 //tabs.append( new OptionsTabBase(this, "events", "", "psi/system", tr("Events"), tr("Change the events behaviour")) );
298 tabs.append( new OptionsTabPresence(this) );
299 //tabs.append( new OptionsTabBase(this, "presence", "", "status/online", tr("Presence"), tr("Presence configuration")) );
300 tabs.append( new OptionsTabLookFeel(this) );
301 tabs.append( new OptionsTabIconset(this) );
302 //tabs.append( new OptionsTabBase(this, "lookfeel", "", "psi/smile", tr("Look and Feel"), tr("Change the Psi's Look and Feel")) );
303 tabs.append( new OptionsTabSound(this) );
304 //tabs.append( new OptionsTabBase(this, "sound", "", "psi/playSounds", tr("Sound"), tr("Configure how Psi sounds")) );
305 */
306
307 tabs.append( new OptionsTabApplication(this) );
308 tabs.append( new OptionsTabChat(this) );
309 tabs.append( new OptionsTabEvents(this) );
310 tabs.append( new OptionsTabStatus(this) );
311 tabs.append( new OptionsTabAppearance(this) );
312 //tabs.append( new OptionsTabIconsetSystem(this) );
313 //tabs.append( new OptionsTabIconsetRoster(this) );
314 //tabs.append( new OptionsTabIconsetEmoticons(this) );
315 tabs.append( new OptionsTabGroupchat(this) );
316 tabs.append( new OptionsTabSound(this) );
317 tabs.append( new OptionsTabAdvanced(this) );
318
319 tabs.append( new OptionsTabLookFeelToolbars(this) ); // it needs to be there, otherwise toolbar options would not be saved correctly in all cases
320
321 // tabs - general
322 /*tabs.append( new OptionsTabGeneralRoster(this) );
323 tabs.append( new OptionsTabGeneralDocking(this) );
324 tabs.append( new OptionsTabGeneralNotifications(this) );
325 tabs.append( new OptionsTabGeneralGroupchat(this) );
326 tabs.append( new OptionsTabGeneralMisc(this) );*/
327
328 // tabs - events
329 /*tabs.append( new OptionsTabEventsReceive(this) );
330 tabs.append( new OptionsTabEventsMisc(this) );*/
331
332 // tabs - presence
333 /*tabs.append( new OptionsTabPresenceAuto(this) );
334 tabs.append( new OptionsTabPresencePresets(this) );
335 tabs.append( new OptionsTabPresenceMisc(this) );*/
336
337 // tabs - look and feel
338 /*tabs.append( new OptionsTabLookFeelColors(this) );
339 tabs.append( new OptionsTabLookFeelFonts(this) );
340 tabs.append( new OptionsTabIconsetSystem(this) );
341 tabs.append( new OptionsTabIconsetEmoticons(this) );
342 tabs.append( new OptionsTabIconsetRoster(this) );
343 tabs.append( new OptionsTabLookFeelToolbars(this) );
344 tabs.append( new OptionsTabLookFeelMisc(this) );*/
345
346 // tabs - sound
347 /*tabs.append( new OptionsTabSoundPrefs(this) );
348 tabs.append( new OptionsTabSoundEvents(this) );*/
349}
350
351void OptionsDlg::Private::createChangedMap()
352{
353 // NOTE about commented out signals:
354 // Do NOT call addWidgetChangedSignal() for them.
355 // Instead, connect the widget's signal to your tab own dataChaged() signal
356 changedMap.insert("QButton", SIGNAL(stateChanged(int)));
357 changedMap.insert("QCheckBox", SIGNAL(stateChanged(int)));
358 changedMap.insert("QPushButton", SIGNAL(stateChanged(int)));
359 changedMap.insert("QRadioButton", SIGNAL(stateChanged(int)));
360 changedMap.insert("QComboBox", SIGNAL(activated (int)));
361 //changedMap.insert("QComboBox", SIGNAL(textChanged(const QString &)));
362 changedMap.insert("QDateEdit", SIGNAL(valueChanged(const QDate &)));
363 changedMap.insert("QDateTimeEdit", SIGNAL(valueChanged(const QDateTime &)));
364 changedMap.insert("QDial", SIGNAL(valueChanged (int)));
365 changedMap.insert("QLineEdit", SIGNAL(textChanged(const QString &)));
366 changedMap.insert("QSlider", SIGNAL(valueChanged(int)));
367 changedMap.insert("QSpinBox", SIGNAL(valueChanged(int)));
368 changedMap.insert("QTimeEdit", SIGNAL(valueChanged(const QTime &)));
369 changedMap.insert("QTextEdit", SIGNAL(textChanged()));
370 changedMap.insert("QTextBrowser", SIGNAL(sourceChanged(const QString &)));
371 changedMap.insert("QMultiLineEdit", SIGNAL(textChanged()));
372 //changedMap.insert("QListBox", SIGNAL(selectionChanged()));
373 //changedMap.insert("QTabWidget", SIGNAL(currentChanged(QWidget *)));
374}
375
376//void OptionsDlg::Private::addWidgetChangedSignal(QString widgetName, QCString signal)
377//{
378// changedMap.insert(widgetName, signal);
379//}
380
381void OptionsDlg::Private::openTab(QString id)
382{
383 if ( id.isEmpty() )
384 return;
385
386 QWidget *tab = id2widget[id];
387 if ( !tab ) {
388 bool found = false;
389 QPtrListIterator<OptionsTab> it ( tabs );
390 OptionsTab *opttab;
391 for ( ; it.current(); ++it) {
392 opttab = it.current();
393
394 if ( opttab->id() == id.latin1() ) {
395 tab = opttab->widget(); // create the widget
396 if ( !tab )
397 continue;
398
399 // TODO: how about QScrollView for large tabs?
400 // idea: maybe do it only for those, whose sizeHint is bigger than ws_tabs'
401 QWidget *w = new QWidget(dlg->ws_tabs, "QWidgetStack/tab");
402 QVBoxLayout *vbox = new QVBoxLayout(w);
403
404 /*FancyLabel *toplbl = new FancyLabel(w, "QWidgetStack/tab/FancyLabel");
405 toplbl->setText( opttab->name() );
406 toplbl->setHelp( opttab->desc() );
407 toplbl->setIcon( opttab->icon() );
408 vbox->addWidget( toplbl );
409 vbox->addSpacing( 5 );*/
410
411 tab->reparent(w, 0, QPoint(0, 0));
412 vbox->addWidget(tab);
413 if ( !opttab->stretchable() )
414 vbox->addStretch();
415
416 dlg->ws_tabs->addWidget(w);
417 id2widget.insert( id, w );
418 connectDataChanged( tab ); // no need to connect to dataChanged() slot by hands anymore
419
420 bool d = dirty;
421
422 opttab->restoreOptions( &opt ); // initialize widgets' values
423
424 dirty = d;
425 dlg->pb_apply->setEnabled( dirty );
426
427 tab = w;
428 found = true;
429 break;
430 }
431 }
432
433 if ( !found ) {
434 qWarning("OptionsDlg::Private::itemSelected(): could not create widget for id '%s'", id.latin1());
435 return;
436 }
437 }
438
439 {
440 QPtrListIterator<OptionsTab> it ( tabs );
441 OptionsTab *opttab;
442 for ( ; it.current(); ++it) {
443 opttab = it.current();
444
445 if ( opttab->id() == id.latin1() ) {
446 dlg->lb_pageTitle->setText( opttab->name() );
447 dlg->lb_pageTitle->setHelp( opttab->desc() );
448 dlg->lb_pageTitle->setIcon( opttab->icon() );
449
450 break;
451 }
452 }
453 }
454
455 dlg->ws_tabs->raiseWidget( tab );
456
457 // and select item in lv_tabs...
458 QListViewItemIterator it( dlg->lv_tabs );
459 while ( it.current() ) {
460 it.current()->setSelected( it.current()->text(1) == id );
461 ++it;
462 }
463}
464
465void OptionsDlg::Private::connectDataChanged(QWidget *widget)
466{
467 QObjectList *l = widget->queryList( "QWidget", 0, false, true ); // search for all QWidget children of widget
468 QObjectListIterator it( *l );
469
470 for ( ; it.current(); ++it) {
471 QWidget *w = (QWidget *)it.current();
472
473 QMap<QString, QCString>::Iterator it2 = changedMap.find( w->className() );
474 if ( it2 != changedMap.end() ) {
475 disconnect(w, changedMap[w->className()], this, SLOT(dataChanged()));
476 connect(w, changedMap[w->className()], SLOT(dataChanged()));
477 }
478 }
479
480 delete l;
481}
482
483void OptionsDlg::Private::itemSelected(QListViewItem *item)
484{
485 if ( !item )
486 return;
487
488 openTab( item->text(1) );
489}
490
491void OptionsDlg::Private::dataChanged()
492{
493 if ( dirty )
494 return;
495
496 if ( !noDirty ) {
497 dirty = true;
498 dlg->pb_apply->setEnabled(true);
499 }
500}
501
502void OptionsDlg::Private::noDirtySlot(bool d)
503{
504 noDirty = d;
505}
506
507void OptionsDlg::Private::doApply()
508{
509 if ( !dirty )
510 return;
511
512 QPtrListIterator<OptionsTab> it ( tabs );
513 OptionsTab *opttab;
514 for ( ; it.current(); ++it) {
515 opttab = it.current();
516
517 opttab->applyOptions( &opt );
518 }
519
520 emit dlg->applyOptions( opt );
521
522 dirty = false;
523 dlg->pb_apply->setEnabled(false);
524}
525
526//----------------------------------------------------------------------------
527// OptionsDlg
528//----------------------------------------------------------------------------
529
530OptionsDlg::OptionsDlg(PsiCon *psi, const Options &opt, QWidget *parent, const char *name)
531: OptionsUI(parent, name, false, WDestructiveClose)
532{
533 d = new Private(this, psi, opt);
534 d->psi->dialogRegister(this);
535
536 setCaption(CAP(caption()));
537 resize(640, 480);
538}
539
540OptionsDlg::~OptionsDlg()
541{
542 d->psi->dialogUnregister(this);
543 delete d;
544}
545
546void OptionsDlg::doOk()
547{
548 doApply();
549 accept();
550}
551
552void OptionsDlg::doApply()
553{
554 d->doApply();
555}
556
557#include "optionsdlg.moc"
Note: See TracBrowser for help on using the repository browser.