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