8d60d99bd9f19474e58147a24f4ff6488fa01dad
[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(NULL, "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(NULL, "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(NULL, "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(NULL,"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         : searchWindow(0)
1263 {
1264         QMenuBar* menu;
1265         bool ok;
1266         int x, y, width, height;
1267
1268         QWidget *d = configApp->desktop();
1269
1270         width = configSettings->readNumEntry("/window width", d->width() - 64);
1271         height = configSettings->readNumEntry("/window height", d->height() - 64);
1272         resize(width, height);
1273         x = configSettings->readNumEntry("/window x", 0, &ok);
1274         if (ok)
1275                 y = configSettings->readNumEntry("/window y", 0, &ok);
1276         if (ok)
1277                 move(x, y);
1278
1279         split1 = new QSplitter(this);
1280         split1->setOrientation(QSplitter::Horizontal);
1281         setCentralWidget(split1);
1282
1283         menuView = new ConfigView(split1, "menu");
1284         menuList = menuView->list;
1285
1286         split2 = new QSplitter(split1);
1287         split2->setOrientation(QSplitter::Vertical);
1288
1289         // create config tree
1290         configView = new ConfigView(split2, "config");
1291         configList = configView->list;
1292
1293         helpText = new ConfigInfoView(split2, "help");
1294         helpText->setTextFormat(Qt::RichText);
1295
1296         setTabOrder(configList, helpText);
1297         configList->setFocus();
1298
1299         menu = menuBar();
1300         toolBar = new QToolBar("Tools", this);
1301
1302         backAction = new QAction("Back", QPixmap(xpm_back), "Back", 0, this);
1303           connect(backAction, SIGNAL(activated()), SLOT(goBack()));
1304           backAction->setEnabled(FALSE);
1305         QAction *quitAction = new QAction("Quit", "&Quit", CTRL+Key_Q, this);
1306           connect(quitAction, SIGNAL(activated()), SLOT(close()));
1307         QAction *loadAction = new QAction("Load", QPixmap(xpm_load), "&Load", CTRL+Key_L, this);
1308           connect(loadAction, SIGNAL(activated()), SLOT(loadConfig()));
1309         QAction *saveAction = new QAction("Save", QPixmap(xpm_save), "&Save", CTRL+Key_S, this);
1310           connect(saveAction, SIGNAL(activated()), SLOT(saveConfig()));
1311         QAction *saveAsAction = new QAction("Save As...", "Save &As...", 0, this);
1312           connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs()));
1313         QAction *searchAction = new QAction("Search", "&Search", CTRL+Key_F, this);
1314           connect(searchAction, SIGNAL(activated()), SLOT(searchConfig()));
1315         QAction *singleViewAction = new QAction("Single View", QPixmap(xpm_single_view), "Split View", 0, this);
1316           connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView()));
1317         QAction *splitViewAction = new QAction("Split View", QPixmap(xpm_split_view), "Split View", 0, this);
1318           connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView()));
1319         QAction *fullViewAction = new QAction("Full View", QPixmap(xpm_tree_view), "Full View", 0, this);
1320           connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView()));
1321
1322         QAction *showNameAction = new QAction(NULL, "Show Name", 0, this);
1323           showNameAction->setToggleAction(TRUE);
1324           connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
1325           connect(configView, SIGNAL(showNameChanged(bool)), showNameAction, SLOT(setOn(bool)));
1326           showNameAction->setOn(configView->showName());
1327         QAction *showRangeAction = new QAction(NULL, "Show Range", 0, this);
1328           showRangeAction->setToggleAction(TRUE);
1329           connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
1330           connect(configView, SIGNAL(showRangeChanged(bool)), showRangeAction, SLOT(setOn(bool)));
1331           showRangeAction->setOn(configList->showRange);
1332         QAction *showDataAction = new QAction(NULL, "Show Data", 0, this);
1333           showDataAction->setToggleAction(TRUE);
1334           connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
1335           connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool)));
1336           showDataAction->setOn(configList->showData);
1337         QAction *showAllAction = new QAction(NULL, "Show All Options", 0, this);
1338           showAllAction->setToggleAction(TRUE);
1339           connect(showAllAction, SIGNAL(toggled(bool)), configView, SLOT(setShowAll(bool)));
1340           connect(showAllAction, SIGNAL(toggled(bool)), menuView, SLOT(setShowAll(bool)));
1341           showAllAction->setOn(configList->showAll);
1342         QAction *showDebugAction = new QAction(NULL, "Show Debug Info", 0, this);
1343           showDebugAction->setToggleAction(TRUE);
1344           connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
1345           connect(helpText, SIGNAL(showDebugChanged(bool)), showDebugAction, SLOT(setOn(bool)));
1346           showDebugAction->setOn(helpText->showDebug());
1347
1348         QAction *showIntroAction = new QAction(NULL, "Introduction", 0, this);
1349           connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro()));
1350         QAction *showAboutAction = new QAction(NULL, "About", 0, this);
1351           connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout()));
1352
1353         // init tool bar
1354         backAction->addTo(toolBar);
1355         toolBar->addSeparator();
1356         loadAction->addTo(toolBar);
1357         saveAction->addTo(toolBar);
1358         toolBar->addSeparator();
1359         singleViewAction->addTo(toolBar);
1360         splitViewAction->addTo(toolBar);
1361         fullViewAction->addTo(toolBar);
1362
1363         // create config menu
1364         QPopupMenu* config = new QPopupMenu(this);
1365         menu->insertItem("&File", config);
1366         loadAction->addTo(config);
1367         saveAction->addTo(config);
1368         saveAsAction->addTo(config);
1369         config->insertSeparator();
1370         searchAction->addTo(config);
1371         config->insertSeparator();
1372         quitAction->addTo(config);
1373
1374         // create options menu
1375         QPopupMenu* optionMenu = new QPopupMenu(this);
1376         menu->insertItem("&Option", optionMenu);
1377         showNameAction->addTo(optionMenu);
1378         showRangeAction->addTo(optionMenu);
1379         showDataAction->addTo(optionMenu);
1380         optionMenu->insertSeparator();
1381         showAllAction->addTo(optionMenu);
1382         showDebugAction->addTo(optionMenu);
1383
1384         // create help menu
1385         QPopupMenu* helpMenu = new QPopupMenu(this);
1386         menu->insertSeparator();
1387         menu->insertItem("&Help", helpMenu);
1388         showIntroAction->addTo(helpMenu);
1389         showAboutAction->addTo(helpMenu);
1390
1391         connect(configList, SIGNAL(menuChanged(struct menu *)),
1392                 helpText, SLOT(setInfo(struct menu *)));
1393         connect(configList, SIGNAL(menuSelected(struct menu *)),
1394                 SLOT(changeMenu(struct menu *)));
1395         connect(configList, SIGNAL(parentSelected()),
1396                 SLOT(goBack()));
1397         connect(menuList, SIGNAL(menuChanged(struct menu *)),
1398                 helpText, SLOT(setInfo(struct menu *)));
1399         connect(menuList, SIGNAL(menuSelected(struct menu *)),
1400                 SLOT(changeMenu(struct menu *)));
1401
1402         connect(configList, SIGNAL(gotFocus(struct menu *)),
1403                 helpText, SLOT(setInfo(struct menu *)));
1404         connect(menuList, SIGNAL(gotFocus(struct menu *)),
1405                 helpText, SLOT(setInfo(struct menu *)));
1406         connect(menuList, SIGNAL(gotFocus(struct menu *)),
1407                 SLOT(listFocusChanged(void)));
1408         connect(helpText, SIGNAL(menuSelected(struct menu *)),
1409                 SLOT(setMenuLink(struct menu *)));
1410
1411         QString listMode = configSettings->readEntry("/listMode", "symbol");
1412         if (listMode == "single")
1413                 showSingleView();
1414         else if (listMode == "full")
1415                 showFullView();
1416         else /*if (listMode == "split")*/
1417                 showSplitView();
1418
1419         // UI setup done, restore splitter positions
1420         QValueList<int> sizes = configSettings->readSizes("/split1", &ok);
1421         if (ok)
1422                 split1->setSizes(sizes);
1423
1424         sizes = configSettings->readSizes("/split2", &ok);
1425         if (ok)
1426                 split2->setSizes(sizes);
1427 }
1428
1429 void ConfigMainWindow::loadConfig(void)
1430 {
1431         QString s = QFileDialog::getOpenFileName(".config", NULL, this);
1432         if (s.isNull())
1433                 return;
1434         if (conf_read(QFile::encodeName(s)))
1435                 QMessageBox::information(this, "qconf", "Unable to load configuration!");
1436         ConfigView::updateListAll();
1437 }
1438
1439 void ConfigMainWindow::saveConfig(void)
1440 {
1441         if (conf_write(NULL))
1442                 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1443 }
1444
1445 void ConfigMainWindow::saveConfigAs(void)
1446 {
1447         QString s = QFileDialog::getSaveFileName(".config", NULL, this);
1448         if (s.isNull())
1449                 return;
1450         if (conf_write(QFile::encodeName(s)))
1451                 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1452 }
1453
1454 void ConfigMainWindow::searchConfig(void)
1455 {
1456         if (!searchWindow)
1457                 searchWindow = new ConfigSearchWindow(this, "search");
1458         searchWindow->show();
1459 }
1460
1461 void ConfigMainWindow::changeMenu(struct menu *menu)
1462 {
1463         configList->setRootMenu(menu);
1464         backAction->setEnabled(TRUE);
1465 }
1466
1467 void ConfigMainWindow::setMenuLink(struct menu *menu)
1468 {
1469         struct menu *parent;
1470         ConfigList* list = NULL;
1471         ConfigItem* item;
1472
1473         if (!menu_is_visible(menu) && !configView->showAll())
1474                 return;
1475
1476         switch (configList->mode) {
1477         case singleMode:
1478                 list = configList;
1479                 parent = menu_get_parent_menu(menu);
1480                 if (!parent)
1481                         return;
1482                 list->setRootMenu(parent);
1483                 break;
1484         case symbolMode:
1485                 if (menu->flags & MENU_ROOT) {
1486                         configList->setRootMenu(menu);
1487                         configList->clearSelection();
1488                         list = menuList;
1489                 } else {
1490                         list = configList;
1491                         parent = menu_get_parent_menu(menu->parent);
1492                         if (!parent)
1493                                 return;
1494                         item = menuList->findConfigItem(parent);
1495                         if (item) {
1496                                 menuList->setSelected(item, TRUE);
1497                                 menuList->ensureItemVisible(item);
1498                         }
1499                         list->setRootMenu(parent);
1500                 }
1501                 break;
1502         case fullMode:
1503                 list = configList;
1504                 break;
1505         }
1506
1507         if (list) {
1508                 item = list->findConfigItem(menu);
1509                 if (item) {
1510                         list->setSelected(item, TRUE);
1511                         list->ensureItemVisible(item);
1512                         list->setFocus();
1513                 }
1514         }
1515 }
1516
1517 void ConfigMainWindow::listFocusChanged(void)
1518 {
1519         if (menuList->mode == menuMode)
1520                 configList->clearSelection();
1521 }
1522
1523 void ConfigMainWindow::goBack(void)
1524 {
1525         ConfigItem* item;
1526
1527         configList->setParentMenu();
1528         if (configList->rootEntry == &rootmenu)
1529                 backAction->setEnabled(FALSE);
1530         item = (ConfigItem*)menuList->selectedItem();
1531         while (item) {
1532                 if (item->menu == configList->rootEntry) {
1533                         menuList->setSelected(item, TRUE);
1534                         break;
1535                 }
1536                 item = (ConfigItem*)item->parent();
1537         }
1538 }
1539
1540 void ConfigMainWindow::showSingleView(void)
1541 {
1542         menuView->hide();
1543         menuList->setRootMenu(0);
1544         configList->mode = singleMode;
1545         if (configList->rootEntry == &rootmenu)
1546                 configList->updateListAll();
1547         else
1548                 configList->setRootMenu(&rootmenu);
1549         configList->setAllOpen(TRUE);
1550         configList->setFocus();
1551 }
1552
1553 void ConfigMainWindow::showSplitView(void)
1554 {
1555         configList->mode = symbolMode;
1556         if (configList->rootEntry == &rootmenu)
1557                 configList->updateListAll();
1558         else
1559                 configList->setRootMenu(&rootmenu);
1560         configList->setAllOpen(TRUE);
1561         configApp->processEvents();
1562         menuList->mode = menuMode;
1563         menuList->setRootMenu(&rootmenu);
1564         menuList->setAllOpen(TRUE);
1565         menuView->show();
1566         menuList->setFocus();
1567 }
1568
1569 void ConfigMainWindow::showFullView(void)
1570 {
1571         menuView->hide();
1572         menuList->setRootMenu(0);
1573         configList->mode = fullMode;
1574         if (configList->rootEntry == &rootmenu)
1575                 configList->updateListAll();
1576         else
1577                 configList->setRootMenu(&rootmenu);
1578         configList->setAllOpen(FALSE);
1579         configList->setFocus();
1580 }
1581
1582 /*
1583  * ask for saving configuration before quitting
1584  * TODO ask only when something changed
1585  */
1586 void ConfigMainWindow::closeEvent(QCloseEvent* e)
1587 {
1588         if (!conf_get_changed()) {
1589                 e->accept();
1590                 return;
1591         }
1592         QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning,
1593                         QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
1594         mb.setButtonText(QMessageBox::Yes, "&Save Changes");
1595         mb.setButtonText(QMessageBox::No, "&Discard Changes");
1596         mb.setButtonText(QMessageBox::Cancel, "Cancel Exit");
1597         switch (mb.exec()) {
1598         case QMessageBox::Yes:
1599                 conf_write(NULL);
1600         case QMessageBox::No:
1601                 e->accept();
1602                 break;
1603         case QMessageBox::Cancel:
1604                 e->ignore();
1605                 break;
1606         }
1607 }
1608
1609 void ConfigMainWindow::showIntro(void)
1610 {
1611         static char str[] = "Welcome to the qconf graphical kernel configuration tool for Linux.\n\n"
1612                 "For each option, a blank box indicates the feature is disabled, a check\n"
1613                 "indicates it is enabled, and a dot indicates that it is to be compiled\n"
1614                 "as a module.  Clicking on the box will cycle through the three states.\n\n"
1615                 "If you do not see an option (e.g., a device driver) that you believe\n"
1616                 "should be present, try turning on Show All Options under the Options menu.\n"
1617                 "Although there is no cross reference yet to help you figure out what other\n"
1618                 "options must be enabled to support the option you are interested in, you can\n"
1619                 "still view the help of a grayed-out option.\n\n"
1620                 "Toggling Show Debug Info under the Options menu will show the dependencies,\n"
1621                 "which you can then match by examining other options.\n\n";
1622
1623         QMessageBox::information(this, "qconf", str);
1624 }
1625
1626 void ConfigMainWindow::showAbout(void)
1627 {
1628         static char str[] = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n\n"
1629                 "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n";
1630
1631         QMessageBox::information(this, "qconf", str);
1632 }
1633
1634 void ConfigMainWindow::saveSettings(void)
1635 {
1636         configSettings->writeEntry("/window x", pos().x());
1637         configSettings->writeEntry("/window y", pos().y());
1638         configSettings->writeEntry("/window width", size().width());
1639         configSettings->writeEntry("/window height", size().height());
1640
1641         QString entry;
1642         switch(configList->mode) {
1643         case singleMode :
1644                 entry = "single";
1645                 break;
1646
1647         case symbolMode :
1648                 entry = "split";
1649                 break;
1650
1651         case fullMode :
1652                 entry = "full";
1653                 break;
1654         }
1655         configSettings->writeEntry("/listMode", entry);
1656
1657         configSettings->writeSizes("/split1", split1->sizes());
1658         configSettings->writeSizes("/split2", split2->sizes());
1659 }
1660
1661 void fixup_rootmenu(struct menu *menu)
1662 {
1663         struct menu *child;
1664         static int menu_cnt = 0;
1665
1666         menu->flags |= MENU_ROOT;
1667         for (child = menu->list; child; child = child->next) {
1668                 if (child->prompt && child->prompt->type == P_MENU) {
1669                         menu_cnt++;
1670                         fixup_rootmenu(child);
1671                         menu_cnt--;
1672                 } else if (!menu_cnt)
1673                         fixup_rootmenu(child);
1674         }
1675 }
1676
1677 static const char *progname;
1678
1679 static void usage(void)
1680 {
1681         printf("%s <config>\n", progname);
1682         exit(0);
1683 }
1684
1685 int main(int ac, char** av)
1686 {
1687         ConfigMainWindow* v;
1688         const char *name;
1689
1690         bindtextdomain(PACKAGE, LOCALEDIR);
1691         textdomain(PACKAGE);
1692
1693 #ifndef LKC_DIRECT_LINK
1694         kconfig_load();
1695 #endif
1696
1697         progname = av[0];
1698         configApp = new QApplication(ac, av);
1699         if (ac > 1 && av[1][0] == '-') {
1700                 switch (av[1][1]) {
1701                 case 'h':
1702                 case '?':
1703                         usage();
1704                 }
1705                 name = av[2];
1706         } else
1707                 name = av[1];
1708         if (!name)
1709                 usage();
1710
1711         conf_parse(name);
1712         fixup_rootmenu(&rootmenu);
1713         conf_read(NULL);
1714         //zconfdump(stdout);
1715
1716         configSettings = new ConfigSettings();
1717         configSettings->beginGroup("/kconfig/qconf");
1718         v = new ConfigMainWindow();
1719
1720         //zconfdump(stdout);
1721         configApp->setMainWidget(v);
1722         configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
1723         configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1724         v->show();
1725         configApp->exec();
1726
1727         configSettings->endGroup();
1728         delete configSettings;
1729
1730         return 0;
1731 }