1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
4 * Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>
8 #include <QActionGroup>
9 #include <QApplication>
10 #include <QCloseEvent>
12 #include <QFileDialog>
18 #include <QMessageBox>
19 #include <QRegularExpression>
31 static QApplication *configApp;
32 static ConfigSettings *configSettings;
34 QAction *ConfigMainWindow::saveAction;
36 ConfigSettings::ConfigSettings()
37 : QSettings("kernel.org", "qconf")
42 * Reads a list of integer values from the application settings.
44 QList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
50 QStringList entryList = value(key).toStringList();
51 QStringList::Iterator it;
53 for (it = entryList.begin(); it != entryList.end(); ++it)
54 result.push_back((*it).toInt());
65 * Writes a list of integer values to the application settings.
67 bool ConfigSettings::writeSizes(const QString& key, const QList<int>& value)
69 QStringList stringList;
70 QList<int>::ConstIterator it;
72 for (it = value.begin(); it != value.end(); ++it)
73 stringList.push_back(QString::number(*it));
74 setValue(key, stringList);
79 QIcon ConfigItem::symbolYesIcon;
80 QIcon ConfigItem::symbolModIcon;
81 QIcon ConfigItem::symbolNoIcon;
82 QIcon ConfigItem::choiceYesIcon;
83 QIcon ConfigItem::choiceNoIcon;
84 QIcon ConfigItem::menuIcon;
85 QIcon ConfigItem::menubackIcon;
88 * update the displayed of a menu entry
90 void ConfigItem::updateMenu(void)
94 struct property *prop;
101 setIcon(promptColIdx, menubackIcon);
108 prompt = menu_get_prompt(menu);
110 if (prop) switch (prop->type) {
112 if (list->mode == singleMode || list->mode == symbolMode) {
113 /* a menuconfig entry is displayed differently
114 * depending whether it's at the view root or a child.
116 if (sym && list->rootEntry == menu)
118 setIcon(promptColIdx, menuIcon);
122 setIcon(promptColIdx, QIcon());
126 setIcon(promptColIdx, QIcon());
127 prompt = "*** " + prompt + " ***";
135 setText(nameColIdx, sym->name);
137 type = sym_get_type(sym);
143 if (!sym_is_changeable(sym) && list->optMode == normalOpt) {
144 setIcon(promptColIdx, QIcon());
147 expr = sym_get_tristate_value(sym);
150 if (sym_is_choice_value(sym) && type == S_BOOLEAN)
151 setIcon(promptColIdx, choiceYesIcon);
153 setIcon(promptColIdx, symbolYesIcon);
157 setIcon(promptColIdx, symbolModIcon);
161 if (sym_is_choice_value(sym) && type == S_BOOLEAN)
162 setIcon(promptColIdx, choiceNoIcon);
164 setIcon(promptColIdx, symbolNoIcon);
169 setText(dataColIdx, QChar(ch));
174 setText(dataColIdx, sym_get_string_value(sym));
177 if (!sym_has_value(sym) && visible)
180 setText(promptColIdx, prompt);
183 void ConfigItem::testUpdateMenu(bool v)
191 sym_calc_value(menu->sym);
192 if (menu->flags & MENU_CHANGED) {
193 /* the menu entry changed, so update all list items */
194 menu->flags &= ~MENU_CHANGED;
195 for (i = (ConfigItem*)menu->data; i; i = i->nextItem)
197 } else if (listView()->updateAll)
203 * construct a menu entry
205 void ConfigItem::init(void)
208 ConfigList* list = listView();
209 nextItem = (ConfigItem*)menu->data;
212 if (list->mode != fullMode)
214 sym_calc_value(menu->sym);
217 enum symbol_type type = menu->sym->type;
219 // Allow to edit "int", "hex", and "string" in-place in
220 // the data column. Unfortunately, you cannot specify
221 // the flags per column. Set ItemIsEditable for all
222 // columns here, and check the column in createEditor().
223 if (type == S_INT || type == S_HEX || type == S_STRING)
224 setFlags(flags() | Qt::ItemIsEditable);
231 * destruct a menu entry
233 ConfigItem::~ConfigItem(void)
236 ConfigItem** ip = (ConfigItem**)&menu->data;
237 for (; *ip; ip = &(*ip)->nextItem) {
246 QWidget *ConfigItemDelegate::createEditor(QWidget *parent,
247 const QStyleOptionViewItem &option,
248 const QModelIndex &index) const
252 // Only the data column is editable
253 if (index.column() != dataColIdx)
256 // You cannot edit invisible menus
257 item = static_cast<ConfigItem *>(index.internalPointer());
258 if (!item || !item->menu || !menu_is_visible(item->menu))
261 return QStyledItemDelegate::createEditor(parent, option, index);
264 void ConfigItemDelegate::setModelData(QWidget *editor,
265 QAbstractItemModel *model,
266 const QModelIndex &index) const
273 lineEdit = qobject_cast<QLineEdit *>(editor);
274 // If this is not a QLineEdit, use the parent's default.
275 // (does this happen?)
279 item = static_cast<ConfigItem *>(index.internalPointer());
280 if (!item || !item->menu)
283 sym = item->menu->sym;
287 success = sym_set_string_value(sym, lineEdit->text().toUtf8().data());
289 ConfigList::updateListForAll();
291 QMessageBox::information(editor, "qconf",
292 "Cannot set the data (maybe due to out of range).\n"
293 "Setting the old value.");
294 lineEdit->setText(sym_get_string_value(sym));
298 QStyledItemDelegate::setModelData(editor, model, index);
301 ConfigList::ConfigList(QWidget *parent, const char *name)
302 : QTreeWidget(parent),
304 showName(false), mode(singleMode), optMode(normalOpt),
305 rootEntry(0), headerPopup(0)
308 setSortingEnabled(false);
309 setRootIsDecorated(true);
311 setVerticalScrollMode(ScrollPerPixel);
312 setHorizontalScrollMode(ScrollPerPixel);
314 setHeaderLabels(QStringList() << "Option" << "Name" << "Value");
316 connect(this, &ConfigList::itemSelectionChanged,
317 this, &ConfigList::updateSelection);
320 configSettings->beginGroup(name);
321 showName = configSettings->value("/showName", false).toBool();
322 optMode = (enum optionMode)configSettings->value("/optionMode", 0).toInt();
323 configSettings->endGroup();
324 connect(configApp, &QApplication::aboutToQuit,
325 this, &ConfigList::saveSettings);
328 showColumn(promptColIdx);
330 setItemDelegate(new ConfigItemDelegate(this));
332 allLists.append(this);
337 ConfigList::~ConfigList()
339 allLists.removeOne(this);
342 bool ConfigList::menuSkip(struct menu *menu)
344 if (optMode == normalOpt && menu_is_visible(menu))
346 if (optMode == promptOpt && menu_has_prompt(menu))
348 if (optMode == allOpt)
353 void ConfigList::reinit(void)
355 hideColumn(nameColIdx);
358 showColumn(nameColIdx);
363 void ConfigList::setOptionMode(QAction *action)
365 if (action == showNormalAction)
367 else if (action == showAllAction)
375 void ConfigList::saveSettings(void)
377 if (!objectName().isEmpty()) {
378 configSettings->beginGroup(objectName());
379 configSettings->setValue("/showName", showName);
380 configSettings->setValue("/optionMode", (int)optMode);
381 configSettings->endGroup();
385 ConfigItem* ConfigList::findConfigItem(struct menu *menu)
387 ConfigItem* item = (ConfigItem*)menu->data;
389 for (; item; item = item->nextItem) {
390 if (this == item->listView())
397 void ConfigList::updateSelection(void)
402 if (selectedItems().count() == 0)
405 ConfigItem* item = (ConfigItem*)selectedItems().first();
410 emit menuChanged(menu);
413 type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
414 if (mode == menuMode && type == P_MENU)
415 emit menuSelected(menu);
418 void ConfigList::updateList()
420 ConfigItem* last = 0;
424 if (mode != listMode)
426 QTreeWidgetItemIterator it(this);
429 item = (ConfigItem*)(*it);
432 item->testUpdateMenu(menu_is_visible(item->menu));
439 if (rootEntry != &rootmenu && (mode == singleMode ||
440 (mode == symbolMode && rootEntry->parent != &rootmenu))) {
441 item = (ConfigItem *)topLevelItem(0);
443 item = new ConfigItem(this, 0, true);
446 if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) &&
447 rootEntry->sym && rootEntry->prompt) {
448 item = last ? last->nextSibling() : nullptr;
450 item = new ConfigItem(this, last, rootEntry, true);
452 item->testUpdateMenu(true);
454 updateMenuList(item, rootEntry);
456 resizeColumnToContents(0);
460 updateMenuList(rootEntry);
462 resizeColumnToContents(0);
465 void ConfigList::updateListForAll()
467 QListIterator<ConfigList *> it(allLists);
469 while (it.hasNext()) {
470 ConfigList *list = it.next();
476 void ConfigList::updateListAllForAll()
478 QListIterator<ConfigList *> it(allLists);
480 while (it.hasNext()) {
481 ConfigList *list = it.next();
487 void ConfigList::setValue(ConfigItem* item, tristate val)
493 sym = item->menu ? item->menu->sym : 0;
497 type = sym_get_type(sym);
501 oldval = sym_get_tristate_value(sym);
503 if (!sym_set_tristate_value(sym, val))
505 if (oldval == no && item->menu->list)
506 item->setExpanded(true);
507 ConfigList::updateListForAll();
512 void ConfigList::changeValue(ConfigItem* item)
516 int type, oldexpr, newexpr;
523 if (item->menu->list)
524 item->setExpanded(!item->isExpanded());
528 type = sym_get_type(sym);
532 oldexpr = sym_get_tristate_value(sym);
533 newexpr = sym_toggle_tristate_value(sym);
534 if (item->menu->list) {
535 if (oldexpr == newexpr)
536 item->setExpanded(!item->isExpanded());
537 else if (oldexpr == no)
538 item->setExpanded(true);
540 if (oldexpr != newexpr)
541 ConfigList::updateListForAll();
548 void ConfigList::setRootMenu(struct menu *menu)
552 if (rootEntry == menu)
554 type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
561 setSelected(currentItem(), hasFocus());
562 scrollToItem(currentItem());
566 void ConfigList::setParentMenu(void)
569 struct menu *oldroot;
572 if (rootEntry == &rootmenu)
574 setRootMenu(menu_get_parent_menu(rootEntry->parent));
576 QTreeWidgetItemIterator it(this);
578 item = (ConfigItem *)(*it);
579 if (item->menu == oldroot) {
580 setCurrentItem(item);
590 * update all the children of a menu entry
591 * removes/adds the entries from the parent widget as necessary
593 * parent: either the menu list widget or a menu entry widget
594 * menu: entry to be updated
596 void ConfigList::updateMenuList(ConfigItem *parent, struct menu* menu)
605 while (parent->childCount() > 0)
607 delete parent->takeChild(0);
613 last = parent->firstChild();
614 if (last && !last->goParent)
616 for (child = menu->list; child; child = child->next) {
617 item = last ? last->nextSibling() : parent->firstChild();
618 type = child->prompt ? child->prompt->type : P_UNKNOWN;
622 if (!(child->flags & MENU_ROOT))
626 if (child->flags & MENU_ROOT)
633 visible = menu_is_visible(child);
634 if (!menuSkip(child)) {
635 if (!child->sym && !child->list && !child->prompt)
637 if (!item || item->menu != child)
638 item = new ConfigItem(parent, last, child, visible);
640 item->testUpdateMenu(visible);
642 if (mode == fullMode || mode == menuMode || type != P_MENU)
643 updateMenuList(item, child);
645 updateMenuList(item, 0);
650 if (item && item->menu == child) {
651 last = parent->firstChild();
654 else while (last->nextSibling() != item)
655 last = last->nextSibling();
661 void ConfigList::updateMenuList(struct menu *menu)
670 while (topLevelItemCount() > 0)
672 delete takeTopLevelItem(0);
678 last = (ConfigItem *)topLevelItem(0);
679 if (last && !last->goParent)
681 for (child = menu->list; child; child = child->next) {
682 item = last ? last->nextSibling() : (ConfigItem *)topLevelItem(0);
683 type = child->prompt ? child->prompt->type : P_UNKNOWN;
687 if (!(child->flags & MENU_ROOT))
691 if (child->flags & MENU_ROOT)
698 visible = menu_is_visible(child);
699 if (!menuSkip(child)) {
700 if (!child->sym && !child->list && !child->prompt)
702 if (!item || item->menu != child)
703 item = new ConfigItem(this, last, child, visible);
705 item->testUpdateMenu(visible);
707 if (mode == fullMode || mode == menuMode || type != P_MENU)
708 updateMenuList(item, child);
710 updateMenuList(item, 0);
715 if (item && item->menu == child) {
716 last = (ConfigItem *)topLevelItem(0);
719 else while (last->nextSibling() != item)
720 last = last->nextSibling();
726 void ConfigList::keyPressEvent(QKeyEvent* ev)
728 QTreeWidgetItem* i = currentItem();
733 if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) {
734 emit parentSelected();
740 Parent::keyPressEvent(ev);
743 item = (ConfigItem*)i;
748 if (item->goParent) {
749 emit parentSelected();
755 type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
756 if (type == P_MENU && rootEntry != menu &&
757 mode != fullMode && mode != menuMode) {
758 if (mode == menuMode)
759 emit menuSelected(menu);
761 emit itemSelected(menu);
777 Parent::keyPressEvent(ev);
783 void ConfigList::mousePressEvent(QMouseEvent* e)
785 //QPoint p(contentsToViewport(e->pos()));
786 //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
787 Parent::mousePressEvent(e);
790 void ConfigList::mouseReleaseEvent(QMouseEvent* e)
793 ConfigItem* item = (ConfigItem*)itemAt(p);
795 enum prop_type ptype;
803 x = header()->offset() + p.x();
804 idx = header()->logicalIndexAt(x);
807 icon = item->icon(promptColIdx);
808 if (!icon.isNull()) {
809 int off = header()->sectionPosition(0) + visualRect(indexAt(p)).x() + 4; // 4 is Hardcoded image offset. There might be a way to do it properly.
810 if (x >= off && x < off + icon.availableSizes().first().width()) {
811 if (item->goParent) {
812 emit parentSelected();
816 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
817 if (ptype == P_MENU && rootEntry != menu &&
818 mode != fullMode && mode != menuMode &&
820 emit menuSelected(menu);
832 //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
833 Parent::mouseReleaseEvent(e);
836 void ConfigList::mouseMoveEvent(QMouseEvent* e)
838 //QPoint p(contentsToViewport(e->pos()));
839 //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
840 Parent::mouseMoveEvent(e);
843 void ConfigList::mouseDoubleClickEvent(QMouseEvent* e)
846 ConfigItem* item = (ConfigItem*)itemAt(p);
848 enum prop_type ptype;
852 if (item->goParent) {
853 emit parentSelected();
859 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
860 if (ptype == P_MENU && mode != listMode) {
861 if (mode == singleMode)
862 emit itemSelected(menu);
863 else if (mode == symbolMode)
864 emit menuSelected(menu);
865 } else if (menu->sym)
869 //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
870 Parent::mouseDoubleClickEvent(e);
873 void ConfigList::focusInEvent(QFocusEvent *e)
875 struct menu *menu = NULL;
877 Parent::focusInEvent(e);
879 ConfigItem* item = (ConfigItem *)currentItem();
881 setSelected(item, true);
887 void ConfigList::contextMenuEvent(QContextMenuEvent *e)
892 headerPopup = new QMenu(this);
893 action = new QAction("Show Name", this);
894 action->setCheckable(true);
895 connect(action, &QAction::toggled,
896 this, &ConfigList::setShowName);
897 connect(this, &ConfigList::showNameChanged,
898 action, &QAction::setChecked);
899 action->setChecked(showName);
900 headerPopup->addAction(action);
903 headerPopup->exec(e->globalPos());
907 void ConfigList::setShowName(bool on)
914 emit showNameChanged(on);
917 QList<ConfigList *> ConfigList::allLists;
918 QAction *ConfigList::showNormalAction;
919 QAction *ConfigList::showAllAction;
920 QAction *ConfigList::showPromptAction;
922 void ConfigList::setAllOpen(bool open)
924 QTreeWidgetItemIterator it(this);
927 (*it)->setExpanded(open);
933 ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
934 : Parent(parent), sym(0), _menu(0)
939 if (!objectName().isEmpty()) {
940 configSettings->beginGroup(objectName());
941 setShowDebug(configSettings->value("/showDebug", false).toBool());
942 configSettings->endGroup();
943 connect(configApp, &QApplication::aboutToQuit,
944 this, &ConfigInfoView::saveSettings);
947 contextMenu = createStandardContextMenu();
948 QAction *action = new QAction("Show Debug Info", contextMenu);
950 action->setCheckable(true);
951 connect(action, &QAction::toggled,
952 this, &ConfigInfoView::setShowDebug);
953 connect(this, &ConfigInfoView::showDebugChanged,
954 action, &QAction::setChecked);
955 action->setChecked(showDebug());
956 contextMenu->addSeparator();
957 contextMenu->addAction(action);
960 void ConfigInfoView::saveSettings(void)
962 if (!objectName().isEmpty()) {
963 configSettings->beginGroup(objectName());
964 configSettings->setValue("/showDebug", showDebug());
965 configSettings->endGroup();
969 void ConfigInfoView::setShowDebug(bool b)
971 if (_showDebug != b) {
977 emit showDebugChanged(b);
981 void ConfigInfoView::setInfo(struct menu *m)
993 void ConfigInfoView::symbolInfo(void)
997 str += "<big>Symbol: <b>";
998 str += print_filter(sym->name);
999 str += "</b></big><br><br>value: ";
1000 str += print_filter(sym_get_string_value(sym));
1001 str += "<br>visibility: ";
1002 str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n";
1004 str += debug_info(sym);
1009 void ConfigInfoView::menuInfo(void)
1013 QTextStream stream(&info);
1017 if (_menu->prompt) {
1018 stream << "<big><b>";
1019 stream << print_filter(_menu->prompt->text);
1020 stream << "</b></big>";
1024 stream << "<a href=\"s" << sym->name << "\">";
1025 stream << print_filter(sym->name);
1030 } else if (sym->name) {
1031 stream << "<big><b>";
1033 stream << "<a href=\"s" << sym->name << "\">";
1034 stream << print_filter(sym->name);
1037 stream << "</b></big>";
1039 stream << "<br><br>";
1042 stream << debug_info(sym);
1044 struct gstr help_gstr = str_new();
1046 menu_get_ext_help(_menu, &help_gstr);
1047 stream << print_filter(str_get(&help_gstr));
1048 str_free(&help_gstr);
1049 } else if (_menu->prompt) {
1050 stream << "<big><b>";
1051 stream << print_filter(_menu->prompt->text);
1052 stream << "</b></big><br><br>";
1054 if (_menu->prompt->visible.expr) {
1055 stream << " dep: ";
1056 expr_print(_menu->prompt->visible.expr,
1057 expr_print_help, &stream, E_NONE);
1058 stream << "<br><br>";
1061 stream << "defined at " << _menu->file->name << ":"
1062 << _menu->lineno << "<br><br>";
1069 QString ConfigInfoView::debug_info(struct symbol *sym)
1072 QTextStream stream(&debug);
1075 stream << print_filter(sym_type_name(sym->type));
1076 if (sym_is_choice(sym))
1077 stream << " (choice)";
1079 if (sym->rev_dep.expr) {
1080 stream << "reverse dep: ";
1081 expr_print(sym->rev_dep.expr, expr_print_help, &stream, E_NONE);
1084 for (struct property *prop = sym->prop; prop; prop = prop->next) {
1085 switch (prop->type) {
1088 stream << "prompt: <a href=\"m" << sym->name << "\">";
1089 stream << print_filter(prop->text);
1090 stream << "</a><br>";
1098 stream << prop_get_type_name(prop->type);
1100 expr_print(prop->expr, expr_print_help,
1105 if (sym_is_choice(sym)) {
1106 stream << "choice: ";
1107 expr_print(prop->expr, expr_print_help,
1113 stream << "unknown property: ";
1114 stream << prop_get_type_name(prop->type);
1117 if (prop->visible.expr) {
1118 stream << " dep: ";
1119 expr_print(prop->visible.expr, expr_print_help,
1129 QString ConfigInfoView::print_filter(const QString &str)
1131 QRegularExpression re("[<>&\"\\n]");
1133 for (int i = 0; (i = res.indexOf(re, i)) >= 0;) {
1134 switch (res[i].toLatin1()) {
1136 res.replace(i, 1, "<");
1140 res.replace(i, 1, ">");
1144 res.replace(i, 1, "&");
1148 res.replace(i, 1, """);
1152 res.replace(i, 1, "<br>");
1160 void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str)
1162 QTextStream *stream = reinterpret_cast<QTextStream *>(data);
1164 if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
1165 *stream << "<a href=\"s" << sym->name << "\">";
1166 *stream << print_filter(str);
1169 *stream << print_filter(str);
1173 void ConfigInfoView::clicked(const QUrl &url)
1175 QByteArray str = url.toEncoded();
1176 const std::size_t count = str.size();
1177 char *data = new char[count + 1];
1178 struct symbol **result;
1179 struct menu *m = NULL;
1186 memcpy(data, str.constData(), count);
1189 /* Seek for exact match */
1192 result = sym_re_search(data);
1200 /* Seek for the menu which holds the symbol */
1201 for (struct property *prop = sym->prop; prop; prop = prop->next) {
1202 if (prop->type != P_PROMPT && prop->type != P_MENU)
1209 /* Symbol is not visible as a menu */
1211 emit showDebugChanged(true);
1213 emit menuSelected(m);
1220 void ConfigInfoView::contextMenuEvent(QContextMenuEvent *event)
1222 contextMenu->popup(event->globalPos());
1226 ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow *parent)
1227 : Parent(parent), result(NULL)
1229 setObjectName("search");
1230 setWindowTitle("Search Config");
1232 QVBoxLayout* layout1 = new QVBoxLayout(this);
1233 layout1->setContentsMargins(11, 11, 11, 11);
1234 layout1->setSpacing(6);
1236 QHBoxLayout* layout2 = new QHBoxLayout();
1237 layout2->setContentsMargins(0, 0, 0, 0);
1238 layout2->setSpacing(6);
1239 layout2->addWidget(new QLabel("Find:", this));
1240 editField = new QLineEdit(this);
1241 connect(editField, &QLineEdit::returnPressed,
1242 this, &ConfigSearchWindow::search);
1243 layout2->addWidget(editField);
1244 searchButton = new QPushButton("Search", this);
1245 searchButton->setAutoDefault(false);
1246 connect(searchButton, &QPushButton::clicked,
1247 this, &ConfigSearchWindow::search);
1248 layout2->addWidget(searchButton);
1249 layout1->addLayout(layout2);
1251 split = new QSplitter(this);
1252 split->setOrientation(Qt::Vertical);
1253 list = new ConfigList(split, "search");
1254 list->mode = listMode;
1255 info = new ConfigInfoView(split, "search");
1256 connect(list, &ConfigList::menuChanged,
1257 info, &ConfigInfoView::setInfo);
1258 connect(list, &ConfigList::menuChanged,
1259 parent, &ConfigMainWindow::setMenuLink);
1261 layout1->addWidget(split);
1267 configSettings->beginGroup("search");
1268 width = configSettings->value("/window width", parent->width() / 2).toInt();
1269 height = configSettings->value("/window height", parent->height() / 2).toInt();
1270 resize(width, height);
1271 x = configSettings->value("/window x");
1272 y = configSettings->value("/window y");
1273 if (x.isValid() && y.isValid())
1274 move(x.toInt(), y.toInt());
1275 QList<int> sizes = configSettings->readSizes("/split", &ok);
1277 split->setSizes(sizes);
1278 configSettings->endGroup();
1279 connect(configApp, &QApplication::aboutToQuit,
1280 this, &ConfigSearchWindow::saveSettings);
1283 void ConfigSearchWindow::saveSettings(void)
1285 if (!objectName().isEmpty()) {
1286 configSettings->beginGroup(objectName());
1287 configSettings->setValue("/window x", pos().x());
1288 configSettings->setValue("/window y", pos().y());
1289 configSettings->setValue("/window width", size().width());
1290 configSettings->setValue("/window height", size().height());
1291 configSettings->writeSizes("/split", split->sizes());
1292 configSettings->endGroup();
1296 void ConfigSearchWindow::search(void)
1299 struct property *prop;
1300 ConfigItem *lastItem = NULL;
1306 result = sym_re_search(editField->text().toLatin1());
1309 for (p = result; *p; p++) {
1310 for_all_prompts((*p), prop)
1311 lastItem = new ConfigItem(list, lastItem, prop->menu,
1312 menu_is_visible(prop->menu));
1317 * Construct the complete config widget
1319 ConfigMainWindow::ConfigMainWindow(void)
1327 snprintf(title, sizeof(title), "%s%s",
1328 rootmenu.prompt->text,
1331 setWindowTitle(title);
1333 QRect g = configApp->primaryScreen()->geometry();
1334 width = configSettings->value("/window width", g.width() - 64).toInt();
1335 height = configSettings->value("/window height", g.height() - 64).toInt();
1336 resize(width, height);
1337 x = configSettings->value("/window x");
1338 y = configSettings->value("/window y");
1339 if ((x.isValid())&&(y.isValid()))
1340 move(x.toInt(), y.toInt());
1343 ConfigItem::symbolYesIcon = QIcon(QPixmap(xpm_symbol_yes));
1344 ConfigItem::symbolModIcon = QIcon(QPixmap(xpm_symbol_mod));
1345 ConfigItem::symbolNoIcon = QIcon(QPixmap(xpm_symbol_no));
1346 ConfigItem::choiceYesIcon = QIcon(QPixmap(xpm_choice_yes));
1347 ConfigItem::choiceNoIcon = QIcon(QPixmap(xpm_choice_no));
1348 ConfigItem::menuIcon = QIcon(QPixmap(xpm_menu));
1349 ConfigItem::menubackIcon = QIcon(QPixmap(xpm_menuback));
1351 QWidget *widget = new QWidget(this);
1352 QVBoxLayout *layout = new QVBoxLayout(widget);
1353 setCentralWidget(widget);
1355 split1 = new QSplitter(widget);
1356 split1->setOrientation(Qt::Horizontal);
1357 split1->setChildrenCollapsible(false);
1359 menuList = new ConfigList(widget, "menu");
1361 split2 = new QSplitter(widget);
1362 split2->setChildrenCollapsible(false);
1363 split2->setOrientation(Qt::Vertical);
1365 // create config tree
1366 configList = new ConfigList(widget, "config");
1368 helpText = new ConfigInfoView(widget, "help");
1370 layout->addWidget(split2);
1371 split2->addWidget(split1);
1372 split1->addWidget(configList);
1373 split1->addWidget(menuList);
1374 split2->addWidget(helpText);
1376 setTabOrder(configList, helpText);
1377 configList->setFocus();
1379 backAction = new QAction(QPixmap(xpm_back), "Back", this);
1380 connect(backAction, &QAction::triggered,
1381 this, &ConfigMainWindow::goBack);
1383 QAction *quitAction = new QAction("&Quit", this);
1384 quitAction->setShortcut(Qt::CTRL | Qt::Key_Q);
1385 connect(quitAction, &QAction::triggered,
1386 this, &ConfigMainWindow::close);
1388 QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this);
1389 loadAction->setShortcut(Qt::CTRL | Qt::Key_L);
1390 connect(loadAction, &QAction::triggered,
1391 this, &ConfigMainWindow::loadConfig);
1393 saveAction = new QAction(QPixmap(xpm_save), "&Save", this);
1394 saveAction->setShortcut(Qt::CTRL | Qt::Key_S);
1395 connect(saveAction, &QAction::triggered,
1396 this, &ConfigMainWindow::saveConfig);
1398 conf_set_changed_callback(conf_changed);
1400 // Set saveAction's initial state
1402 configname = xstrdup(conf_get_configname());
1404 QAction *saveAsAction = new QAction("Save &As...", this);
1405 connect(saveAsAction, &QAction::triggered,
1406 this, &ConfigMainWindow::saveConfigAs);
1407 QAction *searchAction = new QAction("&Find", this);
1408 searchAction->setShortcut(Qt::CTRL | Qt::Key_F);
1409 connect(searchAction, &QAction::triggered,
1410 this, &ConfigMainWindow::searchConfig);
1411 singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this);
1412 singleViewAction->setCheckable(true);
1413 connect(singleViewAction, &QAction::triggered,
1414 this, &ConfigMainWindow::showSingleView);
1415 splitViewAction = new QAction(QPixmap(xpm_split_view), "Split View", this);
1416 splitViewAction->setCheckable(true);
1417 connect(splitViewAction, &QAction::triggered,
1418 this, &ConfigMainWindow::showSplitView);
1419 fullViewAction = new QAction(QPixmap(xpm_tree_view), "Full View", this);
1420 fullViewAction->setCheckable(true);
1421 connect(fullViewAction, &QAction::triggered,
1422 this, &ConfigMainWindow::showFullView);
1424 QAction *showNameAction = new QAction("Show Name", this);
1425 showNameAction->setCheckable(true);
1426 connect(showNameAction, &QAction::toggled,
1427 configList, &ConfigList::setShowName);
1428 showNameAction->setChecked(configList->showName);
1430 QActionGroup *optGroup = new QActionGroup(this);
1431 optGroup->setExclusive(true);
1432 connect(optGroup, &QActionGroup::triggered,
1433 configList, &ConfigList::setOptionMode);
1434 connect(optGroup, &QActionGroup::triggered,
1435 menuList, &ConfigList::setOptionMode);
1437 ConfigList::showNormalAction = new QAction("Show Normal Options", optGroup);
1438 ConfigList::showNormalAction->setCheckable(true);
1439 ConfigList::showAllAction = new QAction("Show All Options", optGroup);
1440 ConfigList::showAllAction->setCheckable(true);
1441 ConfigList::showPromptAction = new QAction("Show Prompt Options", optGroup);
1442 ConfigList::showPromptAction->setCheckable(true);
1444 QAction *showDebugAction = new QAction("Show Debug Info", this);
1445 showDebugAction->setCheckable(true);
1446 connect(showDebugAction, &QAction::toggled,
1447 helpText, &ConfigInfoView::setShowDebug);
1448 showDebugAction->setChecked(helpText->showDebug());
1450 QAction *showIntroAction = new QAction("Introduction", this);
1451 connect(showIntroAction, &QAction::triggered,
1452 this, &ConfigMainWindow::showIntro);
1453 QAction *showAboutAction = new QAction("About", this);
1454 connect(showAboutAction, &QAction::triggered,
1455 this, &ConfigMainWindow::showAbout);
1458 QToolBar *toolBar = addToolBar("Tools");
1459 toolBar->addAction(backAction);
1460 toolBar->addSeparator();
1461 toolBar->addAction(loadAction);
1462 toolBar->addAction(saveAction);
1463 toolBar->addSeparator();
1464 toolBar->addAction(singleViewAction);
1465 toolBar->addAction(splitViewAction);
1466 toolBar->addAction(fullViewAction);
1469 QMenu *menu = menuBar()->addMenu("&File");
1470 menu->addAction(loadAction);
1471 menu->addAction(saveAction);
1472 menu->addAction(saveAsAction);
1473 menu->addSeparator();
1474 menu->addAction(quitAction);
1477 menu = menuBar()->addMenu("&Edit");
1478 menu->addAction(searchAction);
1480 // create options menu
1481 menu = menuBar()->addMenu("&Option");
1482 menu->addAction(showNameAction);
1483 menu->addSeparator();
1484 menu->addActions(optGroup->actions());
1485 menu->addSeparator();
1486 menu->addAction(showDebugAction);
1489 menu = menuBar()->addMenu("&Help");
1490 menu->addAction(showIntroAction);
1491 menu->addAction(showAboutAction);
1493 connect(helpText, &ConfigInfoView::anchorClicked,
1494 helpText, &ConfigInfoView::clicked);
1496 connect(configList, &ConfigList::menuChanged,
1497 helpText, &ConfigInfoView::setInfo);
1498 connect(configList, &ConfigList::menuSelected,
1499 this, &ConfigMainWindow::changeMenu);
1500 connect(configList, &ConfigList::itemSelected,
1501 this, &ConfigMainWindow::changeItens);
1502 connect(configList, &ConfigList::parentSelected,
1503 this, &ConfigMainWindow::goBack);
1504 connect(menuList, &ConfigList::menuChanged,
1505 helpText, &ConfigInfoView::setInfo);
1506 connect(menuList, &ConfigList::menuSelected,
1507 this, &ConfigMainWindow::changeMenu);
1509 connect(configList, &ConfigList::gotFocus,
1510 helpText, &ConfigInfoView::setInfo);
1511 connect(menuList, &ConfigList::gotFocus,
1512 helpText, &ConfigInfoView::setInfo);
1513 connect(menuList, &ConfigList::gotFocus,
1514 this, &ConfigMainWindow::listFocusChanged);
1515 connect(helpText, &ConfigInfoView::menuSelected,
1516 this, &ConfigMainWindow::setMenuLink);
1518 QString listMode = configSettings->value("/listMode", "symbol").toString();
1519 if (listMode == "single")
1521 else if (listMode == "full")
1523 else /*if (listMode == "split")*/
1526 // UI setup done, restore splitter positions
1527 QList<int> sizes = configSettings->readSizes("/split1", &ok);
1529 split1->setSizes(sizes);
1531 sizes = configSettings->readSizes("/split2", &ok);
1533 split2->setSizes(sizes);
1536 void ConfigMainWindow::loadConfig(void)
1542 str = QFileDialog::getOpenFileName(this, "", configname);
1546 ba = str.toLocal8Bit();
1549 if (conf_read(name))
1550 QMessageBox::information(this, "qconf", "Unable to load configuration!");
1553 configname = xstrdup(name);
1555 ConfigList::updateListAllForAll();
1558 bool ConfigMainWindow::saveConfig(void)
1560 if (conf_write(configname)) {
1561 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1564 conf_write_autoconf(0);
1569 void ConfigMainWindow::saveConfigAs(void)
1575 str = QFileDialog::getSaveFileName(this, "", configname);
1579 ba = str.toLocal8Bit();
1582 if (conf_write(name)) {
1583 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1585 conf_write_autoconf(0);
1588 configname = xstrdup(name);
1591 void ConfigMainWindow::searchConfig(void)
1594 searchWindow = new ConfigSearchWindow(this);
1595 searchWindow->show();
1598 void ConfigMainWindow::changeItens(struct menu *menu)
1600 configList->setRootMenu(menu);
1603 void ConfigMainWindow::changeMenu(struct menu *menu)
1605 menuList->setRootMenu(menu);
1608 void ConfigMainWindow::setMenuLink(struct menu *menu)
1610 struct menu *parent;
1611 ConfigList* list = NULL;
1614 if (configList->menuSkip(menu))
1617 switch (configList->mode) {
1620 parent = menu_get_parent_menu(menu);
1623 list->setRootMenu(parent);
1626 if (menu->flags & MENU_ROOT) {
1627 menuList->setRootMenu(menu);
1628 configList->clearSelection();
1631 parent = menu_get_parent_menu(menu->parent);
1635 /* Select the config view */
1636 item = configList->findConfigItem(parent);
1638 configList->setSelected(item, true);
1639 configList->scrollToItem(item);
1642 menuList->setRootMenu(parent);
1643 menuList->clearSelection();
1655 item = list->findConfigItem(menu);
1657 list->setSelected(item, true);
1658 list->scrollToItem(item);
1660 helpText->setInfo(menu);
1665 void ConfigMainWindow::listFocusChanged(void)
1667 if (menuList->mode == menuMode)
1668 configList->clearSelection();
1671 void ConfigMainWindow::goBack(void)
1673 if (configList->rootEntry == &rootmenu)
1676 configList->setParentMenu();
1679 void ConfigMainWindow::showSingleView(void)
1681 singleViewAction->setEnabled(false);
1682 singleViewAction->setChecked(true);
1683 splitViewAction->setEnabled(true);
1684 splitViewAction->setChecked(false);
1685 fullViewAction->setEnabled(true);
1686 fullViewAction->setChecked(false);
1688 backAction->setEnabled(true);
1691 menuList->setRootMenu(0);
1692 configList->mode = singleMode;
1693 if (configList->rootEntry == &rootmenu)
1694 configList->updateListAll();
1696 configList->setRootMenu(&rootmenu);
1697 configList->setFocus();
1700 void ConfigMainWindow::showSplitView(void)
1702 singleViewAction->setEnabled(true);
1703 singleViewAction->setChecked(false);
1704 splitViewAction->setEnabled(false);
1705 splitViewAction->setChecked(true);
1706 fullViewAction->setEnabled(true);
1707 fullViewAction->setChecked(false);
1709 backAction->setEnabled(false);
1711 configList->mode = menuMode;
1712 if (configList->rootEntry == &rootmenu)
1713 configList->updateListAll();
1715 configList->setRootMenu(&rootmenu);
1716 configList->setAllOpen(true);
1717 configApp->processEvents();
1718 menuList->mode = symbolMode;
1719 menuList->setRootMenu(&rootmenu);
1720 menuList->setAllOpen(true);
1722 menuList->setFocus();
1725 void ConfigMainWindow::showFullView(void)
1727 singleViewAction->setEnabled(true);
1728 singleViewAction->setChecked(false);
1729 splitViewAction->setEnabled(true);
1730 splitViewAction->setChecked(false);
1731 fullViewAction->setEnabled(false);
1732 fullViewAction->setChecked(true);
1734 backAction->setEnabled(false);
1737 menuList->setRootMenu(0);
1738 configList->mode = fullMode;
1739 if (configList->rootEntry == &rootmenu)
1740 configList->updateListAll();
1742 configList->setRootMenu(&rootmenu);
1743 configList->setFocus();
1747 * ask for saving configuration before quitting
1749 void ConfigMainWindow::closeEvent(QCloseEvent* e)
1751 if (!conf_get_changed()) {
1756 QMessageBox mb(QMessageBox::Icon::Warning, "qconf",
1757 "Save configuration?");
1759 QPushButton *yb = mb.addButton(QMessageBox::Yes);
1760 QPushButton *db = mb.addButton(QMessageBox::No);
1761 QPushButton *cb = mb.addButton(QMessageBox::Cancel);
1763 yb->setText("&Save Changes");
1764 db->setText("&Discard Changes");
1765 cb->setText("Cancel Exit");
1767 mb.setDefaultButton(yb);
1768 mb.setEscapeButton(cb);
1770 switch (mb.exec()) {
1771 case QMessageBox::Yes:
1777 case QMessageBox::No:
1780 case QMessageBox::Cancel:
1786 void ConfigMainWindow::showIntro(void)
1788 static const QString str =
1789 "Welcome to the qconf graphical configuration tool.\n"
1791 "For bool and tristate options, a blank box indicates the "
1792 "feature is disabled, a check indicates it is enabled, and a "
1793 "dot indicates that it is to be compiled as a module. Clicking "
1794 "on the box will cycle through the three states. For int, hex, "
1795 "and string options, double-clicking or pressing F2 on the "
1796 "Value cell will allow you to edit the value.\n"
1798 "If you do not see an option (e.g., a device driver) that you "
1799 "believe should be present, try turning on Show All Options "
1800 "under the Options menu. Enabling Show Debug Info will help you"
1801 "figure out what other options must be enabled to support the "
1802 "option you are interested in, and hyperlinks will navigate to "
1805 "Toggling Show Debug Info under the Options menu will show the "
1806 "dependencies, which you can then match by examining other "
1809 QMessageBox::information(this, "qconf", str);
1812 void ConfigMainWindow::showAbout(void)
1814 static const QString str = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n"
1815 "Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>.\n"
1817 "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n"
1821 QMessageBox::information(this, "qconf", str + qVersion());
1824 void ConfigMainWindow::saveSettings(void)
1826 configSettings->setValue("/window x", pos().x());
1827 configSettings->setValue("/window y", pos().y());
1828 configSettings->setValue("/window width", size().width());
1829 configSettings->setValue("/window height", size().height());
1832 switch(configList->mode) {
1848 configSettings->setValue("/listMode", entry);
1850 configSettings->writeSizes("/split1", split1->sizes());
1851 configSettings->writeSizes("/split2", split2->sizes());
1854 void ConfigMainWindow::conf_changed(void)
1857 saveAction->setEnabled(conf_get_changed());
1860 void fixup_rootmenu(struct menu *menu)
1863 static int menu_cnt = 0;
1865 menu->flags |= MENU_ROOT;
1866 for (child = menu->list; child; child = child->next) {
1867 if (child->prompt && child->prompt->type == P_MENU) {
1869 fixup_rootmenu(child);
1871 } else if (!menu_cnt)
1872 fixup_rootmenu(child);
1876 static const char *progname;
1878 static void usage(void)
1880 printf("%s [-s] <config>\n", progname);
1884 int main(int ac, char** av)
1886 ConfigMainWindow* v;
1890 if (ac > 1 && av[1][0] == '-') {
1893 conf_set_message_callback(NULL);
1906 fixup_rootmenu(&rootmenu);
1908 //zconfdump(stdout);
1910 configApp = new QApplication(ac, av);
1912 configSettings = new ConfigSettings();
1913 configSettings->beginGroup("/kconfig/qconf");
1914 v = new ConfigMainWindow();
1916 //zconfdump(stdout);
1917 configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
1918 configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1922 configSettings->endGroup();
1923 delete configSettings;