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