]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - scripts/kconfig/qconf.cc
Merge remote-tracking branch 'kgdb/kgdb-next'
[karo-tx-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         ConfigItem* item = (ConfigItem*)selectedItems().first();
404         if (!item)
405                 return;
406
407         menu = item->menu;
408         emit menuChanged(menu);
409         if (!menu)
410                 return;
411         type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
412         if (mode == menuMode && type == P_MENU)
413                 emit menuSelected(menu);
414 }
415
416 void ConfigList::updateList(ConfigItem* item)
417 {
418         ConfigItem* last = 0;
419
420         if (!rootEntry) {
421                 if (mode != listMode)
422                         goto update;
423                 QTreeWidgetItemIterator it(this);
424                 ConfigItem* item;
425
426                 while (*it) {
427                         item = (ConfigItem*)(*it);
428                         if (!item->menu)
429                                 continue;
430                         item->testUpdateMenu(menu_is_visible(item->menu));
431
432                         ++it;
433                 }
434                 return;
435         }
436
437         if (rootEntry != &rootmenu && (mode == singleMode ||
438             (mode == symbolMode && rootEntry->parent != &rootmenu))) {
439                 item = (ConfigItem *)topLevelItem(0);
440                 if (!item)
441                         item = new ConfigItem(this, 0, true);
442                 last = item;
443         }
444         if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) &&
445             rootEntry->sym && rootEntry->prompt) {
446                 item = last ? last->nextSibling() : firstChild();
447                 if (!item)
448                         item = new ConfigItem(this, last, rootEntry, true);
449                 else
450                         item->testUpdateMenu(true);
451
452                 updateMenuList(item, rootEntry);
453                 update();
454                 resizeColumnToContents(0);
455                 return;
456         }
457 update:
458         updateMenuList(this, rootEntry);
459         update();
460         resizeColumnToContents(0);
461 }
462
463 void ConfigList::setValue(ConfigItem* item, tristate val)
464 {
465         struct symbol* sym;
466         int type;
467         tristate oldval;
468
469         sym = item->menu ? item->menu->sym : 0;
470         if (!sym)
471                 return;
472
473         type = sym_get_type(sym);
474         switch (type) {
475         case S_BOOLEAN:
476         case S_TRISTATE:
477                 oldval = sym_get_tristate_value(sym);
478
479                 if (!sym_set_tristate_value(sym, val))
480                         return;
481                 if (oldval == no && item->menu->list)
482                         item->setExpanded(true);
483                 parent()->updateList(item);
484                 break;
485         }
486 }
487
488 void ConfigList::changeValue(ConfigItem* item)
489 {
490         struct symbol* sym;
491         struct menu* menu;
492         int type, oldexpr, newexpr;
493
494         menu = item->menu;
495         if (!menu)
496                 return;
497         sym = menu->sym;
498         if (!sym) {
499                 if (item->menu->list)
500                         item->setExpanded(!item->isExpanded());
501                 return;
502         }
503
504         type = sym_get_type(sym);
505         switch (type) {
506         case S_BOOLEAN:
507         case S_TRISTATE:
508                 oldexpr = sym_get_tristate_value(sym);
509                 newexpr = sym_toggle_tristate_value(sym);
510                 if (item->menu->list) {
511                         if (oldexpr == newexpr)
512                                 item->setExpanded(!item->isExpanded());
513                         else if (oldexpr == no)
514                                 item->setExpanded(true);
515                 }
516                 if (oldexpr != newexpr)
517                         parent()->updateList(item);
518                 break;
519         case S_INT:
520         case S_HEX:
521         case S_STRING:
522                 parent()->lineEdit->show(item);
523                 break;
524         }
525 }
526
527 void ConfigList::setRootMenu(struct menu *menu)
528 {
529         enum prop_type type;
530
531         if (rootEntry == menu)
532                 return;
533         type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
534         if (type != P_MENU)
535                 return;
536         updateMenuList(this, 0);
537         rootEntry = menu;
538         updateListAll();
539         if (currentItem()) {
540                 currentItem()->setSelected(hasFocus());
541                 scrollToItem(currentItem());
542         }
543 }
544
545 void ConfigList::setParentMenu(void)
546 {
547         ConfigItem* item;
548         struct menu *oldroot;
549
550         oldroot = rootEntry;
551         if (rootEntry == &rootmenu)
552                 return;
553         setRootMenu(menu_get_parent_menu(rootEntry->parent));
554
555         QTreeWidgetItemIterator it(this);
556         while (*it) {
557                 item = (ConfigItem *)(*it);
558                 if (item->menu == oldroot) {
559                         setCurrentItem(item);
560                         scrollToItem(item);
561                         break;
562                 }
563
564                 ++it;
565         }
566 }
567
568 /*
569  * update all the children of a menu entry
570  *   removes/adds the entries from the parent widget as necessary
571  *
572  * parent: either the menu list widget or a menu entry widget
573  * menu: entry to be updated
574  */
575 void ConfigList::updateMenuList(ConfigItem *parent, struct menu* menu)
576 {
577         struct menu* child;
578         ConfigItem* item;
579         ConfigItem* last;
580         bool visible;
581         enum prop_type type;
582
583         if (!menu) {
584                 while (parent->childCount() > 0)
585                 {
586                         delete parent->takeChild(0);
587                 }
588
589                 return;
590         }
591
592         last = parent->firstChild();
593         if (last && !last->goParent)
594                 last = 0;
595         for (child = menu->list; child; child = child->next) {
596                 item = last ? last->nextSibling() : parent->firstChild();
597                 type = child->prompt ? child->prompt->type : P_UNKNOWN;
598
599                 switch (mode) {
600                 case menuMode:
601                         if (!(child->flags & MENU_ROOT))
602                                 goto hide;
603                         break;
604                 case symbolMode:
605                         if (child->flags & MENU_ROOT)
606                                 goto hide;
607                         break;
608                 default:
609                         break;
610                 }
611
612                 visible = menu_is_visible(child);
613                 if (!menuSkip(child)) {
614                         if (!child->sym && !child->list && !child->prompt)
615                                 continue;
616                         if (!item || item->menu != child)
617                                 item = new ConfigItem(parent, last, child, visible);
618                         else
619                                 item->testUpdateMenu(visible);
620
621                         if (mode == fullMode || mode == menuMode || type != P_MENU)
622                                 updateMenuList(item, child);
623                         else
624                                 updateMenuList(item, 0);
625                         last = item;
626                         continue;
627                 }
628         hide:
629                 if (item && item->menu == child) {
630                         last = parent->firstChild();
631                         if (last == item)
632                                 last = 0;
633                         else while (last->nextSibling() != item)
634                                 last = last->nextSibling();
635                         delete item;
636                 }
637         }
638 }
639
640 void ConfigList::updateMenuList(ConfigList *parent, struct menu* menu)
641 {
642         struct menu* child;
643         ConfigItem* item;
644         ConfigItem* last;
645         bool visible;
646         enum prop_type type;
647
648         if (!menu) {
649                 while (parent->topLevelItemCount() > 0)
650                 {
651                         delete parent->takeTopLevelItem(0);
652                 }
653
654                 return;
655         }
656
657         last = (ConfigItem*)parent->topLevelItem(0);
658         if (last && !last->goParent)
659                 last = 0;
660         for (child = menu->list; child; child = child->next) {
661                 item = last ? last->nextSibling() : (ConfigItem*)parent->topLevelItem(0);
662                 type = child->prompt ? child->prompt->type : P_UNKNOWN;
663
664                 switch (mode) {
665                 case menuMode:
666                         if (!(child->flags & MENU_ROOT))
667                                 goto hide;
668                         break;
669                 case symbolMode:
670                         if (child->flags & MENU_ROOT)
671                                 goto hide;
672                         break;
673                 default:
674                         break;
675                 }
676
677                 visible = menu_is_visible(child);
678                 if (!menuSkip(child)) {
679                         if (!child->sym && !child->list && !child->prompt)
680                                 continue;
681                         if (!item || item->menu != child)
682                                 item = new ConfigItem(parent, last, child, visible);
683                         else
684                                 item->testUpdateMenu(visible);
685
686                         if (mode == fullMode || mode == menuMode || type != P_MENU)
687                                 updateMenuList(item, child);
688                         else
689                                 updateMenuList(item, 0);
690                         last = item;
691                         continue;
692                 }
693         hide:
694                 if (item && item->menu == child) {
695                         last = (ConfigItem*)parent->topLevelItem(0);
696                         if (last == item)
697                                 last = 0;
698                         else while (last->nextSibling() != item)
699                                 last = last->nextSibling();
700                         delete item;
701                 }
702         }
703 }
704
705 void ConfigList::keyPressEvent(QKeyEvent* ev)
706 {
707         QTreeWidgetItem* i = currentItem();
708         ConfigItem* item;
709         struct menu *menu;
710         enum prop_type type;
711
712         if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) {
713                 emit parentSelected();
714                 ev->accept();
715                 return;
716         }
717
718         if (!i) {
719                 Parent::keyPressEvent(ev);
720                 return;
721         }
722         item = (ConfigItem*)i;
723
724         switch (ev->key()) {
725         case Qt::Key_Return:
726         case Qt::Key_Enter:
727                 if (item->goParent) {
728                         emit parentSelected();
729                         break;
730                 }
731                 menu = item->menu;
732                 if (!menu)
733                         break;
734                 type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
735                 if (type == P_MENU && rootEntry != menu &&
736                     mode != fullMode && mode != menuMode) {
737                         emit menuSelected(menu);
738                         break;
739                 }
740         case Qt::Key_Space:
741                 changeValue(item);
742                 break;
743         case Qt::Key_N:
744                 setValue(item, no);
745                 break;
746         case Qt::Key_M:
747                 setValue(item, mod);
748                 break;
749         case Qt::Key_Y:
750                 setValue(item, yes);
751                 break;
752         default:
753                 Parent::keyPressEvent(ev);
754                 return;
755         }
756         ev->accept();
757 }
758
759 void ConfigList::mousePressEvent(QMouseEvent* e)
760 {
761         //QPoint p(contentsToViewport(e->pos()));
762         //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
763         Parent::mousePressEvent(e);
764 }
765
766 void ConfigList::mouseReleaseEvent(QMouseEvent* e)
767 {
768         QPoint p = e->pos();
769         ConfigItem* item = (ConfigItem*)itemAt(p);
770         struct menu *menu;
771         enum prop_type ptype;
772         QIcon icon;
773         int idx, x;
774
775         if (!item)
776                 goto skip;
777
778         menu = item->menu;
779         x = header()->offset() + p.x();
780         idx = header()->logicalIndexAt(x);
781         switch (idx) {
782         case promptColIdx:
783                 icon = item->pixmap(promptColIdx);
784                 if (!icon.isNull()) {
785                         int off = header()->sectionPosition(0) + visualRect(indexAt(p)).x() + 4; // 4 is Hardcoded image offset. There might be a way to do it properly.
786                         if (x >= off && x < off + icon.availableSizes().first().width()) {
787                                 if (item->goParent) {
788                                         emit parentSelected();
789                                         break;
790                                 } else if (!menu)
791                                         break;
792                                 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
793                                 if (ptype == P_MENU && rootEntry != menu &&
794                                     mode != fullMode && mode != menuMode)
795                                         emit menuSelected(menu);
796                                 else
797                                         changeValue(item);
798                         }
799                 }
800                 break;
801         case noColIdx:
802                 setValue(item, no);
803                 break;
804         case modColIdx:
805                 setValue(item, mod);
806                 break;
807         case yesColIdx:
808                 setValue(item, yes);
809                 break;
810         case dataColIdx:
811                 changeValue(item);
812                 break;
813         }
814
815 skip:
816         //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
817         Parent::mouseReleaseEvent(e);
818 }
819
820 void ConfigList::mouseMoveEvent(QMouseEvent* e)
821 {
822         //QPoint p(contentsToViewport(e->pos()));
823         //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
824         Parent::mouseMoveEvent(e);
825 }
826
827 void ConfigList::mouseDoubleClickEvent(QMouseEvent* e)
828 {
829         QPoint p = e->pos(); // TODO: Check if this works(was contentsToViewport).
830         ConfigItem* item = (ConfigItem*)itemAt(p);
831         struct menu *menu;
832         enum prop_type ptype;
833
834         if (!item)
835                 goto skip;
836         if (item->goParent) {
837                 emit parentSelected();
838                 goto skip;
839         }
840         menu = item->menu;
841         if (!menu)
842                 goto skip;
843         ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
844         if (ptype == P_MENU && (mode == singleMode || mode == symbolMode))
845                 emit menuSelected(menu);
846         else if (menu->sym)
847                 changeValue(item);
848
849 skip:
850         //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
851         Parent::mouseDoubleClickEvent(e);
852 }
853
854 void ConfigList::focusInEvent(QFocusEvent *e)
855 {
856         struct menu *menu = NULL;
857
858         Parent::focusInEvent(e);
859
860         ConfigItem* item = (ConfigItem *)currentItem();
861         if (item) {
862                 item->setSelected(true);
863                 menu = item->menu;
864         }
865         emit gotFocus(menu);
866 }
867
868 void ConfigList::contextMenuEvent(QContextMenuEvent *e)
869 {
870         if (e->y() <= header()->geometry().bottom()) {
871                 if (!headerPopup) {
872                         QAction *action;
873
874                         headerPopup = new QMenu(this);
875                         action = new QAction(_("Show Name"), this);
876                           action->setCheckable(true);
877                           connect(action, SIGNAL(toggled(bool)),
878                                   parent(), SLOT(setShowName(bool)));
879                           connect(parent(), SIGNAL(showNameChanged(bool)),
880                                   action, SLOT(setOn(bool)));
881                           action->setChecked(showName);
882                           headerPopup->addAction(action);
883                         action = new QAction(_("Show Range"), this);
884                           action->setCheckable(true);
885                           connect(action, SIGNAL(toggled(bool)),
886                                   parent(), SLOT(setShowRange(bool)));
887                           connect(parent(), SIGNAL(showRangeChanged(bool)),
888                                   action, SLOT(setOn(bool)));
889                           action->setChecked(showRange);
890                           headerPopup->addAction(action);
891                         action = new QAction(_("Show Data"), this);
892                           action->setCheckable(true);
893                           connect(action, SIGNAL(toggled(bool)),
894                                   parent(), SLOT(setShowData(bool)));
895                           connect(parent(), SIGNAL(showDataChanged(bool)),
896                                   action, SLOT(setOn(bool)));
897                           action->setChecked(showData);
898                           headerPopup->addAction(action);
899                 }
900                 headerPopup->exec(e->globalPos());
901                 e->accept();
902         } else
903                 e->ignore();
904 }
905
906 ConfigView*ConfigView::viewList;
907 QAction *ConfigView::showNormalAction;
908 QAction *ConfigView::showAllAction;
909 QAction *ConfigView::showPromptAction;
910
911 ConfigView::ConfigView(QWidget* parent, const char *name)
912         : Parent(parent)
913 {
914         setObjectName(name);
915         QVBoxLayout *verticalLayout = new QVBoxLayout(this);
916         verticalLayout->setContentsMargins(0, 0, 0, 0);
917
918         list = new ConfigList(this);
919         verticalLayout->addWidget(list);
920         lineEdit = new ConfigLineEdit(this);
921         lineEdit->hide();
922         verticalLayout->addWidget(lineEdit);
923
924         this->nextView = viewList;
925         viewList = this;
926 }
927
928 ConfigView::~ConfigView(void)
929 {
930         ConfigView** vp;
931
932         for (vp = &viewList; *vp; vp = &(*vp)->nextView) {
933                 if (*vp == this) {
934                         *vp = nextView;
935                         break;
936                 }
937         }
938 }
939
940 void ConfigView::setOptionMode(QAction *act)
941 {
942         if (act == showNormalAction)
943                 list->optMode = normalOpt;
944         else if (act == showAllAction)
945                 list->optMode = allOpt;
946         else
947                 list->optMode = promptOpt;
948
949         list->updateListAll();
950 }
951
952 void ConfigView::setShowName(bool b)
953 {
954         if (list->showName != b) {
955                 list->showName = b;
956                 list->reinit();
957                 emit showNameChanged(b);
958         }
959 }
960
961 void ConfigView::setShowRange(bool b)
962 {
963         if (list->showRange != b) {
964                 list->showRange = b;
965                 list->reinit();
966                 emit showRangeChanged(b);
967         }
968 }
969
970 void ConfigView::setShowData(bool b)
971 {
972         if (list->showData != b) {
973                 list->showData = b;
974                 list->reinit();
975                 emit showDataChanged(b);
976         }
977 }
978
979 void ConfigList::setAllOpen(bool open)
980 {
981         QTreeWidgetItemIterator it(this);
982
983         while (*it) {
984                 (*it)->setExpanded(open);
985
986                 ++it;
987         }
988 }
989
990 void ConfigView::updateList(ConfigItem* item)
991 {
992         ConfigView* v;
993
994         for (v = viewList; v; v = v->nextView)
995                 v->list->updateList(item);
996 }
997
998 void ConfigView::updateListAll(void)
999 {
1000         ConfigView* v;
1001
1002         for (v = viewList; v; v = v->nextView)
1003                 v->list->updateListAll();
1004 }
1005
1006 ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
1007         : Parent(parent), sym(0), _menu(0)
1008 {
1009         setObjectName(name);
1010
1011
1012         if (!objectName().isEmpty()) {
1013                 configSettings->beginGroup(objectName());
1014                 _showDebug = configSettings->value("/showDebug", false).toBool();
1015                 configSettings->endGroup();
1016                 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
1017         }
1018 }
1019
1020 void ConfigInfoView::saveSettings(void)
1021 {
1022         if (!objectName().isEmpty()) {
1023                 configSettings->beginGroup(objectName());
1024                 configSettings->setValue("/showDebug", showDebug());
1025                 configSettings->endGroup();
1026         }
1027 }
1028
1029 void ConfigInfoView::setShowDebug(bool b)
1030 {
1031         if (_showDebug != b) {
1032                 _showDebug = b;
1033                 if (_menu)
1034                         menuInfo();
1035                 else if (sym)
1036                         symbolInfo();
1037                 emit showDebugChanged(b);
1038         }
1039 }
1040
1041 void ConfigInfoView::setInfo(struct menu *m)
1042 {
1043         if (_menu == m)
1044                 return;
1045         _menu = m;
1046         sym = NULL;
1047         if (!_menu)
1048                 clear();
1049         else
1050                 menuInfo();
1051 }
1052
1053 void ConfigInfoView::symbolInfo(void)
1054 {
1055         QString str;
1056
1057         str += "<big>Symbol: <b>";
1058         str += print_filter(sym->name);
1059         str += "</b></big><br><br>value: ";
1060         str += print_filter(sym_get_string_value(sym));
1061         str += "<br>visibility: ";
1062         str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n";
1063         str += "<br>";
1064         str += debug_info(sym);
1065
1066         setText(str);
1067 }
1068
1069 void ConfigInfoView::menuInfo(void)
1070 {
1071         struct symbol* sym;
1072         QString head, debug, help;
1073
1074         sym = _menu->sym;
1075         if (sym) {
1076                 if (_menu->prompt) {
1077                         head += "<big><b>";
1078                         head += print_filter(_(_menu->prompt->text));
1079                         head += "</b></big>";
1080                         if (sym->name) {
1081                                 head += " (";
1082                                 if (showDebug())
1083                                         head += QString().sprintf("<a href=\"s%p\">", sym);
1084                                 head += print_filter(sym->name);
1085                                 if (showDebug())
1086                                         head += "</a>";
1087                                 head += ")";
1088                         }
1089                 } else if (sym->name) {
1090                         head += "<big><b>";
1091                         if (showDebug())
1092                                 head += QString().sprintf("<a href=\"s%p\">", sym);
1093                         head += print_filter(sym->name);
1094                         if (showDebug())
1095                                 head += "</a>";
1096                         head += "</b></big>";
1097                 }
1098                 head += "<br><br>";
1099
1100                 if (showDebug())
1101                         debug = debug_info(sym);
1102
1103                 struct gstr help_gstr = str_new();
1104                 menu_get_ext_help(_menu, &help_gstr);
1105                 help = print_filter(str_get(&help_gstr));
1106                 str_free(&help_gstr);
1107         } else if (_menu->prompt) {
1108                 head += "<big><b>";
1109                 head += print_filter(_(_menu->prompt->text));
1110                 head += "</b></big><br><br>";
1111                 if (showDebug()) {
1112                         if (_menu->prompt->visible.expr) {
1113                                 debug += "&nbsp;&nbsp;dep: ";
1114                                 expr_print(_menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
1115                                 debug += "<br><br>";
1116                         }
1117                 }
1118         }
1119         if (showDebug())
1120                 debug += QString().sprintf("defined at %s:%d<br><br>", _menu->file->name, _menu->lineno);
1121
1122         setText(head + debug + help);
1123 }
1124
1125 QString ConfigInfoView::debug_info(struct symbol *sym)
1126 {
1127         QString debug;
1128
1129         debug += "type: ";
1130         debug += print_filter(sym_type_name(sym->type));
1131         if (sym_is_choice(sym))
1132                 debug += " (choice)";
1133         debug += "<br>";
1134         if (sym->rev_dep.expr) {
1135                 debug += "reverse dep: ";
1136                 expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
1137                 debug += "<br>";
1138         }
1139         for (struct property *prop = sym->prop; prop; prop = prop->next) {
1140                 switch (prop->type) {
1141                 case P_PROMPT:
1142                 case P_MENU:
1143                         debug += QString().sprintf("prompt: <a href=\"m%p\">", prop->menu);
1144                         debug += print_filter(_(prop->text));
1145                         debug += "</a><br>";
1146                         break;
1147                 case P_DEFAULT:
1148                 case P_SELECT:
1149                 case P_RANGE:
1150                 case P_ENV:
1151                         debug += prop_get_type_name(prop->type);
1152                         debug += ": ";
1153                         expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1154                         debug += "<br>";
1155                         break;
1156                 case P_CHOICE:
1157                         if (sym_is_choice(sym)) {
1158                                 debug += "choice: ";
1159                                 expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1160                                 debug += "<br>";
1161                         }
1162                         break;
1163                 default:
1164                         debug += "unknown property: ";
1165                         debug += prop_get_type_name(prop->type);
1166                         debug += "<br>";
1167                 }
1168                 if (prop->visible.expr) {
1169                         debug += "&nbsp;&nbsp;&nbsp;&nbsp;dep: ";
1170                         expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
1171                         debug += "<br>";
1172                 }
1173         }
1174         debug += "<br>";
1175
1176         return debug;
1177 }
1178
1179 QString ConfigInfoView::print_filter(const QString &str)
1180 {
1181         QRegExp re("[<>&\"\\n]");
1182         QString res = str;
1183         for (int i = 0; (i = res.indexOf(re, i)) >= 0;) {
1184                 switch (res[i].toLatin1()) {
1185                 case '<':
1186                         res.replace(i, 1, "&lt;");
1187                         i += 4;
1188                         break;
1189                 case '>':
1190                         res.replace(i, 1, "&gt;");
1191                         i += 4;
1192                         break;
1193                 case '&':
1194                         res.replace(i, 1, "&amp;");
1195                         i += 5;
1196                         break;
1197                 case '"':
1198                         res.replace(i, 1, "&quot;");
1199                         i += 6;
1200                         break;
1201                 case '\n':
1202                         res.replace(i, 1, "<br>");
1203                         i += 4;
1204                         break;
1205                 }
1206         }
1207         return res;
1208 }
1209
1210 void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str)
1211 {
1212         QString* text = reinterpret_cast<QString*>(data);
1213         QString str2 = print_filter(str);
1214
1215         if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
1216                 *text += QString().sprintf("<a href=\"s%p\">", sym);
1217                 *text += str2;
1218                 *text += "</a>";
1219         } else
1220                 *text += str2;
1221 }
1222
1223 QMenu* ConfigInfoView::createStandardContextMenu(const QPoint & pos)
1224 {
1225         QMenu* popup = Parent::createStandardContextMenu(pos);
1226         QAction* action = new QAction(_("Show Debug Info"), popup);
1227           action->setCheckable(true);
1228           connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
1229           connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
1230           action->setChecked(showDebug());
1231         popup->addSeparator();
1232         popup->addAction(action);
1233         return popup;
1234 }
1235
1236 void ConfigInfoView::contextMenuEvent(QContextMenuEvent *e)
1237 {
1238         Parent::contextMenuEvent(e);
1239 }
1240
1241 ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *name)
1242         : Parent(parent), result(NULL)
1243 {
1244         setObjectName(name);
1245         setWindowTitle("Search Config");
1246
1247         QVBoxLayout* layout1 = new QVBoxLayout(this);
1248         layout1->setContentsMargins(11, 11, 11, 11);
1249         layout1->setSpacing(6);
1250         QHBoxLayout* layout2 = new QHBoxLayout(0);
1251         layout2->setContentsMargins(0, 0, 0, 0);
1252         layout2->setSpacing(6);
1253         layout2->addWidget(new QLabel(_("Find:"), this));
1254         editField = new QLineEdit(this);
1255         connect(editField, SIGNAL(returnPressed()), SLOT(search()));
1256         layout2->addWidget(editField);
1257         searchButton = new QPushButton(_("Search"), this);
1258         searchButton->setAutoDefault(false);
1259         connect(searchButton, SIGNAL(clicked()), SLOT(search()));
1260         layout2->addWidget(searchButton);
1261         layout1->addLayout(layout2);
1262
1263         split = new QSplitter(this);
1264         split->setOrientation(Qt::Vertical);
1265         list = new ConfigView(split, name);
1266         list->list->mode = listMode;
1267         info = new ConfigInfoView(split, name);
1268         connect(list->list, SIGNAL(menuChanged(struct menu *)),
1269                 info, SLOT(setInfo(struct menu *)));
1270         connect(list->list, SIGNAL(menuChanged(struct menu *)),
1271                 parent, SLOT(setMenuLink(struct menu *)));
1272
1273         layout1->addWidget(split);
1274
1275         if (name) {
1276                 QVariant x, y;
1277                 int width, height;
1278                 bool ok;
1279
1280                 configSettings->beginGroup(name);
1281                 width = configSettings->value("/window width", parent->width() / 2).toInt();
1282                 height = configSettings->value("/window height", parent->height() / 2).toInt();
1283                 resize(width, height);
1284                 x = configSettings->value("/window x");
1285                 y = configSettings->value("/window y");
1286                 if ((x.isValid())&&(y.isValid()))
1287                         move(x.toInt(), y.toInt());
1288                 QList<int> sizes = configSettings->readSizes("/split", &ok);
1289                 if (ok)
1290                         split->setSizes(sizes);
1291                 configSettings->endGroup();
1292                 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
1293         }
1294 }
1295
1296 void ConfigSearchWindow::saveSettings(void)
1297 {
1298         if (!objectName().isEmpty()) {
1299                 configSettings->beginGroup(objectName());
1300                 configSettings->setValue("/window x", pos().x());
1301                 configSettings->setValue("/window y", pos().y());
1302                 configSettings->setValue("/window width", size().width());
1303                 configSettings->setValue("/window height", size().height());
1304                 configSettings->writeSizes("/split", split->sizes());
1305                 configSettings->endGroup();
1306         }
1307 }
1308
1309 void ConfigSearchWindow::search(void)
1310 {
1311         struct symbol **p;
1312         struct property *prop;
1313         ConfigItem *lastItem = NULL;
1314
1315         free(result);
1316         list->list->clear();
1317         info->clear();
1318
1319         result = sym_re_search(editField->text().toLatin1());
1320         if (!result)
1321                 return;
1322         for (p = result; *p; p++) {
1323                 for_all_prompts((*p), prop)
1324                         lastItem = new ConfigItem(list->list, lastItem, prop->menu,
1325                                                   menu_is_visible(prop->menu));
1326         }
1327 }
1328
1329 /*
1330  * Construct the complete config widget
1331  */
1332 ConfigMainWindow::ConfigMainWindow(void)
1333         : searchWindow(0)
1334 {
1335         QMenuBar* menu;
1336         bool ok = true;
1337         QVariant x, y;
1338         int width, height;
1339         char title[256];
1340
1341         QDesktopWidget *d = configApp->desktop();
1342         snprintf(title, sizeof(title), "%s%s",
1343                 rootmenu.prompt->text,
1344                 ""
1345                 );
1346         setWindowTitle(title);
1347
1348         width = configSettings->value("/window width", d->width() - 64).toInt();
1349         height = configSettings->value("/window height", d->height() - 64).toInt();
1350         resize(width, height);
1351         x = configSettings->value("/window x");
1352         y = configSettings->value("/window y");
1353         if ((x.isValid())&&(y.isValid()))
1354                 move(x.toInt(), y.toInt());
1355
1356         split1 = new QSplitter(this);
1357         split1->setOrientation(Qt::Horizontal);
1358         setCentralWidget(split1);
1359
1360         menuView = new ConfigView(split1, "menu");
1361         menuList = menuView->list;
1362
1363         split2 = new QSplitter(split1);
1364         split2->setOrientation(Qt::Vertical);
1365
1366         // create config tree
1367         configView = new ConfigView(split2, "config");
1368         configList = configView->list;
1369
1370         helpText = new ConfigInfoView(split2, "help");
1371
1372         setTabOrder(configList, helpText);
1373         configList->setFocus();
1374
1375         menu = menuBar();
1376         toolBar = new QToolBar("Tools", this);
1377         addToolBar(toolBar);
1378
1379         backAction = new QAction(QPixmap(xpm_back), _("Back"), this);
1380           connect(backAction, SIGNAL(triggered(bool)), SLOT(goBack()));
1381           backAction->setEnabled(false);
1382         QAction *quitAction = new QAction(_("&Quit"), this);
1383         quitAction->setShortcut(Qt::CTRL + Qt::Key_Q);
1384           connect(quitAction, SIGNAL(triggered(bool)), SLOT(close()));
1385         QAction *loadAction = new QAction(QPixmap(xpm_load), _("&Load"), this);
1386         loadAction->setShortcut(Qt::CTRL + Qt::Key_L);
1387           connect(loadAction, SIGNAL(triggered(bool)), SLOT(loadConfig()));
1388         saveAction = new QAction(QPixmap(xpm_save), _("&Save"), this);
1389         saveAction->setShortcut(Qt::CTRL + Qt::Key_S);
1390           connect(saveAction, SIGNAL(triggered(bool)), SLOT(saveConfig()));
1391         conf_set_changed_callback(conf_changed);
1392         // Set saveAction's initial state
1393         conf_changed();
1394         QAction *saveAsAction = new QAction(_("Save &As..."), this);
1395           connect(saveAsAction, SIGNAL(triggered(bool)), SLOT(saveConfigAs()));
1396         QAction *searchAction = new QAction(_("&Find"), this);
1397         searchAction->setShortcut(Qt::CTRL + Qt::Key_F);
1398           connect(searchAction, SIGNAL(triggered(bool)), SLOT(searchConfig()));
1399         singleViewAction = new QAction(QPixmap(xpm_single_view), _("Single View"), this);
1400         singleViewAction->setCheckable(true);
1401           connect(singleViewAction, SIGNAL(triggered(bool)), SLOT(showSingleView()));
1402         splitViewAction = new QAction(QPixmap(xpm_split_view), _("Split View"), this);
1403         splitViewAction->setCheckable(true);
1404           connect(splitViewAction, SIGNAL(triggered(bool)), SLOT(showSplitView()));
1405         fullViewAction = new QAction(QPixmap(xpm_tree_view), _("Full View"), this);
1406         fullViewAction->setCheckable(true);
1407           connect(fullViewAction, SIGNAL(triggered(bool)), SLOT(showFullView()));
1408
1409         QAction *showNameAction = new QAction(_("Show Name"), this);
1410           showNameAction->setCheckable(true);
1411           connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
1412           showNameAction->setChecked(configView->showName());
1413         QAction *showRangeAction = new QAction(_("Show Range"), this);
1414           showRangeAction->setCheckable(true);
1415           connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
1416         QAction *showDataAction = new QAction(_("Show Data"), this);
1417           showDataAction->setCheckable(true);
1418           connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
1419
1420         QActionGroup *optGroup = new QActionGroup(this);
1421         optGroup->setExclusive(true);
1422         connect(optGroup, SIGNAL(triggered(QAction*)), configView,
1423                 SLOT(setOptionMode(QAction *)));
1424         connect(optGroup, SIGNAL(triggered(QAction *)), menuView,
1425                 SLOT(setOptionMode(QAction *)));
1426
1427         configView->showNormalAction = new QAction(_("Show Normal Options"), optGroup);
1428         configView->showAllAction = new QAction(_("Show All Options"), optGroup);
1429         configView->showPromptAction = new QAction(_("Show Prompt Options"), optGroup);
1430         configView->showNormalAction->setCheckable(true);
1431         configView->showAllAction->setCheckable(true);
1432         configView->showPromptAction->setCheckable(true);
1433
1434         QAction *showDebugAction = new QAction( _("Show Debug Info"), this);
1435           showDebugAction->setCheckable(true);
1436           connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
1437           showDebugAction->setChecked(helpText->showDebug());
1438
1439         QAction *showIntroAction = new QAction( _("Introduction"), this);
1440           connect(showIntroAction, SIGNAL(triggered(bool)), SLOT(showIntro()));
1441         QAction *showAboutAction = new QAction( _("About"), this);
1442           connect(showAboutAction, SIGNAL(triggered(bool)), SLOT(showAbout()));
1443
1444         // init tool bar
1445         toolBar->addAction(backAction);
1446         toolBar->addSeparator();
1447         toolBar->addAction(loadAction);
1448         toolBar->addAction(saveAction);
1449         toolBar->addSeparator();
1450         toolBar->addAction(singleViewAction);
1451         toolBar->addAction(splitViewAction);
1452         toolBar->addAction(fullViewAction);
1453
1454         // create config menu
1455         QMenu* config = menu->addMenu(_("&File"));
1456         config->addAction(loadAction);
1457         config->addAction(saveAction);
1458         config->addAction(saveAsAction);
1459         config->addSeparator();
1460         config->addAction(quitAction);
1461
1462         // create edit menu
1463         QMenu* editMenu = menu->addMenu(_("&Edit"));
1464         editMenu->addAction(searchAction);
1465
1466         // create options menu
1467         QMenu* optionMenu = menu->addMenu(_("&Option"));
1468         optionMenu->addAction(showNameAction);
1469         optionMenu->addAction(showRangeAction);
1470         optionMenu->addAction(showDataAction);
1471         optionMenu->addSeparator();
1472         optionMenu->addActions(optGroup->actions());
1473         optionMenu->addSeparator();
1474
1475         // create help menu
1476         menu->addSeparator();
1477         QMenu* helpMenu = menu->addMenu(_("&Help"));
1478         helpMenu->addAction(showIntroAction);
1479         helpMenu->addAction(showAboutAction);
1480
1481         connect(configList, SIGNAL(menuChanged(struct menu *)),
1482                 helpText, SLOT(setInfo(struct menu *)));
1483         connect(configList, SIGNAL(menuSelected(struct menu *)),
1484                 SLOT(changeMenu(struct menu *)));
1485         connect(configList, SIGNAL(parentSelected()),
1486                 SLOT(goBack()));
1487         connect(menuList, SIGNAL(menuChanged(struct menu *)),
1488                 helpText, SLOT(setInfo(struct menu *)));
1489         connect(menuList, SIGNAL(menuSelected(struct menu *)),
1490                 SLOT(changeMenu(struct menu *)));
1491
1492         connect(configList, SIGNAL(gotFocus(struct menu *)),
1493                 helpText, SLOT(setInfo(struct menu *)));
1494         connect(menuList, SIGNAL(gotFocus(struct menu *)),
1495                 helpText, SLOT(setInfo(struct menu *)));
1496         connect(menuList, SIGNAL(gotFocus(struct menu *)),
1497                 SLOT(listFocusChanged(void)));
1498         connect(helpText, SIGNAL(menuSelected(struct menu *)),
1499                 SLOT(setMenuLink(struct menu *)));
1500
1501         QString listMode = configSettings->value("/listMode", "symbol").toString();
1502         if (listMode == "single")
1503                 showSingleView();
1504         else if (listMode == "full")
1505                 showFullView();
1506         else /*if (listMode == "split")*/
1507                 showSplitView();
1508
1509         // UI setup done, restore splitter positions
1510         QList<int> sizes = configSettings->readSizes("/split1", &ok);
1511         if (ok)
1512                 split1->setSizes(sizes);
1513
1514         sizes = configSettings->readSizes("/split2", &ok);
1515         if (ok)
1516                 split2->setSizes(sizes);
1517 }
1518
1519 void ConfigMainWindow::loadConfig(void)
1520 {
1521         QString s = QFileDialog::getOpenFileName(this, "", conf_get_configname());
1522         if (s.isNull())
1523                 return;
1524         if (conf_read(QFile::encodeName(s)))
1525                 QMessageBox::information(this, "qconf", _("Unable to load configuration!"));
1526         ConfigView::updateListAll();
1527 }
1528
1529 bool ConfigMainWindow::saveConfig(void)
1530 {
1531         if (conf_write(NULL)) {
1532                 QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
1533                 return false;
1534         }
1535         return true;
1536 }
1537
1538 void ConfigMainWindow::saveConfigAs(void)
1539 {
1540         QString s = QFileDialog::getSaveFileName(this, "", conf_get_configname());
1541         if (s.isNull())
1542                 return;
1543         saveConfig();
1544 }
1545
1546 void ConfigMainWindow::searchConfig(void)
1547 {
1548         if (!searchWindow)
1549                 searchWindow = new ConfigSearchWindow(this, "search");
1550         searchWindow->show();
1551 }
1552
1553 void ConfigMainWindow::changeMenu(struct menu *menu)
1554 {
1555         configList->setRootMenu(menu);
1556         if (configList->rootEntry->parent == &rootmenu)
1557                 backAction->setEnabled(false);
1558         else
1559                 backAction->setEnabled(true);
1560 }
1561
1562 void ConfigMainWindow::setMenuLink(struct menu *menu)
1563 {
1564         struct menu *parent;
1565         ConfigList* list = NULL;
1566         ConfigItem* item;
1567
1568         if (configList->menuSkip(menu))
1569                 return;
1570
1571         switch (configList->mode) {
1572         case singleMode:
1573                 list = configList;
1574                 parent = menu_get_parent_menu(menu);
1575                 if (!parent)
1576                         return;
1577                 list->setRootMenu(parent);
1578                 break;
1579         case symbolMode:
1580                 if (menu->flags & MENU_ROOT) {
1581                         configList->setRootMenu(menu);
1582                         configList->clearSelection();
1583                         list = menuList;
1584                 } else {
1585                         list = configList;
1586                         parent = menu_get_parent_menu(menu->parent);
1587                         if (!parent)
1588                                 return;
1589                         item = menuList->findConfigItem(parent);
1590                         if (item) {
1591                                 item->setSelected(true);
1592                                 menuList->scrollToItem(item);
1593                         }
1594                         list->setRootMenu(parent);
1595                 }
1596                 break;
1597         case fullMode:
1598                 list = configList;
1599                 break;
1600         default:
1601                 break;
1602         }
1603
1604         if (list) {
1605                 item = list->findConfigItem(menu);
1606                 if (item) {
1607                         item->setSelected(true);
1608                         list->scrollToItem(item);
1609                         list->setFocus();
1610                 }
1611         }
1612 }
1613
1614 void ConfigMainWindow::listFocusChanged(void)
1615 {
1616         if (menuList->mode == menuMode)
1617                 configList->clearSelection();
1618 }
1619
1620 void ConfigMainWindow::goBack(void)
1621 {
1622         ConfigItem* item, *oldSelection;
1623
1624         configList->setParentMenu();
1625         if (configList->rootEntry == &rootmenu)
1626                 backAction->setEnabled(false);
1627         item = (ConfigItem*)menuList->selectedItems().first();
1628         oldSelection = item;
1629         while (item) {
1630                 if (item->menu == configList->rootEntry) {
1631                         oldSelection->setSelected(false);
1632                         item->setSelected(true);
1633                         break;
1634                 }
1635                 item = (ConfigItem*)item->parent();
1636         }
1637 }
1638
1639 void ConfigMainWindow::showSingleView(void)
1640 {
1641         singleViewAction->setEnabled(false);
1642         singleViewAction->setChecked(true);
1643         splitViewAction->setEnabled(true);
1644         splitViewAction->setChecked(false);
1645         fullViewAction->setEnabled(true);
1646         fullViewAction->setChecked(false);
1647
1648         menuView->hide();
1649         menuList->setRootMenu(0);
1650         configList->mode = singleMode;
1651         if (configList->rootEntry == &rootmenu)
1652                 configList->updateListAll();
1653         else
1654                 configList->setRootMenu(&rootmenu);
1655         configList->setFocus();
1656 }
1657
1658 void ConfigMainWindow::showSplitView(void)
1659 {
1660         singleViewAction->setEnabled(true);
1661         singleViewAction->setChecked(false);
1662         splitViewAction->setEnabled(false);
1663         splitViewAction->setChecked(true);
1664         fullViewAction->setEnabled(true);
1665         fullViewAction->setChecked(false);
1666
1667         configList->mode = symbolMode;
1668         if (configList->rootEntry == &rootmenu)
1669                 configList->updateListAll();
1670         else
1671                 configList->setRootMenu(&rootmenu);
1672         configList->setAllOpen(true);
1673         configApp->processEvents();
1674         menuList->mode = menuMode;
1675         menuList->setRootMenu(&rootmenu);
1676         menuList->setAllOpen(true);
1677         menuView->show();
1678         menuList->setFocus();
1679 }
1680
1681 void ConfigMainWindow::showFullView(void)
1682 {
1683         singleViewAction->setEnabled(true);
1684         singleViewAction->setChecked(false);
1685         splitViewAction->setEnabled(true);
1686         splitViewAction->setChecked(false);
1687         fullViewAction->setEnabled(false);
1688         fullViewAction->setChecked(true);
1689
1690         menuView->hide();
1691         menuList->setRootMenu(0);
1692         configList->mode = fullMode;
1693         if (configList->rootEntry == &rootmenu)
1694                 configList->updateListAll();
1695         else
1696                 configList->setRootMenu(&rootmenu);
1697         configList->setFocus();
1698 }
1699
1700 /*
1701  * ask for saving configuration before quitting
1702  * TODO ask only when something changed
1703  */
1704 void ConfigMainWindow::closeEvent(QCloseEvent* e)
1705 {
1706         if (!conf_get_changed()) {
1707                 e->accept();
1708                 return;
1709         }
1710         QMessageBox mb("qconf", _("Save configuration?"), QMessageBox::Warning,
1711                         QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
1712         mb.setButtonText(QMessageBox::Yes, _("&Save Changes"));
1713         mb.setButtonText(QMessageBox::No, _("&Discard Changes"));
1714         mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit"));
1715         switch (mb.exec()) {
1716         case QMessageBox::Yes:
1717                 if (saveConfig())
1718                         e->accept();
1719                 else
1720                         e->ignore();
1721                 break;
1722         case QMessageBox::No:
1723                 e->accept();
1724                 break;
1725         case QMessageBox::Cancel:
1726                 e->ignore();
1727                 break;
1728         }
1729 }
1730
1731 void ConfigMainWindow::showIntro(void)
1732 {
1733         static const QString str = _("Welcome to the qconf graphical configuration tool.\n\n"
1734                 "For each option, a blank box indicates the feature is disabled, a check\n"
1735                 "indicates it is enabled, and a dot indicates that it is to be compiled\n"
1736                 "as a module.  Clicking on the box will cycle through the three states.\n\n"
1737                 "If you do not see an option (e.g., a device driver) that you believe\n"
1738                 "should be present, try turning on Show All Options under the Options menu.\n"
1739                 "Although there is no cross reference yet to help you figure out what other\n"
1740                 "options must be enabled to support the option you are interested in, you can\n"
1741                 "still view the help of a grayed-out option.\n\n"
1742                 "Toggling Show Debug Info under the Options menu will show the dependencies,\n"
1743                 "which you can then match by examining other options.\n\n");
1744
1745         QMessageBox::information(this, "qconf", str);
1746 }
1747
1748 void ConfigMainWindow::showAbout(void)
1749 {
1750         static const QString str = _("qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n"
1751                 "Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>.\n\n"
1752                 "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n");
1753
1754         QMessageBox::information(this, "qconf", str);
1755 }
1756
1757 void ConfigMainWindow::saveSettings(void)
1758 {
1759         configSettings->setValue("/window x", pos().x());
1760         configSettings->setValue("/window y", pos().y());
1761         configSettings->setValue("/window width", size().width());
1762         configSettings->setValue("/window height", size().height());
1763
1764         QString entry;
1765         switch(configList->mode) {
1766         case singleMode :
1767                 entry = "single";
1768                 break;
1769
1770         case symbolMode :
1771                 entry = "split";
1772                 break;
1773
1774         case fullMode :
1775                 entry = "full";
1776                 break;
1777
1778         default:
1779                 break;
1780         }
1781         configSettings->setValue("/listMode", entry);
1782
1783         configSettings->writeSizes("/split1", split1->sizes());
1784         configSettings->writeSizes("/split2", split2->sizes());
1785 }
1786
1787 void ConfigMainWindow::conf_changed(void)
1788 {
1789         if (saveAction)
1790                 saveAction->setEnabled(conf_get_changed());
1791 }
1792
1793 void fixup_rootmenu(struct menu *menu)
1794 {
1795         struct menu *child;
1796         static int menu_cnt = 0;
1797
1798         menu->flags |= MENU_ROOT;
1799         for (child = menu->list; child; child = child->next) {
1800                 if (child->prompt && child->prompt->type == P_MENU) {
1801                         menu_cnt++;
1802                         fixup_rootmenu(child);
1803                         menu_cnt--;
1804                 } else if (!menu_cnt)
1805                         fixup_rootmenu(child);
1806         }
1807 }
1808
1809 static const char *progname;
1810
1811 static void usage(void)
1812 {
1813         printf(_("%s [-s] <config>\n").toLatin1().constData(), progname);
1814         exit(0);
1815 }
1816
1817 int main(int ac, char** av)
1818 {
1819         ConfigMainWindow* v;
1820         const char *name;
1821
1822         bindtextdomain(PACKAGE, LOCALEDIR);
1823         textdomain(PACKAGE);
1824
1825         progname = av[0];
1826         configApp = new QApplication(ac, av);
1827         if (ac > 1 && av[1][0] == '-') {
1828                 switch (av[1][1]) {
1829                 case 's':
1830                         conf_set_message_callback(NULL);
1831                         break;
1832                 case 'h':
1833                 case '?':
1834                         usage();
1835                 }
1836                 name = av[2];
1837         } else
1838                 name = av[1];
1839         if (!name)
1840                 usage();
1841
1842         conf_parse(name);
1843         fixup_rootmenu(&rootmenu);
1844         conf_read(NULL);
1845         //zconfdump(stdout);
1846
1847         configSettings = new ConfigSettings();
1848         configSettings->beginGroup("/kconfig/qconf");
1849         v = new ConfigMainWindow();
1850
1851         //zconfdump(stdout);
1852         configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
1853         configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1854         v->show();
1855         configApp->exec();
1856
1857         configSettings->endGroup();
1858         delete configSettings;
1859
1860         return 0;
1861 }