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