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