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