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