]> git.sur5r.net Git - kconfig-frontends/blob - frontends/qconf/qconf.cc
libs/images: fix warnings
[kconfig-frontends] / frontends / qconf / qconf.cc
1 /*
2  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
3  * Released under the terms of the GNU GPL v2.0.
4  */
5
6 #include <qglobal.h>
7
8 #if QT_VERSION < 0x040000
9 #include <qmainwindow.h>
10 #include <qvbox.h>
11 #include <qvaluelist.h>
12 #include <qtextbrowser.h>
13 #include <qaction.h>
14 #include <qheader.h>
15 #include <qfiledialog.h>
16 #include <qdragobject.h>
17 #include <qpopupmenu.h>
18 #else
19 #include <q3mainwindow.h>
20 #include <q3vbox.h>
21 #include <q3valuelist.h>
22 #include <q3textbrowser.h>
23 #include <q3action.h>
24 #include <q3header.h>
25 #include <q3filedialog.h>
26 #include <q3dragobject.h>
27 #include <q3popupmenu.h>
28 #endif
29
30 #include <qapplication.h>
31 #include <qdesktopwidget.h>
32 #include <qtoolbar.h>
33 #include <qlayout.h>
34 #include <qsplitter.h>
35 #include <qlineedit.h>
36 #include <qlabel.h>
37 #include <qpushbutton.h>
38 #include <qmenubar.h>
39 #include <qmessagebox.h>
40 #include <qregexp.h>
41 #include <qevent.h>
42
43 #include <stdlib.h>
44
45 #include "lkc.h"
46 #include "qconf.h"
47
48 #include "qconf.moc"
49 #define WANTS_xpm_symbol_yes
50 #define WANTS_xpm_symbol_mod
51 #define WANTS_xpm_symbol_no
52 #define WANTS_xpm_choice_yes
53 #define WANTS_xpm_choice_no
54 #define WANTS_xpm_menu
55 #define WANTS_xpm_menu_inv
56 #define WANTS_xpm_menuback
57 #define WANTS_xpm_void
58 #define WANTS_xpm_back
59 #define WANTS_xpm_load
60 #define WANTS_xpm_save
61 #define WANTS_xpm_single_view
62 #define WANTS_xpm_split_view
63 #define WANTS_xpm_tree_view
64 #include "images.h"
65
66 #ifdef _
67 # undef _
68 # define _ qgettext
69 #endif
70
71 static QApplication *configApp;
72 static ConfigSettings *configSettings;
73
74 Q3Action *ConfigMainWindow::saveAction;
75
76 static inline QString qgettext(const char* str)
77 {
78         return QString::fromLocal8Bit(gettext(str));
79 }
80
81 static inline QString qgettext(const QString& str)
82 {
83         return QString::fromLocal8Bit(gettext(str.latin1()));
84 }
85
86 /**
87  * Reads a list of integer values from the application settings.
88  */
89 Q3ValueList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
90 {
91         Q3ValueList<int> result;
92         QStringList entryList = readListEntry(key, ok);
93         QStringList::Iterator it;
94
95         for (it = entryList.begin(); it != entryList.end(); ++it)
96                 result.push_back((*it).toInt());
97
98         return result;
99 }
100
101 /**
102  * Writes a list of integer values to the application settings.
103  */
104 bool ConfigSettings::writeSizes(const QString& key, const Q3ValueList<int>& value)
105 {
106         QStringList stringList;
107         Q3ValueList<int>::ConstIterator it;
108
109         for (it = value.begin(); it != value.end(); ++it)
110                 stringList.push_back(QString::number(*it));
111         return writeEntry(key, stringList);
112 }
113
114
115 /*
116  * set the new data
117  * TODO check the value
118  */
119 void ConfigItem::okRename(int col)
120 {
121         Parent::okRename(col);
122         sym_set_string_value(menu->sym, text(dataColIdx).latin1());
123         listView()->updateList(this);
124 }
125
126 /*
127  * update the displayed of a menu entry
128  */
129 void ConfigItem::updateMenu(void)
130 {
131         ConfigList* list;
132         struct symbol* sym;
133         struct property *prop;
134         QString prompt;
135         int type;
136         tristate expr;
137
138         list = listView();
139         if (goParent) {
140                 setPixmap(promptColIdx, list->menuBackPix);
141                 prompt = "..";
142                 goto set_prompt;
143         }
144
145         sym = menu->sym;
146         prop = menu->prompt;
147         prompt = _(menu_get_prompt(menu));
148
149         if (prop) switch (prop->type) {
150         case P_MENU:
151                 if (list->mode == singleMode || list->mode == symbolMode) {
152                         /* a menuconfig entry is displayed differently
153                          * depending whether it's at the view root or a child.
154                          */
155                         if (sym && list->rootEntry == menu)
156                                 break;
157                         setPixmap(promptColIdx, list->menuPix);
158                 } else {
159                         if (sym)
160                                 break;
161                         setPixmap(promptColIdx, 0);
162                 }
163                 goto set_prompt;
164         case P_COMMENT:
165                 setPixmap(promptColIdx, 0);
166                 goto set_prompt;
167         default:
168                 ;
169         }
170         if (!sym)
171                 goto set_prompt;
172
173         setText(nameColIdx, QString::fromLocal8Bit(sym->name));
174
175         type = sym_get_type(sym);
176         switch (type) {
177         case S_BOOLEAN:
178         case S_TRISTATE:
179                 char ch;
180
181                 if (!sym_is_changable(sym) && list->optMode == normalOpt) {
182                         setPixmap(promptColIdx, 0);
183                         setText(noColIdx, QString::null);
184                         setText(modColIdx, QString::null);
185                         setText(yesColIdx, QString::null);
186                         break;
187                 }
188                 expr = sym_get_tristate_value(sym);
189                 switch (expr) {
190                 case yes:
191                         if (sym_is_choice_value(sym) && type == S_BOOLEAN)
192                                 setPixmap(promptColIdx, list->choiceYesPix);
193                         else
194                                 setPixmap(promptColIdx, list->symbolYesPix);
195                         setText(yesColIdx, "Y");
196                         ch = 'Y';
197                         break;
198                 case mod:
199                         setPixmap(promptColIdx, list->symbolModPix);
200                         setText(modColIdx, "M");
201                         ch = 'M';
202                         break;
203                 default:
204                         if (sym_is_choice_value(sym) && type == S_BOOLEAN)
205                                 setPixmap(promptColIdx, list->choiceNoPix);
206                         else
207                                 setPixmap(promptColIdx, list->symbolNoPix);
208                         setText(noColIdx, "N");
209                         ch = 'N';
210                         break;
211                 }
212                 if (expr != no)
213                         setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0);
214                 if (expr != mod)
215                         setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0);
216                 if (expr != yes)
217                         setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0);
218
219                 setText(dataColIdx, QChar(ch));
220                 break;
221         case S_INT:
222         case S_HEX:
223         case S_STRING:
224                 const char* data;
225
226                 data = sym_get_string_value(sym);
227
228                 int i = list->mapIdx(dataColIdx);
229                 if (i >= 0)
230                         setRenameEnabled(i, TRUE);
231                 setText(dataColIdx, data);
232                 if (type == S_STRING)
233                         prompt = QString("%1: %2").arg(prompt).arg(data);
234                 else
235                         prompt = QString("(%2) %1").arg(prompt).arg(data);
236                 break;
237         }
238         if (!sym_has_value(sym) && visible)
239                 prompt += _(" (NEW)");
240 set_prompt:
241         setText(promptColIdx, prompt);
242 }
243
244 void ConfigItem::testUpdateMenu(bool v)
245 {
246         ConfigItem* i;
247
248         visible = v;
249         if (!menu)
250                 return;
251
252         sym_calc_value(menu->sym);
253         if (menu->flags & MENU_CHANGED) {
254                 /* the menu entry changed, so update all list items */
255                 menu->flags &= ~MENU_CHANGED;
256                 for (i = (ConfigItem*)menu->data; i; i = i->nextItem)
257                         i->updateMenu();
258         } else if (listView()->updateAll)
259                 updateMenu();
260 }
261
262 void ConfigItem::paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align)
263 {
264         ConfigList* list = listView();
265
266         if (visible) {
267                 if (isSelected() && !list->hasFocus() && list->mode == menuMode)
268                         Parent::paintCell(p, list->inactivedColorGroup, column, width, align);
269                 else
270                         Parent::paintCell(p, cg, column, width, align);
271         } else
272                 Parent::paintCell(p, list->disabledColorGroup, column, width, align);
273 }
274
275 /*
276  * construct a menu entry
277  */
278 void ConfigItem::init(void)
279 {
280         if (menu) {
281                 ConfigList* list = listView();
282                 nextItem = (ConfigItem*)menu->data;
283                 menu->data = this;
284
285                 if (list->mode != fullMode)
286                         setOpen(TRUE);
287                 sym_calc_value(menu->sym);
288         }
289         updateMenu();
290 }
291
292 /*
293  * destruct a menu entry
294  */
295 ConfigItem::~ConfigItem(void)
296 {
297         if (menu) {
298                 ConfigItem** ip = (ConfigItem**)&menu->data;
299                 for (; *ip; ip = &(*ip)->nextItem) {
300                         if (*ip == this) {
301                                 *ip = nextItem;
302                                 break;
303                         }
304                 }
305         }
306 }
307
308 ConfigLineEdit::ConfigLineEdit(ConfigView* parent)
309         : Parent(parent)
310 {
311         connect(this, SIGNAL(lostFocus()), SLOT(hide()));
312 }
313
314 void ConfigLineEdit::show(ConfigItem* i)
315 {
316         item = i;
317         if (sym_get_string_value(item->menu->sym))
318                 setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym)));
319         else
320                 setText(QString::null);
321         Parent::show();
322         setFocus();
323 }
324
325 void ConfigLineEdit::keyPressEvent(QKeyEvent* e)
326 {
327         switch (e->key()) {
328         case Qt::Key_Escape:
329                 break;
330         case Qt::Key_Return:
331         case Qt::Key_Enter:
332                 sym_set_string_value(item->menu->sym, text().latin1());
333                 parent()->updateList(item);
334                 break;
335         default:
336                 Parent::keyPressEvent(e);
337                 return;
338         }
339         e->accept();
340         parent()->list->setFocus();
341         hide();
342 }
343
344 ConfigList::ConfigList(ConfigView* p, const char *name)
345         : Parent(p, name),
346           updateAll(false),
347           symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no),
348           choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no),
349           menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void),
350           showName(false), showRange(false), showData(false), optMode(normalOpt),
351           rootEntry(0), headerPopup(0)
352 {
353         int i;
354
355         setSorting(-1);
356         setRootIsDecorated(TRUE);
357         disabledColorGroup = palette().active();
358         disabledColorGroup.setColor(QColorGroup::Text, palette().disabled().text());
359         inactivedColorGroup = palette().active();
360         inactivedColorGroup.setColor(QColorGroup::Highlight, palette().disabled().highlight());
361
362         connect(this, SIGNAL(selectionChanged(void)),
363                 SLOT(updateSelection(void)));
364
365         if (name) {
366                 configSettings->beginGroup(name);
367                 showName = configSettings->readBoolEntry("/showName", false);
368                 showRange = configSettings->readBoolEntry("/showRange", false);
369                 showData = configSettings->readBoolEntry("/showData", false);
370                 optMode = (enum optionMode)configSettings->readNumEntry("/optionMode", false);
371                 configSettings->endGroup();
372                 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
373         }
374
375         for (i = 0; i < colNr; i++)
376                 colMap[i] = colRevMap[i] = -1;
377         addColumn(promptColIdx, _("Option"));
378
379         reinit();
380 }
381
382 bool ConfigList::menuSkip(struct menu *menu)
383 {
384         if (optMode == normalOpt && menu_is_visible(menu))
385                 return false;
386         if (optMode == promptOpt && menu_has_prompt(menu))
387                 return false;
388         if (optMode == allOpt)
389                 return false;
390         return true;
391 }
392
393 void ConfigList::reinit(void)
394 {
395         removeColumn(dataColIdx);
396         removeColumn(yesColIdx);
397         removeColumn(modColIdx);
398         removeColumn(noColIdx);
399         removeColumn(nameColIdx);
400
401         if (showName)
402                 addColumn(nameColIdx, _("Name"));
403         if (showRange) {
404                 addColumn(noColIdx, "N");
405                 addColumn(modColIdx, "M");
406                 addColumn(yesColIdx, "Y");
407         }
408         if (showData)
409                 addColumn(dataColIdx, _("Value"));
410
411         updateListAll();
412 }
413
414 void ConfigList::saveSettings(void)
415 {
416         if (name()) {
417                 configSettings->beginGroup(name());
418                 configSettings->writeEntry("/showName", showName);
419                 configSettings->writeEntry("/showRange", showRange);
420                 configSettings->writeEntry("/showData", showData);
421                 configSettings->writeEntry("/optionMode", (int)optMode);
422                 configSettings->endGroup();
423         }
424 }
425
426 ConfigItem* ConfigList::findConfigItem(struct menu *menu)
427 {
428         ConfigItem* item = (ConfigItem*)menu->data;
429
430         for (; item; item = item->nextItem) {
431                 if (this == item->listView())
432                         break;
433         }
434
435         return item;
436 }
437
438 void ConfigList::updateSelection(void)
439 {
440         struct menu *menu;
441         enum prop_type type;
442
443         ConfigItem* item = (ConfigItem*)selectedItem();
444         if (!item)
445                 return;
446
447         menu = item->menu;
448         emit menuChanged(menu);
449         if (!menu)
450                 return;
451         type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
452         if (mode == menuMode && type == P_MENU)
453                 emit menuSelected(menu);
454 }
455
456 void ConfigList::updateList(ConfigItem* item)
457 {
458         ConfigItem* last = 0;
459
460         if (!rootEntry) {
461                 if (mode != listMode)
462                         goto update;
463                 Q3ListViewItemIterator it(this);
464                 ConfigItem* item;
465
466                 for (; it.current(); ++it) {
467                         item = (ConfigItem*)it.current();
468                         if (!item->menu)
469                                 continue;
470                         item->testUpdateMenu(menu_is_visible(item->menu));
471                 }
472                 return;
473         }
474
475         if (rootEntry != &rootmenu && (mode == singleMode ||
476             (mode == symbolMode && rootEntry->parent != &rootmenu))) {
477                 item = firstChild();
478                 if (!item)
479                         item = new ConfigItem(this, 0, true);
480                 last = item;
481         }
482         if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) &&
483             rootEntry->sym && rootEntry->prompt) {
484                 item = last ? last->nextSibling() : firstChild();
485                 if (!item)
486                         item = new ConfigItem(this, last, rootEntry, true);
487                 else
488                         item->testUpdateMenu(true);
489
490                 updateMenuList(item, rootEntry);
491                 triggerUpdate();
492                 return;
493         }
494 update:
495         updateMenuList(this, rootEntry);
496         triggerUpdate();
497 }
498
499 void ConfigList::setValue(ConfigItem* item, tristate val)
500 {
501         struct symbol* sym;
502         int type;
503         tristate oldval;
504
505         sym = item->menu ? item->menu->sym : 0;
506         if (!sym)
507                 return;
508
509         type = sym_get_type(sym);
510         switch (type) {
511         case S_BOOLEAN:
512         case S_TRISTATE:
513                 oldval = sym_get_tristate_value(sym);
514
515                 if (!sym_set_tristate_value(sym, val))
516                         return;
517                 if (oldval == no && item->menu->list)
518                         item->setOpen(TRUE);
519                 parent()->updateList(item);
520                 break;
521         }
522 }
523
524 void ConfigList::changeValue(ConfigItem* item)
525 {
526         struct symbol* sym;
527         struct menu* menu;
528         int type, oldexpr, newexpr;
529
530         menu = item->menu;
531         if (!menu)
532                 return;
533         sym = menu->sym;
534         if (!sym) {
535                 if (item->menu->list)
536                         item->setOpen(!item->isOpen());
537                 return;
538         }
539
540         type = sym_get_type(sym);
541         switch (type) {
542         case S_BOOLEAN:
543         case S_TRISTATE:
544                 oldexpr = sym_get_tristate_value(sym);
545                 newexpr = sym_toggle_tristate_value(sym);
546                 if (item->menu->list) {
547                         if (oldexpr == newexpr)
548                                 item->setOpen(!item->isOpen());
549                         else if (oldexpr == no)
550                                 item->setOpen(TRUE);
551                 }
552                 if (oldexpr != newexpr)
553                         parent()->updateList(item);
554                 break;
555         case S_INT:
556         case S_HEX:
557         case S_STRING:
558                 if (colMap[dataColIdx] >= 0)
559                         item->startRename(colMap[dataColIdx]);
560                 else
561                         parent()->lineEdit->show(item);
562                 break;
563         }
564 }
565
566 void ConfigList::setRootMenu(struct menu *menu)
567 {
568         enum prop_type type;
569
570         if (rootEntry == menu)
571                 return;
572         type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
573         if (type != P_MENU)
574                 return;
575         updateMenuList(this, 0);
576         rootEntry = menu;
577         updateListAll();
578         setSelected(currentItem(), hasFocus());
579         ensureItemVisible(currentItem());
580 }
581
582 void ConfigList::setParentMenu(void)
583 {
584         ConfigItem* item;
585         struct menu *oldroot;
586
587         oldroot = rootEntry;
588         if (rootEntry == &rootmenu)
589                 return;
590         setRootMenu(menu_get_parent_menu(rootEntry->parent));
591
592         Q3ListViewItemIterator it(this);
593         for (; (item = (ConfigItem*)it.current()); it++) {
594                 if (item->menu == oldroot) {
595                         setCurrentItem(item);
596                         ensureItemVisible(item);
597                         break;
598                 }
599         }
600 }
601
602 /*
603  * update all the children of a menu entry
604  *   removes/adds the entries from the parent widget as necessary
605  *
606  * parent: either the menu list widget or a menu entry widget
607  * menu: entry to be updated
608  */
609 template <class P>
610 void ConfigList::updateMenuList(P* parent, struct menu* menu)
611 {
612         struct menu* child;
613         ConfigItem* item;
614         ConfigItem* last;
615         bool visible;
616         enum prop_type type;
617
618         if (!menu) {
619                 while ((item = parent->firstChild()))
620                         delete item;
621                 return;
622         }
623
624         last = parent->firstChild();
625         if (last && !last->goParent)
626                 last = 0;
627         for (child = menu->list; child; child = child->next) {
628                 item = last ? last->nextSibling() : parent->firstChild();
629                 type = child->prompt ? child->prompt->type : P_UNKNOWN;
630
631                 switch (mode) {
632                 case menuMode:
633                         if (!(child->flags & MENU_ROOT))
634                                 goto hide;
635                         break;
636                 case symbolMode:
637                         if (child->flags & MENU_ROOT)
638                                 goto hide;
639                         break;
640                 default:
641                         break;
642                 }
643
644                 visible = menu_is_visible(child);
645                 if (!menuSkip(child)) {
646                         if (!child->sym && !child->list && !child->prompt)
647                                 continue;
648                         if (!item || item->menu != child)
649                                 item = new ConfigItem(parent, last, child, visible);
650                         else
651                                 item->testUpdateMenu(visible);
652
653                         if (mode == fullMode || mode == menuMode || type != P_MENU)
654                                 updateMenuList(item, child);
655                         else
656                                 updateMenuList(item, 0);
657                         last = item;
658                         continue;
659                 }
660         hide:
661                 if (item && item->menu == child) {
662                         last = parent->firstChild();
663                         if (last == item)
664                                 last = 0;
665                         else while (last->nextSibling() != item)
666                                 last = last->nextSibling();
667                         delete item;
668                 }
669         }
670 }
671
672 void ConfigList::keyPressEvent(QKeyEvent* ev)
673 {
674         Q3ListViewItem* i = currentItem();
675         ConfigItem* item;
676         struct menu *menu;
677         enum prop_type type;
678
679         if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) {
680                 emit parentSelected();
681                 ev->accept();
682                 return;
683         }
684
685         if (!i) {
686                 Parent::keyPressEvent(ev);
687                 return;
688         }
689         item = (ConfigItem*)i;
690
691         switch (ev->key()) {
692         case Qt::Key_Return:
693         case Qt::Key_Enter:
694                 if (item->goParent) {
695                         emit parentSelected();
696                         break;
697                 }
698                 menu = item->menu;
699                 if (!menu)
700                         break;
701                 type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
702                 if (type == P_MENU && rootEntry != menu &&
703                     mode != fullMode && mode != menuMode) {
704                         emit menuSelected(menu);
705                         break;
706                 }
707         case Qt::Key_Space:
708                 changeValue(item);
709                 break;
710         case Qt::Key_N:
711                 setValue(item, no);
712                 break;
713         case Qt::Key_M:
714                 setValue(item, mod);
715                 break;
716         case Qt::Key_Y:
717                 setValue(item, yes);
718                 break;
719         default:
720                 Parent::keyPressEvent(ev);
721                 return;
722         }
723         ev->accept();
724 }
725
726 void ConfigList::contentsMousePressEvent(QMouseEvent* e)
727 {
728         //QPoint p(contentsToViewport(e->pos()));
729         //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
730         Parent::contentsMousePressEvent(e);
731 }
732
733 void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e)
734 {
735         QPoint p(contentsToViewport(e->pos()));
736         ConfigItem* item = (ConfigItem*)itemAt(p);
737         struct menu *menu;
738         enum prop_type ptype;
739         const QPixmap* pm;
740         int idx, x;
741
742         if (!item)
743                 goto skip;
744
745         menu = item->menu;
746         x = header()->offset() + p.x();
747         idx = colRevMap[header()->sectionAt(x)];
748         switch (idx) {
749         case promptColIdx:
750                 pm = item->pixmap(promptColIdx);
751                 if (pm) {
752                         int off = header()->sectionPos(0) + itemMargin() +
753                                 treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0));
754                         if (x >= off && x < off + pm->width()) {
755                                 if (item->goParent) {
756                                         emit parentSelected();
757                                         break;
758                                 } else if (!menu)
759                                         break;
760                                 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
761                                 if (ptype == P_MENU && rootEntry != menu &&
762                                     mode != fullMode && mode != menuMode)
763                                         emit menuSelected(menu);
764                                 else
765                                         changeValue(item);
766                         }
767                 }
768                 break;
769         case noColIdx:
770                 setValue(item, no);
771                 break;
772         case modColIdx:
773                 setValue(item, mod);
774                 break;
775         case yesColIdx:
776                 setValue(item, yes);
777                 break;
778         case dataColIdx:
779                 changeValue(item);
780                 break;
781         }
782
783 skip:
784         //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
785         Parent::contentsMouseReleaseEvent(e);
786 }
787
788 void ConfigList::contentsMouseMoveEvent(QMouseEvent* e)
789 {
790         //QPoint p(contentsToViewport(e->pos()));
791         //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
792         Parent::contentsMouseMoveEvent(e);
793 }
794
795 void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e)
796 {
797         QPoint p(contentsToViewport(e->pos()));
798         ConfigItem* item = (ConfigItem*)itemAt(p);
799         struct menu *menu;
800         enum prop_type ptype;
801
802         if (!item)
803                 goto skip;
804         if (item->goParent) {
805                 emit parentSelected();
806                 goto skip;
807         }
808         menu = item->menu;
809         if (!menu)
810                 goto skip;
811         ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
812         if (ptype == P_MENU && (mode == singleMode || mode == symbolMode))
813                 emit menuSelected(menu);
814         else if (menu->sym)
815                 changeValue(item);
816
817 skip:
818         //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
819         Parent::contentsMouseDoubleClickEvent(e);
820 }
821
822 void ConfigList::focusInEvent(QFocusEvent *e)
823 {
824         struct menu *menu = NULL;
825
826         Parent::focusInEvent(e);
827
828         ConfigItem* item = (ConfigItem *)currentItem();
829         if (item) {
830                 setSelected(item, TRUE);
831                 menu = item->menu;
832         }
833         emit gotFocus(menu);
834 }
835
836 void ConfigList::contextMenuEvent(QContextMenuEvent *e)
837 {
838         if (e->y() <= header()->geometry().bottom()) {
839                 if (!headerPopup) {
840                         Q3Action *action;
841
842                         headerPopup = new Q3PopupMenu(this);
843                         action = new Q3Action(NULL, _("Show Name"), 0, this);
844                           action->setToggleAction(TRUE);
845                           connect(action, SIGNAL(toggled(bool)),
846                                   parent(), SLOT(setShowName(bool)));
847                           connect(parent(), SIGNAL(showNameChanged(bool)),
848                                   action, SLOT(setOn(bool)));
849                           action->setOn(showName);
850                           action->addTo(headerPopup);
851                         action = new Q3Action(NULL, _("Show Range"), 0, this);
852                           action->setToggleAction(TRUE);
853                           connect(action, SIGNAL(toggled(bool)),
854                                   parent(), SLOT(setShowRange(bool)));
855                           connect(parent(), SIGNAL(showRangeChanged(bool)),
856                                   action, SLOT(setOn(bool)));
857                           action->setOn(showRange);
858                           action->addTo(headerPopup);
859                         action = new Q3Action(NULL, _("Show Data"), 0, this);
860                           action->setToggleAction(TRUE);
861                           connect(action, SIGNAL(toggled(bool)),
862                                   parent(), SLOT(setShowData(bool)));
863                           connect(parent(), SIGNAL(showDataChanged(bool)),
864                                   action, SLOT(setOn(bool)));
865                           action->setOn(showData);
866                           action->addTo(headerPopup);
867                 }
868                 headerPopup->exec(e->globalPos());
869                 e->accept();
870         } else
871                 e->ignore();
872 }
873
874 ConfigView*ConfigView::viewList;
875 QAction *ConfigView::showNormalAction;
876 QAction *ConfigView::showAllAction;
877 QAction *ConfigView::showPromptAction;
878
879 ConfigView::ConfigView(QWidget* parent, const char *name)
880         : Parent(parent, name)
881 {
882         list = new ConfigList(this, name);
883         lineEdit = new ConfigLineEdit(this);
884         lineEdit->hide();
885
886         this->nextView = viewList;
887         viewList = this;
888 }
889
890 ConfigView::~ConfigView(void)
891 {
892         ConfigView** vp;
893
894         for (vp = &viewList; *vp; vp = &(*vp)->nextView) {
895                 if (*vp == this) {
896                         *vp = nextView;
897                         break;
898                 }
899         }
900 }
901
902 void ConfigView::setOptionMode(QAction *act)
903 {
904         if (act == showNormalAction)
905                 list->optMode = normalOpt;
906         else if (act == showAllAction)
907                 list->optMode = allOpt;
908         else
909                 list->optMode = promptOpt;
910
911         list->updateListAll();
912 }
913
914 void ConfigView::setShowName(bool b)
915 {
916         if (list->showName != b) {
917                 list->showName = b;
918                 list->reinit();
919                 emit showNameChanged(b);
920         }
921 }
922
923 void ConfigView::setShowRange(bool b)
924 {
925         if (list->showRange != b) {
926                 list->showRange = b;
927                 list->reinit();
928                 emit showRangeChanged(b);
929         }
930 }
931
932 void ConfigView::setShowData(bool b)
933 {
934         if (list->showData != b) {
935                 list->showData = b;
936                 list->reinit();
937                 emit showDataChanged(b);
938         }
939 }
940
941 void ConfigList::setAllOpen(bool open)
942 {
943         Q3ListViewItemIterator it(this);
944
945         for (; it.current(); it++)
946                 it.current()->setOpen(open);
947 }
948
949 void ConfigView::updateList(ConfigItem* item)
950 {
951         ConfigView* v;
952
953         for (v = viewList; v; v = v->nextView)
954                 v->list->updateList(item);
955 }
956
957 void ConfigView::updateListAll(void)
958 {
959         ConfigView* v;
960
961         for (v = viewList; v; v = v->nextView)
962                 v->list->updateListAll();
963 }
964
965 ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
966         : Parent(parent, name), sym(0), _menu(0)
967 {
968         if (name) {
969                 configSettings->beginGroup(name);
970                 _showDebug = configSettings->readBoolEntry("/showDebug", false);
971                 configSettings->endGroup();
972                 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
973         }
974 }
975
976 void ConfigInfoView::saveSettings(void)
977 {
978         if (name()) {
979                 configSettings->beginGroup(name());
980                 configSettings->writeEntry("/showDebug", showDebug());
981                 configSettings->endGroup();
982         }
983 }
984
985 void ConfigInfoView::setShowDebug(bool b)
986 {
987         if (_showDebug != b) {
988                 _showDebug = b;
989                 if (_menu)
990                         menuInfo();
991                 else if (sym)
992                         symbolInfo();
993                 emit showDebugChanged(b);
994         }
995 }
996
997 void ConfigInfoView::setInfo(struct menu *m)
998 {
999         if (_menu == m)
1000                 return;
1001         _menu = m;
1002         sym = NULL;
1003         if (!_menu)
1004                 clear();
1005         else
1006                 menuInfo();
1007 }
1008
1009 void ConfigInfoView::symbolInfo(void)
1010 {
1011         QString str;
1012
1013         str += "<big>Symbol: <b>";
1014         str += print_filter(sym->name);
1015         str += "</b></big><br><br>value: ";
1016         str += print_filter(sym_get_string_value(sym));
1017         str += "<br>visibility: ";
1018         str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n";
1019         str += "<br>";
1020         str += debug_info(sym);
1021
1022         setText(str);
1023 }
1024
1025 void ConfigInfoView::menuInfo(void)
1026 {
1027         struct symbol* sym;
1028         QString head, debug, help;
1029
1030         sym = _menu->sym;
1031         if (sym) {
1032                 if (_menu->prompt) {
1033                         head += "<big><b>";
1034                         head += print_filter(_(_menu->prompt->text));
1035                         head += "</b></big>";
1036                         if (sym->name) {
1037                                 head += " (";
1038                                 if (showDebug())
1039                                         head += QString().sprintf("<a href=\"s%p\">", sym);
1040                                 head += print_filter(sym->name);
1041                                 if (showDebug())
1042                                         head += "</a>";
1043                                 head += ")";
1044                         }
1045                 } else if (sym->name) {
1046                         head += "<big><b>";
1047                         if (showDebug())
1048                                 head += QString().sprintf("<a href=\"s%p\">", sym);
1049                         head += print_filter(sym->name);
1050                         if (showDebug())
1051                                 head += "</a>";
1052                         head += "</b></big>";
1053                 }
1054                 head += "<br><br>";
1055
1056                 if (showDebug())
1057                         debug = debug_info(sym);
1058
1059                 struct gstr help_gstr = str_new();
1060                 menu_get_ext_help(_menu, &help_gstr);
1061                 help = print_filter(str_get(&help_gstr));
1062                 str_free(&help_gstr);
1063         } else if (_menu->prompt) {
1064                 head += "<big><b>";
1065                 head += print_filter(_(_menu->prompt->text));
1066                 head += "</b></big><br><br>";
1067                 if (showDebug()) {
1068                         if (_menu->prompt->visible.expr) {
1069                                 debug += "&nbsp;&nbsp;dep: ";
1070                                 expr_print(_menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
1071                                 debug += "<br><br>";
1072                         }
1073                 }
1074         }
1075         if (showDebug())
1076                 debug += QString().sprintf("defined at %s:%d<br><br>", _menu->file->name, _menu->lineno);
1077
1078         setText(head + debug + help);
1079 }
1080
1081 QString ConfigInfoView::debug_info(struct symbol *sym)
1082 {
1083         QString debug;
1084
1085         debug += "type: ";
1086         debug += print_filter(sym_type_name(sym->type));
1087         if (sym_is_choice(sym))
1088                 debug += " (choice)";
1089         debug += "<br>";
1090         if (sym->rev_dep.expr) {
1091                 debug += "reverse dep: ";
1092                 expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
1093                 debug += "<br>";
1094         }
1095         for (struct property *prop = sym->prop; prop; prop = prop->next) {
1096                 switch (prop->type) {
1097                 case P_PROMPT:
1098                 case P_MENU:
1099                         debug += QString().sprintf("prompt: <a href=\"m%p\">", prop->menu);
1100                         debug += print_filter(_(prop->text));
1101                         debug += "</a><br>";
1102                         break;
1103                 case P_DEFAULT:
1104                 case P_SELECT:
1105                 case P_RANGE:
1106                 case P_ENV:
1107                         debug += prop_get_type_name(prop->type);
1108                         debug += ": ";
1109                         expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1110                         debug += "<br>";
1111                         break;
1112                 case P_CHOICE:
1113                         if (sym_is_choice(sym)) {
1114                                 debug += "choice: ";
1115                                 expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1116                                 debug += "<br>";
1117                         }
1118                         break;
1119                 default:
1120                         debug += "unknown property: ";
1121                         debug += prop_get_type_name(prop->type);
1122                         debug += "<br>";
1123                 }
1124                 if (prop->visible.expr) {
1125                         debug += "&nbsp;&nbsp;&nbsp;&nbsp;dep: ";
1126                         expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
1127                         debug += "<br>";
1128                 }
1129         }
1130         debug += "<br>";
1131
1132         return debug;
1133 }
1134
1135 QString ConfigInfoView::print_filter(const QString &str)
1136 {
1137         QRegExp re("[<>&\"\\n]");
1138         QString res = str;
1139         for (int i = 0; (i = res.find(re, i)) >= 0;) {
1140                 switch (res[i].latin1()) {
1141                 case '<':
1142                         res.replace(i, 1, "&lt;");
1143                         i += 4;
1144                         break;
1145                 case '>':
1146                         res.replace(i, 1, "&gt;");
1147                         i += 4;
1148                         break;
1149                 case '&':
1150                         res.replace(i, 1, "&amp;");
1151                         i += 5;
1152                         break;
1153                 case '"':
1154                         res.replace(i, 1, "&quot;");
1155                         i += 6;
1156                         break;
1157                 case '\n':
1158                         res.replace(i, 1, "<br>");
1159                         i += 4;
1160                         break;
1161                 }
1162         }
1163         return res;
1164 }
1165
1166 void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str)
1167 {
1168         QString* text = reinterpret_cast<QString*>(data);
1169         QString str2 = print_filter(str);
1170
1171         if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
1172                 *text += QString().sprintf("<a href=\"s%p\">", sym);
1173                 *text += str2;
1174                 *text += "</a>";
1175         } else
1176                 *text += str2;
1177 }
1178
1179 Q3PopupMenu* ConfigInfoView::createPopupMenu(const QPoint& pos)
1180 {
1181         Q3PopupMenu* popup = Parent::createPopupMenu(pos);
1182         Q3Action* action = new Q3Action(NULL, _("Show Debug Info"), 0, popup);
1183           action->setToggleAction(TRUE);
1184           connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
1185           connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
1186           action->setOn(showDebug());
1187         popup->insertSeparator();
1188         action->addTo(popup);
1189         return popup;
1190 }
1191
1192 void ConfigInfoView::contentsContextMenuEvent(QContextMenuEvent *e)
1193 {
1194         Parent::contentsContextMenuEvent(e);
1195 }
1196
1197 ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *name)
1198         : Parent(parent, name), result(NULL)
1199 {
1200         setCaption("Search Config");
1201
1202         QVBoxLayout* layout1 = new QVBoxLayout(this, 11, 6);
1203         QHBoxLayout* layout2 = new QHBoxLayout(0, 0, 6);
1204         layout2->addWidget(new QLabel(_("Find:"), this));
1205         editField = new QLineEdit(this);
1206         connect(editField, SIGNAL(returnPressed()), SLOT(search()));
1207         layout2->addWidget(editField);
1208         searchButton = new QPushButton(_("Search"), this);
1209         searchButton->setAutoDefault(FALSE);
1210         connect(searchButton, SIGNAL(clicked()), SLOT(search()));
1211         layout2->addWidget(searchButton);
1212         layout1->addLayout(layout2);
1213
1214         split = new QSplitter(this);
1215         split->setOrientation(Qt::Vertical);
1216         list = new ConfigView(split, name);
1217         list->list->mode = listMode;
1218         info = new ConfigInfoView(split, name);
1219         connect(list->list, SIGNAL(menuChanged(struct menu *)),
1220                 info, SLOT(setInfo(struct menu *)));
1221         connect(list->list, SIGNAL(menuChanged(struct menu *)),
1222                 parent, SLOT(setMenuLink(struct menu *)));
1223
1224         layout1->addWidget(split);
1225
1226         if (name) {
1227                 int x, y, width, height;
1228                 bool ok;
1229
1230                 configSettings->beginGroup(name);
1231                 width = configSettings->readNumEntry("/window width", parent->width() / 2);
1232                 height = configSettings->readNumEntry("/window height", parent->height() / 2);
1233                 resize(width, height);
1234                 x = configSettings->readNumEntry("/window x", 0, &ok);
1235                 if (ok)
1236                         y = configSettings->readNumEntry("/window y", 0, &ok);
1237                 if (ok)
1238                         move(x, y);
1239                 Q3ValueList<int> sizes = configSettings->readSizes("/split", &ok);
1240                 if (ok)
1241                         split->setSizes(sizes);
1242                 configSettings->endGroup();
1243                 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
1244         }
1245 }
1246
1247 void ConfigSearchWindow::saveSettings(void)
1248 {
1249         if (name()) {
1250                 configSettings->beginGroup(name());
1251                 configSettings->writeEntry("/window x", pos().x());
1252                 configSettings->writeEntry("/window y", pos().y());
1253                 configSettings->writeEntry("/window width", size().width());
1254                 configSettings->writeEntry("/window height", size().height());
1255                 configSettings->writeSizes("/split", split->sizes());
1256                 configSettings->endGroup();
1257         }
1258 }
1259
1260 void ConfigSearchWindow::search(void)
1261 {
1262         struct symbol **p;
1263         struct property *prop;
1264         ConfigItem *lastItem = NULL;
1265
1266         free(result);
1267         list->list->clear();
1268         info->clear();
1269
1270         result = sym_re_search(editField->text().latin1());
1271         if (!result)
1272                 return;
1273         for (p = result; *p; p++) {
1274                 for_all_prompts((*p), prop)
1275                         lastItem = new ConfigItem(list->list, lastItem, prop->menu,
1276                                                   menu_is_visible(prop->menu));
1277         }
1278 }
1279
1280 /*
1281  * Construct the complete config widget
1282  */
1283 ConfigMainWindow::ConfigMainWindow(void)
1284         : searchWindow(0)
1285 {
1286         QMenuBar* menu;
1287         bool ok;
1288         int x, y, width, height;
1289         char title[256];
1290
1291         QDesktopWidget *d = configApp->desktop();
1292         snprintf(title, sizeof(title), "%s%s",
1293                 rootmenu.prompt->text,
1294 #if QT_VERSION < 0x040000
1295                 " (Qt3)"
1296 #else
1297                 ""
1298 #endif
1299                 );
1300         setCaption(title);
1301
1302         width = configSettings->readNumEntry("/window width", d->width() - 64);
1303         height = configSettings->readNumEntry("/window height", d->height() - 64);
1304         resize(width, height);
1305         x = configSettings->readNumEntry("/window x", 0, &ok);
1306         if (ok)
1307                 y = configSettings->readNumEntry("/window y", 0, &ok);
1308         if (ok)
1309                 move(x, y);
1310
1311         split1 = new QSplitter(this);
1312         split1->setOrientation(Qt::Horizontal);
1313         setCentralWidget(split1);
1314
1315         menuView = new ConfigView(split1, "menu");
1316         menuList = menuView->list;
1317
1318         split2 = new QSplitter(split1);
1319         split2->setOrientation(Qt::Vertical);
1320
1321         // create config tree
1322         configView = new ConfigView(split2, "config");
1323         configList = configView->list;
1324
1325         helpText = new ConfigInfoView(split2, "help");
1326         helpText->setTextFormat(Qt::RichText);
1327
1328         setTabOrder(configList, helpText);
1329         configList->setFocus();
1330
1331         menu = menuBar();
1332         toolBar = new Q3ToolBar("Tools", this);
1333
1334         backAction = new Q3Action("Back", QPixmap(xpm_back), _("Back"), 0, this);
1335           connect(backAction, SIGNAL(activated()), SLOT(goBack()));
1336           backAction->setEnabled(FALSE);
1337         Q3Action *quitAction = new Q3Action("Quit", _("&Quit"), Qt::CTRL + Qt::Key_Q, this);
1338           connect(quitAction, SIGNAL(activated()), SLOT(close()));
1339         Q3Action *loadAction = new Q3Action("Load", QPixmap(xpm_load), _("&Load"), Qt::CTRL + Qt::Key_L, this);
1340           connect(loadAction, SIGNAL(activated()), SLOT(loadConfig()));
1341         saveAction = new Q3Action("Save", QPixmap(xpm_save), _("&Save"), Qt::CTRL + Qt::Key_S, this);
1342           connect(saveAction, SIGNAL(activated()), SLOT(saveConfig()));
1343         conf_set_changed_callback(conf_changed);
1344         // Set saveAction's initial state
1345         conf_changed();
1346         Q3Action *saveAsAction = new Q3Action("Save As...", _("Save &As..."), 0, this);
1347           connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs()));
1348         Q3Action *searchAction = new Q3Action("Find", _("&Find"), Qt::CTRL + Qt::Key_F, this);
1349           connect(searchAction, SIGNAL(activated()), SLOT(searchConfig()));
1350         Q3Action *singleViewAction = new Q3Action("Single View", QPixmap(xpm_single_view), _("Single View"), 0, this);
1351           connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView()));
1352         Q3Action *splitViewAction = new Q3Action("Split View", QPixmap(xpm_split_view), _("Split View"), 0, this);
1353           connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView()));
1354         Q3Action *fullViewAction = new Q3Action("Full View", QPixmap(xpm_tree_view), _("Full View"), 0, this);
1355           connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView()));
1356
1357         Q3Action *showNameAction = new Q3Action(NULL, _("Show Name"), 0, this);
1358           showNameAction->setToggleAction(TRUE);
1359           connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
1360           connect(configView, SIGNAL(showNameChanged(bool)), showNameAction, SLOT(setOn(bool)));
1361           showNameAction->setOn(configView->showName());
1362         Q3Action *showRangeAction = new Q3Action(NULL, _("Show Range"), 0, this);
1363           showRangeAction->setToggleAction(TRUE);
1364           connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
1365           connect(configView, SIGNAL(showRangeChanged(bool)), showRangeAction, SLOT(setOn(bool)));
1366           showRangeAction->setOn(configList->showRange);
1367         Q3Action *showDataAction = new Q3Action(NULL, _("Show Data"), 0, this);
1368           showDataAction->setToggleAction(TRUE);
1369           connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
1370           connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool)));
1371           showDataAction->setOn(configList->showData);
1372
1373         QActionGroup *optGroup = new QActionGroup(this);
1374         optGroup->setExclusive(TRUE);
1375         connect(optGroup, SIGNAL(selected(QAction *)), configView,
1376                 SLOT(setOptionMode(QAction *)));
1377         connect(optGroup, SIGNAL(selected(QAction *)), menuView,
1378                 SLOT(setOptionMode(QAction *)));
1379
1380 #if QT_VERSION >= 0x040000
1381         configView->showNormalAction = new QAction(_("Show Normal Options"), optGroup);
1382         configView->showAllAction = new QAction(_("Show All Options"), optGroup);
1383         configView->showPromptAction = new QAction(_("Show Prompt Options"), optGroup);
1384 #else
1385         configView->showNormalAction = new QAction(_("Show Normal Options"), 0, optGroup);
1386         configView->showAllAction = new QAction(_("Show All Options"), 0, optGroup);
1387         configView->showPromptAction = new QAction(_("Show Prompt Options"), 0, optGroup);
1388 #endif
1389         configView->showNormalAction->setToggleAction(TRUE);
1390         configView->showNormalAction->setOn(configList->optMode == normalOpt);
1391         configView->showAllAction->setToggleAction(TRUE);
1392         configView->showAllAction->setOn(configList->optMode == allOpt);
1393         configView->showPromptAction->setToggleAction(TRUE);
1394         configView->showPromptAction->setOn(configList->optMode == promptOpt);
1395
1396         Q3Action *showDebugAction = new Q3Action(NULL, _("Show Debug Info"), 0, this);
1397           showDebugAction->setToggleAction(TRUE);
1398           connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
1399           connect(helpText, SIGNAL(showDebugChanged(bool)), showDebugAction, SLOT(setOn(bool)));
1400           showDebugAction->setOn(helpText->showDebug());
1401
1402         Q3Action *showIntroAction = new Q3Action(NULL, _("Introduction"), 0, this);
1403           connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro()));
1404         Q3Action *showAboutAction = new Q3Action(NULL, _("About"), 0, this);
1405           connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout()));
1406
1407         // init tool bar
1408         backAction->addTo(toolBar);
1409         toolBar->addSeparator();
1410         loadAction->addTo(toolBar);
1411         saveAction->addTo(toolBar);
1412         toolBar->addSeparator();
1413         singleViewAction->addTo(toolBar);
1414         splitViewAction->addTo(toolBar);
1415         fullViewAction->addTo(toolBar);
1416
1417         // create config menu
1418         Q3PopupMenu* config = new Q3PopupMenu(this);
1419         menu->insertItem(_("&File"), config);
1420         loadAction->addTo(config);
1421         saveAction->addTo(config);
1422         saveAsAction->addTo(config);
1423         config->insertSeparator();
1424         quitAction->addTo(config);
1425
1426         // create edit menu
1427         Q3PopupMenu* editMenu = new Q3PopupMenu(this);
1428         menu->insertItem(_("&Edit"), editMenu);
1429         searchAction->addTo(editMenu);
1430
1431         // create options menu
1432         Q3PopupMenu* optionMenu = new Q3PopupMenu(this);
1433         menu->insertItem(_("&Option"), optionMenu);
1434         showNameAction->addTo(optionMenu);
1435         showRangeAction->addTo(optionMenu);
1436         showDataAction->addTo(optionMenu);
1437         optionMenu->insertSeparator();
1438         optGroup->addTo(optionMenu);
1439         optionMenu->insertSeparator();
1440
1441         // create help menu
1442         Q3PopupMenu* helpMenu = new Q3PopupMenu(this);
1443         menu->insertSeparator();
1444         menu->insertItem(_("&Help"), helpMenu);
1445         showIntroAction->addTo(helpMenu);
1446         showAboutAction->addTo(helpMenu);
1447
1448         connect(configList, SIGNAL(menuChanged(struct menu *)),
1449                 helpText, SLOT(setInfo(struct menu *)));
1450         connect(configList, SIGNAL(menuSelected(struct menu *)),
1451                 SLOT(changeMenu(struct menu *)));
1452         connect(configList, SIGNAL(parentSelected()),
1453                 SLOT(goBack()));
1454         connect(menuList, SIGNAL(menuChanged(struct menu *)),
1455                 helpText, SLOT(setInfo(struct menu *)));
1456         connect(menuList, SIGNAL(menuSelected(struct menu *)),
1457                 SLOT(changeMenu(struct menu *)));
1458
1459         connect(configList, SIGNAL(gotFocus(struct menu *)),
1460                 helpText, SLOT(setInfo(struct menu *)));
1461         connect(menuList, SIGNAL(gotFocus(struct menu *)),
1462                 helpText, SLOT(setInfo(struct menu *)));
1463         connect(menuList, SIGNAL(gotFocus(struct menu *)),
1464                 SLOT(listFocusChanged(void)));
1465         connect(helpText, SIGNAL(menuSelected(struct menu *)),
1466                 SLOT(setMenuLink(struct menu *)));
1467
1468         QString listMode = configSettings->readEntry("/listMode", "symbol");
1469         if (listMode == "single")
1470                 showSingleView();
1471         else if (listMode == "full")
1472                 showFullView();
1473         else /*if (listMode == "split")*/
1474                 showSplitView();
1475
1476         // UI setup done, restore splitter positions
1477         Q3ValueList<int> sizes = configSettings->readSizes("/split1", &ok);
1478         if (ok)
1479                 split1->setSizes(sizes);
1480
1481         sizes = configSettings->readSizes("/split2", &ok);
1482         if (ok)
1483                 split2->setSizes(sizes);
1484 }
1485
1486 void ConfigMainWindow::loadConfig(void)
1487 {
1488         QString s = Q3FileDialog::getOpenFileName(conf_get_configname(), NULL, this);
1489         if (s.isNull())
1490                 return;
1491         if (conf_read(QFile::encodeName(s)))
1492                 QMessageBox::information(this, "qconf", _("Unable to load configuration!"));
1493         ConfigView::updateListAll();
1494 }
1495
1496 bool ConfigMainWindow::saveConfig(void)
1497 {
1498         if (conf_write(NULL)) {
1499                 QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
1500                 return false;
1501         }
1502         return true;
1503 }
1504
1505 void ConfigMainWindow::saveConfigAs(void)
1506 {
1507         QString s = Q3FileDialog::getSaveFileName(conf_get_configname(), NULL, this);
1508         if (s.isNull())
1509                 return;
1510         saveConfig();
1511 }
1512
1513 void ConfigMainWindow::searchConfig(void)
1514 {
1515         if (!searchWindow)
1516                 searchWindow = new ConfigSearchWindow(this, "search");
1517         searchWindow->show();
1518 }
1519
1520 void ConfigMainWindow::changeMenu(struct menu *menu)
1521 {
1522         configList->setRootMenu(menu);
1523         if (configList->rootEntry->parent == &rootmenu)
1524                 backAction->setEnabled(FALSE);
1525         else
1526                 backAction->setEnabled(TRUE);
1527 }
1528
1529 void ConfigMainWindow::setMenuLink(struct menu *menu)
1530 {
1531         struct menu *parent;
1532         ConfigList* list = NULL;
1533         ConfigItem* item;
1534
1535         if (configList->menuSkip(menu))
1536                 return;
1537
1538         switch (configList->mode) {
1539         case singleMode:
1540                 list = configList;
1541                 parent = menu_get_parent_menu(menu);
1542                 if (!parent)
1543                         return;
1544                 list->setRootMenu(parent);
1545                 break;
1546         case symbolMode:
1547                 if (menu->flags & MENU_ROOT) {
1548                         configList->setRootMenu(menu);
1549                         configList->clearSelection();
1550                         list = menuList;
1551                 } else {
1552                         list = configList;
1553                         parent = menu_get_parent_menu(menu->parent);
1554                         if (!parent)
1555                                 return;
1556                         item = menuList->findConfigItem(parent);
1557                         if (item) {
1558                                 menuList->setSelected(item, TRUE);
1559                                 menuList->ensureItemVisible(item);
1560                         }
1561                         list->setRootMenu(parent);
1562                 }
1563                 break;
1564         case fullMode:
1565                 list = configList;
1566                 break;
1567         default:
1568                 break;
1569         }
1570
1571         if (list) {
1572                 item = list->findConfigItem(menu);
1573                 if (item) {
1574                         list->setSelected(item, TRUE);
1575                         list->ensureItemVisible(item);
1576                         list->setFocus();
1577                 }
1578         }
1579 }
1580
1581 void ConfigMainWindow::listFocusChanged(void)
1582 {
1583         if (menuList->mode == menuMode)
1584                 configList->clearSelection();
1585 }
1586
1587 void ConfigMainWindow::goBack(void)
1588 {
1589         ConfigItem* item;
1590
1591         configList->setParentMenu();
1592         if (configList->rootEntry == &rootmenu)
1593                 backAction->setEnabled(FALSE);
1594         item = (ConfigItem*)menuList->selectedItem();
1595         while (item) {
1596                 if (item->menu == configList->rootEntry) {
1597                         menuList->setSelected(item, TRUE);
1598                         break;
1599                 }
1600                 item = (ConfigItem*)item->parent();
1601         }
1602 }
1603
1604 void ConfigMainWindow::showSingleView(void)
1605 {
1606         menuView->hide();
1607         menuList->setRootMenu(0);
1608         configList->mode = singleMode;
1609         if (configList->rootEntry == &rootmenu)
1610                 configList->updateListAll();
1611         else
1612                 configList->setRootMenu(&rootmenu);
1613         configList->setAllOpen(TRUE);
1614         configList->setFocus();
1615 }
1616
1617 void ConfigMainWindow::showSplitView(void)
1618 {
1619         configList->mode = symbolMode;
1620         if (configList->rootEntry == &rootmenu)
1621                 configList->updateListAll();
1622         else
1623                 configList->setRootMenu(&rootmenu);
1624         configList->setAllOpen(TRUE);
1625         configApp->processEvents();
1626         menuList->mode = menuMode;
1627         menuList->setRootMenu(&rootmenu);
1628         menuList->setAllOpen(TRUE);
1629         menuView->show();
1630         menuList->setFocus();
1631 }
1632
1633 void ConfigMainWindow::showFullView(void)
1634 {
1635         menuView->hide();
1636         menuList->setRootMenu(0);
1637         configList->mode = fullMode;
1638         if (configList->rootEntry == &rootmenu)
1639                 configList->updateListAll();
1640         else
1641                 configList->setRootMenu(&rootmenu);
1642         configList->setAllOpen(FALSE);
1643         configList->setFocus();
1644 }
1645
1646 /*
1647  * ask for saving configuration before quitting
1648  * TODO ask only when something changed
1649  */
1650 void ConfigMainWindow::closeEvent(QCloseEvent* e)
1651 {
1652         if (!conf_get_changed()) {
1653                 e->accept();
1654                 return;
1655         }
1656         QMessageBox mb("qconf", _("Save configuration?"), QMessageBox::Warning,
1657                         QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
1658         mb.setButtonText(QMessageBox::Yes, _("&Save Changes"));
1659         mb.setButtonText(QMessageBox::No, _("&Discard Changes"));
1660         mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit"));
1661         switch (mb.exec()) {
1662         case QMessageBox::Yes:
1663                 if (saveConfig())
1664                         e->accept();
1665                 else
1666                         e->ignore();
1667                 break;
1668         case QMessageBox::No:
1669                 e->accept();
1670                 break;
1671         case QMessageBox::Cancel:
1672                 e->ignore();
1673                 break;
1674         }
1675 }
1676
1677 void ConfigMainWindow::showIntro(void)
1678 {
1679         static const QString str = _("Welcome to the qconf graphical configuration tool.\n\n"
1680                 "For each option, a blank box indicates the feature is disabled, a check\n"
1681                 "indicates it is enabled, and a dot indicates that it is to be compiled\n"
1682                 "as a module.  Clicking on the box will cycle through the three states.\n\n"
1683                 "If you do not see an option (e.g., a device driver) that you believe\n"
1684                 "should be present, try turning on Show All Options under the Options menu.\n"
1685                 "Although there is no cross reference yet to help you figure out what other\n"
1686                 "options must be enabled to support the option you are interested in, you can\n"
1687                 "still view the help of a grayed-out option.\n\n"
1688                 "Toggling Show Debug Info under the Options menu will show the dependencies,\n"
1689                 "which you can then match by examining other options.\n\n");
1690
1691         QMessageBox::information(this, "qconf", str);
1692 }
1693
1694 void ConfigMainWindow::showAbout(void)
1695 {
1696         static const QString str = _("qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n\n"
1697                 "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n");
1698
1699         QMessageBox::information(this, "qconf", str);
1700 }
1701
1702 void ConfigMainWindow::saveSettings(void)
1703 {
1704         configSettings->writeEntry("/window x", pos().x());
1705         configSettings->writeEntry("/window y", pos().y());
1706         configSettings->writeEntry("/window width", size().width());
1707         configSettings->writeEntry("/window height", size().height());
1708
1709         QString entry;
1710         switch(configList->mode) {
1711         case singleMode :
1712                 entry = "single";
1713                 break;
1714
1715         case symbolMode :
1716                 entry = "split";
1717                 break;
1718
1719         case fullMode :
1720                 entry = "full";
1721                 break;
1722
1723         default:
1724                 break;
1725         }
1726         configSettings->writeEntry("/listMode", entry);
1727
1728         configSettings->writeSizes("/split1", split1->sizes());
1729         configSettings->writeSizes("/split2", split2->sizes());
1730 }
1731
1732 void ConfigMainWindow::conf_changed(void)
1733 {
1734         if (saveAction)
1735                 saveAction->setEnabled(conf_get_changed());
1736 }
1737
1738 void fixup_rootmenu(struct menu *menu)
1739 {
1740         struct menu *child;
1741         static int menu_cnt = 0;
1742
1743         menu->flags |= MENU_ROOT;
1744         for (child = menu->list; child; child = child->next) {
1745                 if (child->prompt && child->prompt->type == P_MENU) {
1746                         menu_cnt++;
1747                         fixup_rootmenu(child);
1748                         menu_cnt--;
1749                 } else if (!menu_cnt)
1750                         fixup_rootmenu(child);
1751         }
1752 }
1753
1754 static const char *progname;
1755
1756 static void usage(void)
1757 {
1758         printf(_("%s <config>\n"), progname);
1759         exit(0);
1760 }
1761
1762 int main(int ac, char** av)
1763 {
1764         ConfigMainWindow* v;
1765         const char *name;
1766
1767         bindtextdomain(PACKAGE, LOCALEDIR);
1768         textdomain(PACKAGE);
1769
1770         progname = av[0];
1771         configApp = new QApplication(ac, av);
1772         if (ac > 1 && av[1][0] == '-') {
1773                 switch (av[1][1]) {
1774                 case 'h':
1775                 case '?':
1776                         usage();
1777                 }
1778                 name = av[2];
1779         } else
1780                 name = av[1];
1781         if (!name)
1782                 usage();
1783
1784         conf_parse(name);
1785         fixup_rootmenu(&rootmenu);
1786         conf_read(NULL);
1787         //zconfdump(stdout);
1788
1789         configSettings = new ConfigSettings();
1790         configSettings->beginGroup("/kconfig/qconf");
1791         v = new ConfigMainWindow();
1792
1793         //zconfdump(stdout);
1794         configApp->setMainWidget(v);
1795         configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
1796         configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1797         v->show();
1798         configApp->exec();
1799
1800         configSettings->endGroup();
1801         delete configSettings;
1802
1803         return 0;
1804 }