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