Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
0004  * Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>
0005  */
0006 
0007 #include <QAction>
0008 #include <QApplication>
0009 #include <QCloseEvent>
0010 #include <QDebug>
0011 #include <QDesktopWidget>
0012 #include <QFileDialog>
0013 #include <QLabel>
0014 #include <QLayout>
0015 #include <QList>
0016 #include <QMenu>
0017 #include <QMenuBar>
0018 #include <QMessageBox>
0019 #include <QToolBar>
0020 
0021 #include <stdlib.h>
0022 
0023 #include "lkc.h"
0024 #include "qconf.h"
0025 
0026 #include "images.h"
0027 
0028 
0029 static QApplication *configApp;
0030 static ConfigSettings *configSettings;
0031 
0032 QAction *ConfigMainWindow::saveAction;
0033 
0034 ConfigSettings::ConfigSettings()
0035     : QSettings("kernel.org", "qconf")
0036 {
0037 }
0038 
0039 /**
0040  * Reads a list of integer values from the application settings.
0041  */
0042 QList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
0043 {
0044     QList<int> result;
0045 
0046     if (contains(key))
0047     {
0048         QStringList entryList = value(key).toStringList();
0049         QStringList::Iterator it;
0050 
0051         for (it = entryList.begin(); it != entryList.end(); ++it)
0052             result.push_back((*it).toInt());
0053 
0054         *ok = true;
0055     }
0056     else
0057         *ok = false;
0058 
0059     return result;
0060 }
0061 
0062 /**
0063  * Writes a list of integer values to the application settings.
0064  */
0065 bool ConfigSettings::writeSizes(const QString& key, const QList<int>& value)
0066 {
0067     QStringList stringList;
0068     QList<int>::ConstIterator it;
0069 
0070     for (it = value.begin(); it != value.end(); ++it)
0071         stringList.push_back(QString::number(*it));
0072     setValue(key, stringList);
0073 
0074     return true;
0075 }
0076 
0077 QIcon ConfigItem::symbolYesIcon;
0078 QIcon ConfigItem::symbolModIcon;
0079 QIcon ConfigItem::symbolNoIcon;
0080 QIcon ConfigItem::choiceYesIcon;
0081 QIcon ConfigItem::choiceNoIcon;
0082 QIcon ConfigItem::menuIcon;
0083 QIcon ConfigItem::menubackIcon;
0084 
0085 /*
0086  * update the displayed of a menu entry
0087  */
0088 void ConfigItem::updateMenu(void)
0089 {
0090     ConfigList* list;
0091     struct symbol* sym;
0092     struct property *prop;
0093     QString prompt;
0094     int type;
0095     tristate expr;
0096 
0097     list = listView();
0098     if (goParent) {
0099         setIcon(promptColIdx, menubackIcon);
0100         prompt = "..";
0101         goto set_prompt;
0102     }
0103 
0104     sym = menu->sym;
0105     prop = menu->prompt;
0106     prompt = menu_get_prompt(menu);
0107 
0108     if (prop) switch (prop->type) {
0109     case P_MENU:
0110         if (list->mode == singleMode || list->mode == symbolMode) {
0111             /* a menuconfig entry is displayed differently
0112              * depending whether it's at the view root or a child.
0113              */
0114             if (sym && list->rootEntry == menu)
0115                 break;
0116             setIcon(promptColIdx, menuIcon);
0117         } else {
0118             if (sym)
0119                 break;
0120             setIcon(promptColIdx, QIcon());
0121         }
0122         goto set_prompt;
0123     case P_COMMENT:
0124         setIcon(promptColIdx, QIcon());
0125         prompt = "*** " + prompt + " ***";
0126         goto set_prompt;
0127     default:
0128         ;
0129     }
0130     if (!sym)
0131         goto set_prompt;
0132 
0133     setText(nameColIdx, sym->name);
0134 
0135     type = sym_get_type(sym);
0136     switch (type) {
0137     case S_BOOLEAN:
0138     case S_TRISTATE:
0139         char ch;
0140 
0141         if (!sym_is_changeable(sym) && list->optMode == normalOpt) {
0142             setIcon(promptColIdx, QIcon());
0143             break;
0144         }
0145         expr = sym_get_tristate_value(sym);
0146         switch (expr) {
0147         case yes:
0148             if (sym_is_choice_value(sym) && type == S_BOOLEAN)
0149                 setIcon(promptColIdx, choiceYesIcon);
0150             else
0151                 setIcon(promptColIdx, symbolYesIcon);
0152             ch = 'Y';
0153             break;
0154         case mod:
0155             setIcon(promptColIdx, symbolModIcon);
0156             ch = 'M';
0157             break;
0158         default:
0159             if (sym_is_choice_value(sym) && type == S_BOOLEAN)
0160                 setIcon(promptColIdx, choiceNoIcon);
0161             else
0162                 setIcon(promptColIdx, symbolNoIcon);
0163             ch = 'N';
0164             break;
0165         }
0166 
0167         setText(dataColIdx, QChar(ch));
0168         break;
0169     case S_INT:
0170     case S_HEX:
0171     case S_STRING:
0172         setText(dataColIdx, sym_get_string_value(sym));
0173         break;
0174     }
0175     if (!sym_has_value(sym) && visible)
0176         prompt += " (NEW)";
0177 set_prompt:
0178     setText(promptColIdx, prompt);
0179 }
0180 
0181 void ConfigItem::testUpdateMenu(bool v)
0182 {
0183     ConfigItem* i;
0184 
0185     visible = v;
0186     if (!menu)
0187         return;
0188 
0189     sym_calc_value(menu->sym);
0190     if (menu->flags & MENU_CHANGED) {
0191         /* the menu entry changed, so update all list items */
0192         menu->flags &= ~MENU_CHANGED;
0193         for (i = (ConfigItem*)menu->data; i; i = i->nextItem)
0194             i->updateMenu();
0195     } else if (listView()->updateAll)
0196         updateMenu();
0197 }
0198 
0199 
0200 /*
0201  * construct a menu entry
0202  */
0203 void ConfigItem::init(void)
0204 {
0205     if (menu) {
0206         ConfigList* list = listView();
0207         nextItem = (ConfigItem*)menu->data;
0208         menu->data = this;
0209 
0210         if (list->mode != fullMode)
0211             setExpanded(true);
0212         sym_calc_value(menu->sym);
0213 
0214         if (menu->sym) {
0215             enum symbol_type type = menu->sym->type;
0216 
0217             // Allow to edit "int", "hex", and "string" in-place in
0218             // the data column. Unfortunately, you cannot specify
0219             // the flags per column. Set ItemIsEditable for all
0220             // columns here, and check the column in createEditor().
0221             if (type == S_INT || type == S_HEX || type == S_STRING)
0222                 setFlags(flags() | Qt::ItemIsEditable);
0223         }
0224     }
0225     updateMenu();
0226 }
0227 
0228 /*
0229  * destruct a menu entry
0230  */
0231 ConfigItem::~ConfigItem(void)
0232 {
0233     if (menu) {
0234         ConfigItem** ip = (ConfigItem**)&menu->data;
0235         for (; *ip; ip = &(*ip)->nextItem) {
0236             if (*ip == this) {
0237                 *ip = nextItem;
0238                 break;
0239             }
0240         }
0241     }
0242 }
0243 
0244 QWidget *ConfigItemDelegate::createEditor(QWidget *parent,
0245                       const QStyleOptionViewItem &option,
0246                       const QModelIndex &index) const
0247 {
0248     ConfigItem *item;
0249 
0250     // Only the data column is editable
0251     if (index.column() != dataColIdx)
0252         return nullptr;
0253 
0254     // You cannot edit invisible menus
0255     item = static_cast<ConfigItem *>(index.internalPointer());
0256     if (!item || !item->menu || !menu_is_visible(item->menu))
0257         return nullptr;
0258 
0259     return QStyledItemDelegate::createEditor(parent, option, index);
0260 }
0261 
0262 void ConfigItemDelegate::setModelData(QWidget *editor,
0263                       QAbstractItemModel *model,
0264                       const QModelIndex &index) const
0265 {
0266     QLineEdit *lineEdit;
0267     ConfigItem *item;
0268     struct symbol *sym;
0269     bool success;
0270 
0271     lineEdit = qobject_cast<QLineEdit *>(editor);
0272     // If this is not a QLineEdit, use the parent's default.
0273     // (does this happen?)
0274     if (!lineEdit)
0275         goto parent;
0276 
0277     item = static_cast<ConfigItem *>(index.internalPointer());
0278     if (!item || !item->menu)
0279         goto parent;
0280 
0281     sym = item->menu->sym;
0282     if (!sym)
0283         goto parent;
0284 
0285     success = sym_set_string_value(sym, lineEdit->text().toUtf8().data());
0286     if (success) {
0287         ConfigList::updateListForAll();
0288     } else {
0289         QMessageBox::information(editor, "qconf",
0290             "Cannot set the data (maybe due to out of range).\n"
0291             "Setting the old value.");
0292         lineEdit->setText(sym_get_string_value(sym));
0293     }
0294 
0295 parent:
0296     QStyledItemDelegate::setModelData(editor, model, index);
0297 }
0298 
0299 ConfigList::ConfigList(QWidget *parent, const char *name)
0300     : QTreeWidget(parent),
0301       updateAll(false),
0302       showName(false), mode(singleMode), optMode(normalOpt),
0303       rootEntry(0), headerPopup(0)
0304 {
0305     setObjectName(name);
0306     setSortingEnabled(false);
0307     setRootIsDecorated(true);
0308 
0309     setVerticalScrollMode(ScrollPerPixel);
0310     setHorizontalScrollMode(ScrollPerPixel);
0311 
0312     setHeaderLabels(QStringList() << "Option" << "Name" << "Value");
0313 
0314     connect(this, &ConfigList::itemSelectionChanged,
0315         this, &ConfigList::updateSelection);
0316 
0317     if (name) {
0318         configSettings->beginGroup(name);
0319         showName = configSettings->value("/showName", false).toBool();
0320         optMode = (enum optionMode)configSettings->value("/optionMode", 0).toInt();
0321         configSettings->endGroup();
0322         connect(configApp, &QApplication::aboutToQuit,
0323             this, &ConfigList::saveSettings);
0324     }
0325 
0326     showColumn(promptColIdx);
0327 
0328     setItemDelegate(new ConfigItemDelegate(this));
0329 
0330     allLists.append(this);
0331 
0332     reinit();
0333 }
0334 
0335 ConfigList::~ConfigList()
0336 {
0337     allLists.removeOne(this);
0338 }
0339 
0340 bool ConfigList::menuSkip(struct menu *menu)
0341 {
0342     if (optMode == normalOpt && menu_is_visible(menu))
0343         return false;
0344     if (optMode == promptOpt && menu_has_prompt(menu))
0345         return false;
0346     if (optMode == allOpt)
0347         return false;
0348     return true;
0349 }
0350 
0351 void ConfigList::reinit(void)
0352 {
0353     hideColumn(nameColIdx);
0354 
0355     if (showName)
0356         showColumn(nameColIdx);
0357 
0358     updateListAll();
0359 }
0360 
0361 void ConfigList::setOptionMode(QAction *action)
0362 {
0363     if (action == showNormalAction)
0364         optMode = normalOpt;
0365     else if (action == showAllAction)
0366         optMode = allOpt;
0367     else
0368         optMode = promptOpt;
0369 
0370     updateListAll();
0371 }
0372 
0373 void ConfigList::saveSettings(void)
0374 {
0375     if (!objectName().isEmpty()) {
0376         configSettings->beginGroup(objectName());
0377         configSettings->setValue("/showName", showName);
0378         configSettings->setValue("/optionMode", (int)optMode);
0379         configSettings->endGroup();
0380     }
0381 }
0382 
0383 ConfigItem* ConfigList::findConfigItem(struct menu *menu)
0384 {
0385     ConfigItem* item = (ConfigItem*)menu->data;
0386 
0387     for (; item; item = item->nextItem) {
0388         if (this == item->listView())
0389             break;
0390     }
0391 
0392     return item;
0393 }
0394 
0395 void ConfigList::updateSelection(void)
0396 {
0397     struct menu *menu;
0398     enum prop_type type;
0399 
0400     if (selectedItems().count() == 0)
0401         return;
0402 
0403     ConfigItem* item = (ConfigItem*)selectedItems().first();
0404     if (!item)
0405         return;
0406 
0407     menu = item->menu;
0408     emit menuChanged(menu);
0409     if (!menu)
0410         return;
0411     type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
0412     if (mode == menuMode && type == P_MENU)
0413         emit menuSelected(menu);
0414 }
0415 
0416 void ConfigList::updateList()
0417 {
0418     ConfigItem* last = 0;
0419     ConfigItem *item;
0420 
0421     if (!rootEntry) {
0422         if (mode != listMode)
0423             goto update;
0424         QTreeWidgetItemIterator it(this);
0425 
0426         while (*it) {
0427             item = (ConfigItem*)(*it);
0428             if (!item->menu)
0429                 continue;
0430             item->testUpdateMenu(menu_is_visible(item->menu));
0431 
0432             ++it;
0433         }
0434         return;
0435     }
0436 
0437     if (rootEntry != &rootmenu && (mode == singleMode ||
0438         (mode == symbolMode && rootEntry->parent != &rootmenu))) {
0439         item = (ConfigItem *)topLevelItem(0);
0440         if (!item)
0441             item = new ConfigItem(this, 0, true);
0442         last = item;
0443     }
0444     if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) &&
0445         rootEntry->sym && rootEntry->prompt) {
0446         item = last ? last->nextSibling() : nullptr;
0447         if (!item)
0448             item = new ConfigItem(this, last, rootEntry, true);
0449         else
0450             item->testUpdateMenu(true);
0451 
0452         updateMenuList(item, rootEntry);
0453         update();
0454         resizeColumnToContents(0);
0455         return;
0456     }
0457 update:
0458     updateMenuList(rootEntry);
0459     update();
0460     resizeColumnToContents(0);
0461 }
0462 
0463 void ConfigList::updateListForAll()
0464 {
0465     QListIterator<ConfigList *> it(allLists);
0466 
0467     while (it.hasNext()) {
0468         ConfigList *list = it.next();
0469 
0470         list->updateList();
0471     }
0472 }
0473 
0474 void ConfigList::updateListAllForAll()
0475 {
0476     QListIterator<ConfigList *> it(allLists);
0477 
0478     while (it.hasNext()) {
0479         ConfigList *list = it.next();
0480 
0481         list->updateList();
0482     }
0483 }
0484 
0485 void ConfigList::setValue(ConfigItem* item, tristate val)
0486 {
0487     struct symbol* sym;
0488     int type;
0489     tristate oldval;
0490 
0491     sym = item->menu ? item->menu->sym : 0;
0492     if (!sym)
0493         return;
0494 
0495     type = sym_get_type(sym);
0496     switch (type) {
0497     case S_BOOLEAN:
0498     case S_TRISTATE:
0499         oldval = sym_get_tristate_value(sym);
0500 
0501         if (!sym_set_tristate_value(sym, val))
0502             return;
0503         if (oldval == no && item->menu->list)
0504             item->setExpanded(true);
0505         ConfigList::updateListForAll();
0506         break;
0507     }
0508 }
0509 
0510 void ConfigList::changeValue(ConfigItem* item)
0511 {
0512     struct symbol* sym;
0513     struct menu* menu;
0514     int type, oldexpr, newexpr;
0515 
0516     menu = item->menu;
0517     if (!menu)
0518         return;
0519     sym = menu->sym;
0520     if (!sym) {
0521         if (item->menu->list)
0522             item->setExpanded(!item->isExpanded());
0523         return;
0524     }
0525 
0526     type = sym_get_type(sym);
0527     switch (type) {
0528     case S_BOOLEAN:
0529     case S_TRISTATE:
0530         oldexpr = sym_get_tristate_value(sym);
0531         newexpr = sym_toggle_tristate_value(sym);
0532         if (item->menu->list) {
0533             if (oldexpr == newexpr)
0534                 item->setExpanded(!item->isExpanded());
0535             else if (oldexpr == no)
0536                 item->setExpanded(true);
0537         }
0538         if (oldexpr != newexpr)
0539             ConfigList::updateListForAll();
0540         break;
0541     default:
0542         break;
0543     }
0544 }
0545 
0546 void ConfigList::setRootMenu(struct menu *menu)
0547 {
0548     enum prop_type type;
0549 
0550     if (rootEntry == menu)
0551         return;
0552     type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
0553     if (type != P_MENU)
0554         return;
0555     updateMenuList(0);
0556     rootEntry = menu;
0557     updateListAll();
0558     if (currentItem()) {
0559         setSelected(currentItem(), hasFocus());
0560         scrollToItem(currentItem());
0561     }
0562 }
0563 
0564 void ConfigList::setParentMenu(void)
0565 {
0566     ConfigItem* item;
0567     struct menu *oldroot;
0568 
0569     oldroot = rootEntry;
0570     if (rootEntry == &rootmenu)
0571         return;
0572     setRootMenu(menu_get_parent_menu(rootEntry->parent));
0573 
0574     QTreeWidgetItemIterator it(this);
0575     while (*it) {
0576         item = (ConfigItem *)(*it);
0577         if (item->menu == oldroot) {
0578             setCurrentItem(item);
0579             scrollToItem(item);
0580             break;
0581         }
0582 
0583         ++it;
0584     }
0585 }
0586 
0587 /*
0588  * update all the children of a menu entry
0589  *   removes/adds the entries from the parent widget as necessary
0590  *
0591  * parent: either the menu list widget or a menu entry widget
0592  * menu: entry to be updated
0593  */
0594 void ConfigList::updateMenuList(ConfigItem *parent, struct menu* menu)
0595 {
0596     struct menu* child;
0597     ConfigItem* item;
0598     ConfigItem* last;
0599     bool visible;
0600     enum prop_type type;
0601 
0602     if (!menu) {
0603         while (parent->childCount() > 0)
0604         {
0605             delete parent->takeChild(0);
0606         }
0607 
0608         return;
0609     }
0610 
0611     last = parent->firstChild();
0612     if (last && !last->goParent)
0613         last = 0;
0614     for (child = menu->list; child; child = child->next) {
0615         item = last ? last->nextSibling() : parent->firstChild();
0616         type = child->prompt ? child->prompt->type : P_UNKNOWN;
0617 
0618         switch (mode) {
0619         case menuMode:
0620             if (!(child->flags & MENU_ROOT))
0621                 goto hide;
0622             break;
0623         case symbolMode:
0624             if (child->flags & MENU_ROOT)
0625                 goto hide;
0626             break;
0627         default:
0628             break;
0629         }
0630 
0631         visible = menu_is_visible(child);
0632         if (!menuSkip(child)) {
0633             if (!child->sym && !child->list && !child->prompt)
0634                 continue;
0635             if (!item || item->menu != child)
0636                 item = new ConfigItem(parent, last, child, visible);
0637             else
0638                 item->testUpdateMenu(visible);
0639 
0640             if (mode == fullMode || mode == menuMode || type != P_MENU)
0641                 updateMenuList(item, child);
0642             else
0643                 updateMenuList(item, 0);
0644             last = item;
0645             continue;
0646         }
0647 hide:
0648         if (item && item->menu == child) {
0649             last = parent->firstChild();
0650             if (last == item)
0651                 last = 0;
0652             else while (last->nextSibling() != item)
0653                 last = last->nextSibling();
0654             delete item;
0655         }
0656     }
0657 }
0658 
0659 void ConfigList::updateMenuList(struct menu *menu)
0660 {
0661     struct menu* child;
0662     ConfigItem* item;
0663     ConfigItem* last;
0664     bool visible;
0665     enum prop_type type;
0666 
0667     if (!menu) {
0668         while (topLevelItemCount() > 0)
0669         {
0670             delete takeTopLevelItem(0);
0671         }
0672 
0673         return;
0674     }
0675 
0676     last = (ConfigItem *)topLevelItem(0);
0677     if (last && !last->goParent)
0678         last = 0;
0679     for (child = menu->list; child; child = child->next) {
0680         item = last ? last->nextSibling() : (ConfigItem *)topLevelItem(0);
0681         type = child->prompt ? child->prompt->type : P_UNKNOWN;
0682 
0683         switch (mode) {
0684         case menuMode:
0685             if (!(child->flags & MENU_ROOT))
0686                 goto hide;
0687             break;
0688         case symbolMode:
0689             if (child->flags & MENU_ROOT)
0690                 goto hide;
0691             break;
0692         default:
0693             break;
0694         }
0695 
0696         visible = menu_is_visible(child);
0697         if (!menuSkip(child)) {
0698             if (!child->sym && !child->list && !child->prompt)
0699                 continue;
0700             if (!item || item->menu != child)
0701                 item = new ConfigItem(this, last, child, visible);
0702             else
0703                 item->testUpdateMenu(visible);
0704 
0705             if (mode == fullMode || mode == menuMode || type != P_MENU)
0706                 updateMenuList(item, child);
0707             else
0708                 updateMenuList(item, 0);
0709             last = item;
0710             continue;
0711         }
0712 hide:
0713         if (item && item->menu == child) {
0714             last = (ConfigItem *)topLevelItem(0);
0715             if (last == item)
0716                 last = 0;
0717             else while (last->nextSibling() != item)
0718                 last = last->nextSibling();
0719             delete item;
0720         }
0721     }
0722 }
0723 
0724 void ConfigList::keyPressEvent(QKeyEvent* ev)
0725 {
0726     QTreeWidgetItem* i = currentItem();
0727     ConfigItem* item;
0728     struct menu *menu;
0729     enum prop_type type;
0730 
0731     if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) {
0732         emit parentSelected();
0733         ev->accept();
0734         return;
0735     }
0736 
0737     if (!i) {
0738         Parent::keyPressEvent(ev);
0739         return;
0740     }
0741     item = (ConfigItem*)i;
0742 
0743     switch (ev->key()) {
0744     case Qt::Key_Return:
0745     case Qt::Key_Enter:
0746         if (item->goParent) {
0747             emit parentSelected();
0748             break;
0749         }
0750         menu = item->menu;
0751         if (!menu)
0752             break;
0753         type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
0754         if (type == P_MENU && rootEntry != menu &&
0755             mode != fullMode && mode != menuMode) {
0756             if (mode == menuMode)
0757                 emit menuSelected(menu);
0758             else
0759                 emit itemSelected(menu);
0760             break;
0761         }
0762     case Qt::Key_Space:
0763         changeValue(item);
0764         break;
0765     case Qt::Key_N:
0766         setValue(item, no);
0767         break;
0768     case Qt::Key_M:
0769         setValue(item, mod);
0770         break;
0771     case Qt::Key_Y:
0772         setValue(item, yes);
0773         break;
0774     default:
0775         Parent::keyPressEvent(ev);
0776         return;
0777     }
0778     ev->accept();
0779 }
0780 
0781 void ConfigList::mousePressEvent(QMouseEvent* e)
0782 {
0783     //QPoint p(contentsToViewport(e->pos()));
0784     //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
0785     Parent::mousePressEvent(e);
0786 }
0787 
0788 void ConfigList::mouseReleaseEvent(QMouseEvent* e)
0789 {
0790     QPoint p = e->pos();
0791     ConfigItem* item = (ConfigItem*)itemAt(p);
0792     struct menu *menu;
0793     enum prop_type ptype;
0794     QIcon icon;
0795     int idx, x;
0796 
0797     if (!item)
0798         goto skip;
0799 
0800     menu = item->menu;
0801     x = header()->offset() + p.x();
0802     idx = header()->logicalIndexAt(x);
0803     switch (idx) {
0804     case promptColIdx:
0805         icon = item->icon(promptColIdx);
0806         if (!icon.isNull()) {
0807             int off = header()->sectionPosition(0) + visualRect(indexAt(p)).x() + 4; // 4 is Hardcoded image offset. There might be a way to do it properly.
0808             if (x >= off && x < off + icon.availableSizes().first().width()) {
0809                 if (item->goParent) {
0810                     emit parentSelected();
0811                     break;
0812                 } else if (!menu)
0813                     break;
0814                 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
0815                 if (ptype == P_MENU && rootEntry != menu &&
0816                     mode != fullMode && mode != menuMode &&
0817                                     mode != listMode)
0818                     emit menuSelected(menu);
0819                 else
0820                     changeValue(item);
0821             }
0822         }
0823         break;
0824     case dataColIdx:
0825         changeValue(item);
0826         break;
0827     }
0828 
0829 skip:
0830     //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
0831     Parent::mouseReleaseEvent(e);
0832 }
0833 
0834 void ConfigList::mouseMoveEvent(QMouseEvent* e)
0835 {
0836     //QPoint p(contentsToViewport(e->pos()));
0837     //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
0838     Parent::mouseMoveEvent(e);
0839 }
0840 
0841 void ConfigList::mouseDoubleClickEvent(QMouseEvent* e)
0842 {
0843     QPoint p = e->pos();
0844     ConfigItem* item = (ConfigItem*)itemAt(p);
0845     struct menu *menu;
0846     enum prop_type ptype;
0847 
0848     if (!item)
0849         goto skip;
0850     if (item->goParent) {
0851         emit parentSelected();
0852         goto skip;
0853     }
0854     menu = item->menu;
0855     if (!menu)
0856         goto skip;
0857     ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
0858     if (ptype == P_MENU && mode != listMode) {
0859         if (mode == singleMode)
0860             emit itemSelected(menu);
0861         else if (mode == symbolMode)
0862             emit menuSelected(menu);
0863     } else if (menu->sym)
0864         changeValue(item);
0865 
0866 skip:
0867     //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
0868     Parent::mouseDoubleClickEvent(e);
0869 }
0870 
0871 void ConfigList::focusInEvent(QFocusEvent *e)
0872 {
0873     struct menu *menu = NULL;
0874 
0875     Parent::focusInEvent(e);
0876 
0877     ConfigItem* item = (ConfigItem *)currentItem();
0878     if (item) {
0879         setSelected(item, true);
0880         menu = item->menu;
0881     }
0882     emit gotFocus(menu);
0883 }
0884 
0885 void ConfigList::contextMenuEvent(QContextMenuEvent *e)
0886 {
0887     if (!headerPopup) {
0888         QAction *action;
0889 
0890         headerPopup = new QMenu(this);
0891         action = new QAction("Show Name", this);
0892         action->setCheckable(true);
0893         connect(action, &QAction::toggled,
0894             this, &ConfigList::setShowName);
0895         connect(this, &ConfigList::showNameChanged,
0896             action, &QAction::setChecked);
0897         action->setChecked(showName);
0898         headerPopup->addAction(action);
0899     }
0900 
0901     headerPopup->exec(e->globalPos());
0902     e->accept();
0903 }
0904 
0905 void ConfigList::setShowName(bool on)
0906 {
0907     if (showName == on)
0908         return;
0909 
0910     showName = on;
0911     reinit();
0912     emit showNameChanged(on);
0913 }
0914 
0915 QList<ConfigList *> ConfigList::allLists;
0916 QAction *ConfigList::showNormalAction;
0917 QAction *ConfigList::showAllAction;
0918 QAction *ConfigList::showPromptAction;
0919 
0920 void ConfigList::setAllOpen(bool open)
0921 {
0922     QTreeWidgetItemIterator it(this);
0923 
0924     while (*it) {
0925         (*it)->setExpanded(open);
0926 
0927         ++it;
0928     }
0929 }
0930 
0931 ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
0932     : Parent(parent), sym(0), _menu(0)
0933 {
0934     setObjectName(name);
0935     setOpenLinks(false);
0936 
0937     if (!objectName().isEmpty()) {
0938         configSettings->beginGroup(objectName());
0939         setShowDebug(configSettings->value("/showDebug", false).toBool());
0940         configSettings->endGroup();
0941         connect(configApp, &QApplication::aboutToQuit,
0942             this, &ConfigInfoView::saveSettings);
0943     }
0944 
0945     contextMenu = createStandardContextMenu();
0946     QAction *action = new QAction("Show Debug Info", contextMenu);
0947 
0948     action->setCheckable(true);
0949     connect(action, &QAction::toggled,
0950         this, &ConfigInfoView::setShowDebug);
0951     connect(this, &ConfigInfoView::showDebugChanged,
0952         action, &QAction::setChecked);
0953     action->setChecked(showDebug());
0954     contextMenu->addSeparator();
0955     contextMenu->addAction(action);
0956 }
0957 
0958 void ConfigInfoView::saveSettings(void)
0959 {
0960     if (!objectName().isEmpty()) {
0961         configSettings->beginGroup(objectName());
0962         configSettings->setValue("/showDebug", showDebug());
0963         configSettings->endGroup();
0964     }
0965 }
0966 
0967 void ConfigInfoView::setShowDebug(bool b)
0968 {
0969     if (_showDebug != b) {
0970         _showDebug = b;
0971         if (_menu)
0972             menuInfo();
0973         else if (sym)
0974             symbolInfo();
0975         emit showDebugChanged(b);
0976     }
0977 }
0978 
0979 void ConfigInfoView::setInfo(struct menu *m)
0980 {
0981     if (_menu == m)
0982         return;
0983     _menu = m;
0984     sym = NULL;
0985     if (!_menu)
0986         clear();
0987     else
0988         menuInfo();
0989 }
0990 
0991 void ConfigInfoView::symbolInfo(void)
0992 {
0993     QString str;
0994 
0995     str += "<big>Symbol: <b>";
0996     str += print_filter(sym->name);
0997     str += "</b></big><br><br>value: ";
0998     str += print_filter(sym_get_string_value(sym));
0999     str += "<br>visibility: ";
1000     str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n";
1001     str += "<br>";
1002     str += debug_info(sym);
1003 
1004     setText(str);
1005 }
1006 
1007 void ConfigInfoView::menuInfo(void)
1008 {
1009     struct symbol* sym;
1010     QString info;
1011     QTextStream stream(&info);
1012 
1013     sym = _menu->sym;
1014     if (sym) {
1015         if (_menu->prompt) {
1016             stream << "<big><b>";
1017             stream << print_filter(_menu->prompt->text);
1018             stream << "</b></big>";
1019             if (sym->name) {
1020                 stream << " (";
1021                 if (showDebug())
1022                     stream << "<a href=\"s" << sym->name << "\">";
1023                 stream << print_filter(sym->name);
1024                 if (showDebug())
1025                     stream << "</a>";
1026                 stream << ")";
1027             }
1028         } else if (sym->name) {
1029             stream << "<big><b>";
1030             if (showDebug())
1031                 stream << "<a href=\"s" << sym->name << "\">";
1032             stream << print_filter(sym->name);
1033             if (showDebug())
1034                 stream << "</a>";
1035             stream << "</b></big>";
1036         }
1037         stream << "<br><br>";
1038 
1039         if (showDebug())
1040             stream << debug_info(sym);
1041 
1042         struct gstr help_gstr = str_new();
1043 
1044         menu_get_ext_help(_menu, &help_gstr);
1045         stream << print_filter(str_get(&help_gstr));
1046         str_free(&help_gstr);
1047     } else if (_menu->prompt) {
1048         stream << "<big><b>";
1049         stream << print_filter(_menu->prompt->text);
1050         stream << "</b></big><br><br>";
1051         if (showDebug()) {
1052             if (_menu->prompt->visible.expr) {
1053                 stream << "&nbsp;&nbsp;dep: ";
1054                 expr_print(_menu->prompt->visible.expr,
1055                        expr_print_help, &stream, E_NONE);
1056                 stream << "<br><br>";
1057             }
1058 
1059             stream << "defined at " << _menu->file->name << ":"
1060                    << _menu->lineno << "<br><br>";
1061         }
1062     }
1063 
1064     setText(info);
1065 }
1066 
1067 QString ConfigInfoView::debug_info(struct symbol *sym)
1068 {
1069     QString debug;
1070     QTextStream stream(&debug);
1071 
1072     stream << "type: ";
1073     stream << print_filter(sym_type_name(sym->type));
1074     if (sym_is_choice(sym))
1075         stream << " (choice)";
1076     debug += "<br>";
1077     if (sym->rev_dep.expr) {
1078         stream << "reverse dep: ";
1079         expr_print(sym->rev_dep.expr, expr_print_help, &stream, E_NONE);
1080         stream << "<br>";
1081     }
1082     for (struct property *prop = sym->prop; prop; prop = prop->next) {
1083         switch (prop->type) {
1084         case P_PROMPT:
1085         case P_MENU:
1086             stream << "prompt: <a href=\"m" << sym->name << "\">";
1087             stream << print_filter(prop->text);
1088             stream << "</a><br>";
1089             break;
1090         case P_DEFAULT:
1091         case P_SELECT:
1092         case P_RANGE:
1093         case P_COMMENT:
1094         case P_IMPLY:
1095         case P_SYMBOL:
1096             stream << prop_get_type_name(prop->type);
1097             stream << ": ";
1098             expr_print(prop->expr, expr_print_help,
1099                    &stream, E_NONE);
1100             stream << "<br>";
1101             break;
1102         case P_CHOICE:
1103             if (sym_is_choice(sym)) {
1104                 stream << "choice: ";
1105                 expr_print(prop->expr, expr_print_help,
1106                        &stream, E_NONE);
1107                 stream << "<br>";
1108             }
1109             break;
1110         default:
1111             stream << "unknown property: ";
1112             stream << prop_get_type_name(prop->type);
1113             stream << "<br>";
1114         }
1115         if (prop->visible.expr) {
1116             stream << "&nbsp;&nbsp;&nbsp;&nbsp;dep: ";
1117             expr_print(prop->visible.expr, expr_print_help,
1118                    &stream, E_NONE);
1119             stream << "<br>";
1120         }
1121     }
1122     stream << "<br>";
1123 
1124     return debug;
1125 }
1126 
1127 QString ConfigInfoView::print_filter(const QString &str)
1128 {
1129     QRegExp re("[<>&\"\\n]");
1130     QString res = str;
1131     for (int i = 0; (i = res.indexOf(re, i)) >= 0;) {
1132         switch (res[i].toLatin1()) {
1133         case '<':
1134             res.replace(i, 1, "&lt;");
1135             i += 4;
1136             break;
1137         case '>':
1138             res.replace(i, 1, "&gt;");
1139             i += 4;
1140             break;
1141         case '&':
1142             res.replace(i, 1, "&amp;");
1143             i += 5;
1144             break;
1145         case '"':
1146             res.replace(i, 1, "&quot;");
1147             i += 6;
1148             break;
1149         case '\n':
1150             res.replace(i, 1, "<br>");
1151             i += 4;
1152             break;
1153         }
1154     }
1155     return res;
1156 }
1157 
1158 void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str)
1159 {
1160     QTextStream *stream = reinterpret_cast<QTextStream *>(data);
1161 
1162     if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
1163         *stream << "<a href=\"s" << sym->name << "\">";
1164         *stream << print_filter(str);
1165         *stream << "</a>";
1166     } else {
1167         *stream << print_filter(str);
1168     }
1169 }
1170 
1171 void ConfigInfoView::clicked(const QUrl &url)
1172 {
1173     QByteArray str = url.toEncoded();
1174     const std::size_t count = str.size();
1175     char *data = new char[count + 1];
1176     struct symbol **result;
1177     struct menu *m = NULL;
1178 
1179     if (count < 1) {
1180         delete[] data;
1181         return;
1182     }
1183 
1184     memcpy(data, str.constData(), count);
1185     data[count] = '\0';
1186 
1187     /* Seek for exact match */
1188     data[0] = '^';
1189     strcat(data, "$");
1190     result = sym_re_search(data);
1191     if (!result) {
1192         delete[] data;
1193         return;
1194     }
1195 
1196     sym = *result;
1197 
1198     /* Seek for the menu which holds the symbol */
1199     for (struct property *prop = sym->prop; prop; prop = prop->next) {
1200             if (prop->type != P_PROMPT && prop->type != P_MENU)
1201                 continue;
1202             m = prop->menu;
1203             break;
1204     }
1205 
1206     if (!m) {
1207         /* Symbol is not visible as a menu */
1208         symbolInfo();
1209         emit showDebugChanged(true);
1210     } else {
1211         emit menuSelected(m);
1212     }
1213 
1214     free(result);
1215     delete[] data;
1216 }
1217 
1218 void ConfigInfoView::contextMenuEvent(QContextMenuEvent *event)
1219 {
1220     contextMenu->popup(event->globalPos());
1221     event->accept();
1222 }
1223 
1224 ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow *parent)
1225     : Parent(parent), result(NULL)
1226 {
1227     setObjectName("search");
1228     setWindowTitle("Search Config");
1229 
1230     QVBoxLayout* layout1 = new QVBoxLayout(this);
1231     layout1->setContentsMargins(11, 11, 11, 11);
1232     layout1->setSpacing(6);
1233 
1234     QHBoxLayout* layout2 = new QHBoxLayout();
1235     layout2->setContentsMargins(0, 0, 0, 0);
1236     layout2->setSpacing(6);
1237     layout2->addWidget(new QLabel("Find:", this));
1238     editField = new QLineEdit(this);
1239     connect(editField, &QLineEdit::returnPressed,
1240         this, &ConfigSearchWindow::search);
1241     layout2->addWidget(editField);
1242     searchButton = new QPushButton("Search", this);
1243     searchButton->setAutoDefault(false);
1244     connect(searchButton, &QPushButton::clicked,
1245         this, &ConfigSearchWindow::search);
1246     layout2->addWidget(searchButton);
1247     layout1->addLayout(layout2);
1248 
1249     split = new QSplitter(this);
1250     split->setOrientation(Qt::Vertical);
1251     list = new ConfigList(split, "search");
1252     list->mode = listMode;
1253     info = new ConfigInfoView(split, "search");
1254     connect(list, &ConfigList::menuChanged,
1255         info, &ConfigInfoView::setInfo);
1256     connect(list, &ConfigList::menuChanged,
1257         parent, &ConfigMainWindow::setMenuLink);
1258 
1259     layout1->addWidget(split);
1260 
1261     QVariant x, y;
1262     int width, height;
1263     bool ok;
1264 
1265     configSettings->beginGroup("search");
1266     width = configSettings->value("/window width", parent->width() / 2).toInt();
1267     height = configSettings->value("/window height", parent->height() / 2).toInt();
1268     resize(width, height);
1269     x = configSettings->value("/window x");
1270     y = configSettings->value("/window y");
1271     if (x.isValid() && y.isValid())
1272         move(x.toInt(), y.toInt());
1273     QList<int> sizes = configSettings->readSizes("/split", &ok);
1274     if (ok)
1275         split->setSizes(sizes);
1276     configSettings->endGroup();
1277     connect(configApp, &QApplication::aboutToQuit,
1278         this, &ConfigSearchWindow::saveSettings);
1279 }
1280 
1281 void ConfigSearchWindow::saveSettings(void)
1282 {
1283     if (!objectName().isEmpty()) {
1284         configSettings->beginGroup(objectName());
1285         configSettings->setValue("/window x", pos().x());
1286         configSettings->setValue("/window y", pos().y());
1287         configSettings->setValue("/window width", size().width());
1288         configSettings->setValue("/window height", size().height());
1289         configSettings->writeSizes("/split", split->sizes());
1290         configSettings->endGroup();
1291     }
1292 }
1293 
1294 void ConfigSearchWindow::search(void)
1295 {
1296     struct symbol **p;
1297     struct property *prop;
1298     ConfigItem *lastItem = NULL;
1299 
1300     free(result);
1301     list->clear();
1302     info->clear();
1303 
1304     result = sym_re_search(editField->text().toLatin1());
1305     if (!result)
1306         return;
1307     for (p = result; *p; p++) {
1308         for_all_prompts((*p), prop)
1309             lastItem = new ConfigItem(list, lastItem, prop->menu,
1310                           menu_is_visible(prop->menu));
1311     }
1312 }
1313 
1314 /*
1315  * Construct the complete config widget
1316  */
1317 ConfigMainWindow::ConfigMainWindow(void)
1318     : searchWindow(0)
1319 {
1320     bool ok = true;
1321     QVariant x, y;
1322     int width, height;
1323     char title[256];
1324 
1325     QDesktopWidget *d = configApp->desktop();
1326     snprintf(title, sizeof(title), "%s%s",
1327         rootmenu.prompt->text,
1328         ""
1329         );
1330     setWindowTitle(title);
1331 
1332     width = configSettings->value("/window width", d->width() - 64).toInt();
1333     height = configSettings->value("/window height", d->height() - 64).toInt();
1334     resize(width, height);
1335     x = configSettings->value("/window x");
1336     y = configSettings->value("/window y");
1337     if ((x.isValid())&&(y.isValid()))
1338         move(x.toInt(), y.toInt());
1339 
1340     // set up icons
1341     ConfigItem::symbolYesIcon = QIcon(QPixmap(xpm_symbol_yes));
1342     ConfigItem::symbolModIcon = QIcon(QPixmap(xpm_symbol_mod));
1343     ConfigItem::symbolNoIcon = QIcon(QPixmap(xpm_symbol_no));
1344     ConfigItem::choiceYesIcon = QIcon(QPixmap(xpm_choice_yes));
1345     ConfigItem::choiceNoIcon = QIcon(QPixmap(xpm_choice_no));
1346     ConfigItem::menuIcon = QIcon(QPixmap(xpm_menu));
1347     ConfigItem::menubackIcon = QIcon(QPixmap(xpm_menuback));
1348 
1349     QWidget *widget = new QWidget(this);
1350     QVBoxLayout *layout = new QVBoxLayout(widget);
1351     setCentralWidget(widget);
1352 
1353     split1 = new QSplitter(widget);
1354     split1->setOrientation(Qt::Horizontal);
1355     split1->setChildrenCollapsible(false);
1356 
1357     menuList = new ConfigList(widget, "menu");
1358 
1359     split2 = new QSplitter(widget);
1360     split2->setChildrenCollapsible(false);
1361     split2->setOrientation(Qt::Vertical);
1362 
1363     // create config tree
1364     configList = new ConfigList(widget, "config");
1365 
1366     helpText = new ConfigInfoView(widget, "help");
1367 
1368     layout->addWidget(split2);
1369     split2->addWidget(split1);
1370     split1->addWidget(configList);
1371     split1->addWidget(menuList);
1372     split2->addWidget(helpText);
1373 
1374     setTabOrder(configList, helpText);
1375     configList->setFocus();
1376 
1377     backAction = new QAction(QPixmap(xpm_back), "Back", this);
1378     connect(backAction, &QAction::triggered,
1379         this, &ConfigMainWindow::goBack);
1380 
1381     QAction *quitAction = new QAction("&Quit", this);
1382     quitAction->setShortcut(Qt::CTRL + Qt::Key_Q);
1383     connect(quitAction, &QAction::triggered,
1384         this, &ConfigMainWindow::close);
1385 
1386     QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this);
1387     loadAction->setShortcut(Qt::CTRL + Qt::Key_L);
1388     connect(loadAction, &QAction::triggered,
1389         this, &ConfigMainWindow::loadConfig);
1390 
1391     saveAction = new QAction(QPixmap(xpm_save), "&Save", this);
1392     saveAction->setShortcut(Qt::CTRL + Qt::Key_S);
1393     connect(saveAction, &QAction::triggered,
1394         this, &ConfigMainWindow::saveConfig);
1395 
1396     conf_set_changed_callback(conf_changed);
1397 
1398     // Set saveAction's initial state
1399     conf_changed();
1400     configname = xstrdup(conf_get_configname());
1401 
1402     QAction *saveAsAction = new QAction("Save &As...", this);
1403     connect(saveAsAction, &QAction::triggered,
1404         this, &ConfigMainWindow::saveConfigAs);
1405     QAction *searchAction = new QAction("&Find", this);
1406     searchAction->setShortcut(Qt::CTRL + Qt::Key_F);
1407     connect(searchAction, &QAction::triggered,
1408         this, &ConfigMainWindow::searchConfig);
1409     singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this);
1410     singleViewAction->setCheckable(true);
1411     connect(singleViewAction, &QAction::triggered,
1412         this, &ConfigMainWindow::showSingleView);
1413     splitViewAction = new QAction(QPixmap(xpm_split_view), "Split View", this);
1414     splitViewAction->setCheckable(true);
1415     connect(splitViewAction, &QAction::triggered,
1416         this, &ConfigMainWindow::showSplitView);
1417     fullViewAction = new QAction(QPixmap(xpm_tree_view), "Full View", this);
1418     fullViewAction->setCheckable(true);
1419     connect(fullViewAction, &QAction::triggered,
1420         this, &ConfigMainWindow::showFullView);
1421 
1422     QAction *showNameAction = new QAction("Show Name", this);
1423       showNameAction->setCheckable(true);
1424     connect(showNameAction, &QAction::toggled,
1425         configList, &ConfigList::setShowName);
1426     showNameAction->setChecked(configList->showName);
1427 
1428     QActionGroup *optGroup = new QActionGroup(this);
1429     optGroup->setExclusive(true);
1430     connect(optGroup, &QActionGroup::triggered,
1431         configList, &ConfigList::setOptionMode);
1432     connect(optGroup, &QActionGroup::triggered,
1433         menuList, &ConfigList::setOptionMode);
1434 
1435     ConfigList::showNormalAction = new QAction("Show Normal Options", optGroup);
1436     ConfigList::showNormalAction->setCheckable(true);
1437     ConfigList::showAllAction = new QAction("Show All Options", optGroup);
1438     ConfigList::showAllAction->setCheckable(true);
1439     ConfigList::showPromptAction = new QAction("Show Prompt Options", optGroup);
1440     ConfigList::showPromptAction->setCheckable(true);
1441 
1442     QAction *showDebugAction = new QAction("Show Debug Info", this);
1443       showDebugAction->setCheckable(true);
1444     connect(showDebugAction, &QAction::toggled,
1445         helpText, &ConfigInfoView::setShowDebug);
1446       showDebugAction->setChecked(helpText->showDebug());
1447 
1448     QAction *showIntroAction = new QAction("Introduction", this);
1449     connect(showIntroAction, &QAction::triggered,
1450         this, &ConfigMainWindow::showIntro);
1451     QAction *showAboutAction = new QAction("About", this);
1452     connect(showAboutAction, &QAction::triggered,
1453         this, &ConfigMainWindow::showAbout);
1454 
1455     // init tool bar
1456     QToolBar *toolBar = addToolBar("Tools");
1457     toolBar->addAction(backAction);
1458     toolBar->addSeparator();
1459     toolBar->addAction(loadAction);
1460     toolBar->addAction(saveAction);
1461     toolBar->addSeparator();
1462     toolBar->addAction(singleViewAction);
1463     toolBar->addAction(splitViewAction);
1464     toolBar->addAction(fullViewAction);
1465 
1466     // create file menu
1467     QMenu *menu = menuBar()->addMenu("&File");
1468     menu->addAction(loadAction);
1469     menu->addAction(saveAction);
1470     menu->addAction(saveAsAction);
1471     menu->addSeparator();
1472     menu->addAction(quitAction);
1473 
1474     // create edit menu
1475     menu = menuBar()->addMenu("&Edit");
1476     menu->addAction(searchAction);
1477 
1478     // create options menu
1479     menu = menuBar()->addMenu("&Option");
1480     menu->addAction(showNameAction);
1481     menu->addSeparator();
1482     menu->addActions(optGroup->actions());
1483     menu->addSeparator();
1484     menu->addAction(showDebugAction);
1485 
1486     // create help menu
1487     menu = menuBar()->addMenu("&Help");
1488     menu->addAction(showIntroAction);
1489     menu->addAction(showAboutAction);
1490 
1491     connect(helpText, &ConfigInfoView::anchorClicked,
1492         helpText, &ConfigInfoView::clicked);
1493 
1494     connect(configList, &ConfigList::menuChanged,
1495         helpText, &ConfigInfoView::setInfo);
1496     connect(configList, &ConfigList::menuSelected,
1497         this, &ConfigMainWindow::changeMenu);
1498     connect(configList, &ConfigList::itemSelected,
1499         this, &ConfigMainWindow::changeItens);
1500     connect(configList, &ConfigList::parentSelected,
1501         this, &ConfigMainWindow::goBack);
1502     connect(menuList, &ConfigList::menuChanged,
1503         helpText, &ConfigInfoView::setInfo);
1504     connect(menuList, &ConfigList::menuSelected,
1505         this, &ConfigMainWindow::changeMenu);
1506 
1507     connect(configList, &ConfigList::gotFocus,
1508         helpText, &ConfigInfoView::setInfo);
1509     connect(menuList, &ConfigList::gotFocus,
1510         helpText, &ConfigInfoView::setInfo);
1511     connect(menuList, &ConfigList::gotFocus,
1512         this, &ConfigMainWindow::listFocusChanged);
1513     connect(helpText, &ConfigInfoView::menuSelected,
1514         this, &ConfigMainWindow::setMenuLink);
1515 
1516     QString listMode = configSettings->value("/listMode", "symbol").toString();
1517     if (listMode == "single")
1518         showSingleView();
1519     else if (listMode == "full")
1520         showFullView();
1521     else /*if (listMode == "split")*/
1522         showSplitView();
1523 
1524     // UI setup done, restore splitter positions
1525     QList<int> sizes = configSettings->readSizes("/split1", &ok);
1526     if (ok)
1527         split1->setSizes(sizes);
1528 
1529     sizes = configSettings->readSizes("/split2", &ok);
1530     if (ok)
1531         split2->setSizes(sizes);
1532 }
1533 
1534 void ConfigMainWindow::loadConfig(void)
1535 {
1536     QString str;
1537     QByteArray ba;
1538     const char *name;
1539 
1540     str = QFileDialog::getOpenFileName(this, "", configname);
1541     if (str.isNull())
1542         return;
1543 
1544     ba = str.toLocal8Bit();
1545     name = ba.data();
1546 
1547     if (conf_read(name))
1548         QMessageBox::information(this, "qconf", "Unable to load configuration!");
1549 
1550     free(configname);
1551     configname = xstrdup(name);
1552 
1553     ConfigList::updateListAllForAll();
1554 }
1555 
1556 bool ConfigMainWindow::saveConfig(void)
1557 {
1558     if (conf_write(configname)) {
1559         QMessageBox::information(this, "qconf", "Unable to save configuration!");
1560         return false;
1561     }
1562     conf_write_autoconf(0);
1563 
1564     return true;
1565 }
1566 
1567 void ConfigMainWindow::saveConfigAs(void)
1568 {
1569     QString str;
1570     QByteArray ba;
1571     const char *name;
1572 
1573     str = QFileDialog::getSaveFileName(this, "", configname);
1574     if (str.isNull())
1575         return;
1576 
1577     ba = str.toLocal8Bit();
1578     name = ba.data();
1579 
1580     if (conf_write(name)) {
1581         QMessageBox::information(this, "qconf", "Unable to save configuration!");
1582     }
1583     conf_write_autoconf(0);
1584 
1585     free(configname);
1586     configname = xstrdup(name);
1587 }
1588 
1589 void ConfigMainWindow::searchConfig(void)
1590 {
1591     if (!searchWindow)
1592         searchWindow = new ConfigSearchWindow(this);
1593     searchWindow->show();
1594 }
1595 
1596 void ConfigMainWindow::changeItens(struct menu *menu)
1597 {
1598     configList->setRootMenu(menu);
1599 }
1600 
1601 void ConfigMainWindow::changeMenu(struct menu *menu)
1602 {
1603     menuList->setRootMenu(menu);
1604 }
1605 
1606 void ConfigMainWindow::setMenuLink(struct menu *menu)
1607 {
1608     struct menu *parent;
1609     ConfigList* list = NULL;
1610     ConfigItem* item;
1611 
1612     if (configList->menuSkip(menu))
1613         return;
1614 
1615     switch (configList->mode) {
1616     case singleMode:
1617         list = configList;
1618         parent = menu_get_parent_menu(menu);
1619         if (!parent)
1620             return;
1621         list->setRootMenu(parent);
1622         break;
1623     case menuMode:
1624         if (menu->flags & MENU_ROOT) {
1625             menuList->setRootMenu(menu);
1626             configList->clearSelection();
1627             list = configList;
1628         } else {
1629             parent = menu_get_parent_menu(menu->parent);
1630             if (!parent)
1631                 return;
1632 
1633             /* Select the config view */
1634             item = configList->findConfigItem(parent);
1635             if (item) {
1636                 configList->setSelected(item, true);
1637                 configList->scrollToItem(item);
1638             }
1639 
1640             menuList->setRootMenu(parent);
1641             menuList->clearSelection();
1642             list = menuList;
1643         }
1644         break;
1645     case fullMode:
1646         list = configList;
1647         break;
1648     default:
1649         break;
1650     }
1651 
1652     if (list) {
1653         item = list->findConfigItem(menu);
1654         if (item) {
1655             list->setSelected(item, true);
1656             list->scrollToItem(item);
1657             list->setFocus();
1658             helpText->setInfo(menu);
1659         }
1660     }
1661 }
1662 
1663 void ConfigMainWindow::listFocusChanged(void)
1664 {
1665     if (menuList->mode == menuMode)
1666         configList->clearSelection();
1667 }
1668 
1669 void ConfigMainWindow::goBack(void)
1670 {
1671     if (configList->rootEntry == &rootmenu)
1672         return;
1673 
1674     configList->setParentMenu();
1675 }
1676 
1677 void ConfigMainWindow::showSingleView(void)
1678 {
1679     singleViewAction->setEnabled(false);
1680     singleViewAction->setChecked(true);
1681     splitViewAction->setEnabled(true);
1682     splitViewAction->setChecked(false);
1683     fullViewAction->setEnabled(true);
1684     fullViewAction->setChecked(false);
1685 
1686     backAction->setEnabled(true);
1687 
1688     menuList->hide();
1689     menuList->setRootMenu(0);
1690     configList->mode = singleMode;
1691     if (configList->rootEntry == &rootmenu)
1692         configList->updateListAll();
1693     else
1694         configList->setRootMenu(&rootmenu);
1695     configList->setFocus();
1696 }
1697 
1698 void ConfigMainWindow::showSplitView(void)
1699 {
1700     singleViewAction->setEnabled(true);
1701     singleViewAction->setChecked(false);
1702     splitViewAction->setEnabled(false);
1703     splitViewAction->setChecked(true);
1704     fullViewAction->setEnabled(true);
1705     fullViewAction->setChecked(false);
1706 
1707     backAction->setEnabled(false);
1708 
1709     configList->mode = menuMode;
1710     if (configList->rootEntry == &rootmenu)
1711         configList->updateListAll();
1712     else
1713         configList->setRootMenu(&rootmenu);
1714     configList->setAllOpen(true);
1715     configApp->processEvents();
1716     menuList->mode = symbolMode;
1717     menuList->setRootMenu(&rootmenu);
1718     menuList->setAllOpen(true);
1719     menuList->show();
1720     menuList->setFocus();
1721 }
1722 
1723 void ConfigMainWindow::showFullView(void)
1724 {
1725     singleViewAction->setEnabled(true);
1726     singleViewAction->setChecked(false);
1727     splitViewAction->setEnabled(true);
1728     splitViewAction->setChecked(false);
1729     fullViewAction->setEnabled(false);
1730     fullViewAction->setChecked(true);
1731 
1732     backAction->setEnabled(false);
1733 
1734     menuList->hide();
1735     menuList->setRootMenu(0);
1736     configList->mode = fullMode;
1737     if (configList->rootEntry == &rootmenu)
1738         configList->updateListAll();
1739     else
1740         configList->setRootMenu(&rootmenu);
1741     configList->setFocus();
1742 }
1743 
1744 /*
1745  * ask for saving configuration before quitting
1746  */
1747 void ConfigMainWindow::closeEvent(QCloseEvent* e)
1748 {
1749     if (!conf_get_changed()) {
1750         e->accept();
1751         return;
1752     }
1753     QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning,
1754             QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
1755     mb.setButtonText(QMessageBox::Yes, "&Save Changes");
1756     mb.setButtonText(QMessageBox::No, "&Discard Changes");
1757     mb.setButtonText(QMessageBox::Cancel, "Cancel Exit");
1758     switch (mb.exec()) {
1759     case QMessageBox::Yes:
1760         if (saveConfig())
1761             e->accept();
1762         else
1763             e->ignore();
1764         break;
1765     case QMessageBox::No:
1766         e->accept();
1767         break;
1768     case QMessageBox::Cancel:
1769         e->ignore();
1770         break;
1771     }
1772 }
1773 
1774 void ConfigMainWindow::showIntro(void)
1775 {
1776     static const QString str =
1777         "Welcome to the qconf graphical configuration tool.\n"
1778         "\n"
1779         "For bool and tristate options, a blank box indicates the "
1780         "feature is disabled, a check indicates it is enabled, and a "
1781         "dot indicates that it is to be compiled as a module. Clicking "
1782         "on the box will cycle through the three states. For int, hex, "
1783         "and string options, double-clicking or pressing F2 on the "
1784         "Value cell will allow you to edit the value.\n"
1785         "\n"
1786         "If you do not see an option (e.g., a device driver) that you "
1787         "believe should be present, try turning on Show All Options "
1788         "under the Options menu. Enabling Show Debug Info will help you"
1789         "figure out what other options must be enabled to support the "
1790         "option you are interested in, and hyperlinks will navigate to "
1791         "them.\n"
1792         "\n"
1793         "Toggling Show Debug Info under the Options menu will show the "
1794         "dependencies, which you can then match by examining other "
1795         "options.\n";
1796 
1797     QMessageBox::information(this, "qconf", str);
1798 }
1799 
1800 void ConfigMainWindow::showAbout(void)
1801 {
1802     static const QString str = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n"
1803         "Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>.\n"
1804         "\n"
1805         "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n"
1806         "\n"
1807         "Qt Version: ";
1808 
1809     QMessageBox::information(this, "qconf", str + qVersion());
1810 }
1811 
1812 void ConfigMainWindow::saveSettings(void)
1813 {
1814     configSettings->setValue("/window x", pos().x());
1815     configSettings->setValue("/window y", pos().y());
1816     configSettings->setValue("/window width", size().width());
1817     configSettings->setValue("/window height", size().height());
1818 
1819     QString entry;
1820     switch(configList->mode) {
1821     case singleMode :
1822         entry = "single";
1823         break;
1824 
1825     case symbolMode :
1826         entry = "split";
1827         break;
1828 
1829     case fullMode :
1830         entry = "full";
1831         break;
1832 
1833     default:
1834         break;
1835     }
1836     configSettings->setValue("/listMode", entry);
1837 
1838     configSettings->writeSizes("/split1", split1->sizes());
1839     configSettings->writeSizes("/split2", split2->sizes());
1840 }
1841 
1842 void ConfigMainWindow::conf_changed(void)
1843 {
1844     if (saveAction)
1845         saveAction->setEnabled(conf_get_changed());
1846 }
1847 
1848 void fixup_rootmenu(struct menu *menu)
1849 {
1850     struct menu *child;
1851     static int menu_cnt = 0;
1852 
1853     menu->flags |= MENU_ROOT;
1854     for (child = menu->list; child; child = child->next) {
1855         if (child->prompt && child->prompt->type == P_MENU) {
1856             menu_cnt++;
1857             fixup_rootmenu(child);
1858             menu_cnt--;
1859         } else if (!menu_cnt)
1860             fixup_rootmenu(child);
1861     }
1862 }
1863 
1864 static const char *progname;
1865 
1866 static void usage(void)
1867 {
1868     printf("%s [-s] <config>\n", progname);
1869     exit(0);
1870 }
1871 
1872 int main(int ac, char** av)
1873 {
1874     ConfigMainWindow* v;
1875     const char *name;
1876 
1877     progname = av[0];
1878     if (ac > 1 && av[1][0] == '-') {
1879         switch (av[1][1]) {
1880         case 's':
1881             conf_set_message_callback(NULL);
1882             break;
1883         case 'h':
1884         case '?':
1885             usage();
1886         }
1887         name = av[2];
1888     } else
1889         name = av[1];
1890     if (!name)
1891         usage();
1892 
1893     conf_parse(name);
1894     fixup_rootmenu(&rootmenu);
1895     conf_read(NULL);
1896     //zconfdump(stdout);
1897 
1898     configApp = new QApplication(ac, av);
1899 
1900     configSettings = new ConfigSettings();
1901     configSettings->beginGroup("/kconfig/qconf");
1902     v = new ConfigMainWindow();
1903 
1904     //zconfdump(stdout);
1905     configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
1906     configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1907     v->show();
1908     configApp->exec();
1909 
1910     configSettings->endGroup();
1911     delete configSettings;
1912     delete v;
1913     delete configApp;
1914 
1915     return 0;
1916 }