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 <QApplication>
11 #include <QDesktopWidget>
12 #include <QFileDialog>
18 #include <QMessageBox>
29 static QApplication *configApp;
30 static ConfigSettings *configSettings;
32 QAction *ConfigMainWindow::saveAction;
34 ConfigSettings::ConfigSettings()
35 : QSettings("kernel.org", "qconf")
40 * Reads a list of integer values from the application settings.
42 QList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
48 QStringList entryList = value(key).toStringList();
49 QStringList::Iterator it;
51 for (it = entryList.begin(); it != entryList.end(); ++it)
52 result.push_back((*it).toInt());
63 * Writes a list of integer values to the application settings.
65 bool ConfigSettings::writeSizes(const QString& key, const QList<int>& value)
67 QStringList stringList;
68 QList<int>::ConstIterator it;
70 for (it = value.begin(); it != value.end(); ++it)
71 stringList.push_back(QString::number(*it));
72 setValue(key, stringList);
77 QIcon ConfigItem::symbolYesIcon;
78 QIcon ConfigItem::symbolModIcon;
79 QIcon ConfigItem::symbolNoIcon;
80 QIcon ConfigItem::choiceYesIcon;
81 QIcon ConfigItem::choiceNoIcon;
82 QIcon ConfigItem::menuIcon;
83 QIcon ConfigItem::menubackIcon;
86 * update the displayed of a menu entry
88 void ConfigItem::updateMenu(void)
92 struct property *prop;
99 setIcon(promptColIdx, menubackIcon);
106 prompt = menu_get_prompt(menu);
108 if (prop) switch (prop->type) {
110 if (list->mode == singleMode || list->mode == symbolMode) {
111 /* a menuconfig entry is displayed differently
112 * depending whether it's at the view root or a child.
114 if (sym && list->rootEntry == menu)
116 setIcon(promptColIdx, menuIcon);
120 setIcon(promptColIdx, QIcon());
124 setIcon(promptColIdx, QIcon());
125 prompt = "*** " + prompt + " ***";
133 setText(nameColIdx, sym->name);
135 type = sym_get_type(sym);
141 if (!sym_is_changeable(sym) && list->optMode == normalOpt) {
142 setIcon(promptColIdx, QIcon());
145 expr = sym_get_tristate_value(sym);
148 if (sym_is_choice_value(sym) && type == S_BOOLEAN)
149 setIcon(promptColIdx, choiceYesIcon);
151 setIcon(promptColIdx, symbolYesIcon);
155 setIcon(promptColIdx, symbolModIcon);
159 if (sym_is_choice_value(sym) && type == S_BOOLEAN)
160 setIcon(promptColIdx, choiceNoIcon);
162 setIcon(promptColIdx, symbolNoIcon);
167 setText(dataColIdx, QChar(ch));
172 setText(dataColIdx, sym_get_string_value(sym));
175 if (!sym_has_value(sym) && visible)
178 setText(promptColIdx, prompt);
181 void ConfigItem::testUpdateMenu(bool v)
189 sym_calc_value(menu->sym);
190 if (menu->flags & MENU_CHANGED) {
191 /* the menu entry changed, so update all list items */
192 menu->flags &= ~MENU_CHANGED;
193 for (i = (ConfigItem*)menu->data; i; i = i->nextItem)
195 } else if (listView()->updateAll)
201 * construct a menu entry
203 void ConfigItem::init(void)
206 ConfigList* list = listView();
207 nextItem = (ConfigItem*)menu->data;
210 if (list->mode != fullMode)
212 sym_calc_value(menu->sym);
215 enum symbol_type type = menu->sym->type;
217 // Allow to edit "int", "hex", and "string" in-place in
218 // the data column. Unfortunately, you cannot specify
219 // the flags per column. Set ItemIsEditable for all
220 // columns here, and check the column in createEditor().
221 if (type == S_INT || type == S_HEX || type == S_STRING)
222 setFlags(flags() | Qt::ItemIsEditable);
229 * destruct a menu entry
231 ConfigItem::~ConfigItem(void)
234 ConfigItem** ip = (ConfigItem**)&menu->data;
235 for (; *ip; ip = &(*ip)->nextItem) {
244 QWidget *ConfigItemDelegate::createEditor(QWidget *parent,
245 const QStyleOptionViewItem &option,
246 const QModelIndex &index) const
250 // Only the data column is editable
251 if (index.column() != dataColIdx)
254 // You cannot edit invisible menus
255 item = static_cast<ConfigItem *>(index.internalPointer());
256 if (!item || !item->menu || !menu_is_visible(item->menu))
259 return QStyledItemDelegate::createEditor(parent, option, index);
262 void ConfigItemDelegate::setModelData(QWidget *editor,
263 QAbstractItemModel *model,
264 const QModelIndex &index) const
271 lineEdit = qobject_cast<QLineEdit *>(editor);
272 // If this is not a QLineEdit, use the parent's default.
273 // (does this happen?)
277 item = static_cast<ConfigItem *>(index.internalPointer());
278 if (!item || !item->menu)
281 sym = item->menu->sym;
285 success = sym_set_string_value(sym, lineEdit->text().toUtf8().data());
287 ConfigList::updateListForAll();
289 QMessageBox::information(editor, "qconf",
290 "Cannot set the data (maybe due to out of range).\n"
291 "Setting the old value.");
292 lineEdit->setText(sym_get_string_value(sym));
296 QStyledItemDelegate::setModelData(editor, model, index);
299 ConfigList::ConfigList(QWidget *parent, const char *name)
300 : QTreeWidget(parent),
302 showName(false), mode(singleMode), optMode(normalOpt),
303 rootEntry(0), headerPopup(0)
306 setSortingEnabled(false);
307 setRootIsDecorated(true);
309 setVerticalScrollMode(ScrollPerPixel);
310 setHorizontalScrollMode(ScrollPerPixel);
312 setHeaderLabels(QStringList() << "Option" << "Name" << "Value");
314 connect(this, &ConfigList::itemSelectionChanged,
315 this, &ConfigList::updateSelection);
318 configSettings->beginGroup(name);
319 showName = configSettings->value("/showName", false).toBool();
320 optMode = (enum optionMode)configSettings->value("/optionMode", 0).toInt();
321 configSettings->endGroup();
322 connect(configApp, &QApplication::aboutToQuit,
323 this, &ConfigList::saveSettings);
326 showColumn(promptColIdx);
328 setItemDelegate(new ConfigItemDelegate(this));
330 allLists.append(this);
335 ConfigList::~ConfigList()
337 allLists.removeOne(this);
340 bool ConfigList::menuSkip(struct menu *menu)
342 if (optMode == normalOpt && menu_is_visible(menu))
344 if (optMode == promptOpt && menu_has_prompt(menu))
346 if (optMode == allOpt)
351 void ConfigList::reinit(void)
353 hideColumn(nameColIdx);
356 showColumn(nameColIdx);
361 void ConfigList::setOptionMode(QAction *action)
363 if (action == showNormalAction)
365 else if (action == showAllAction)
373 void ConfigList::saveSettings(void)
375 if (!objectName().isEmpty()) {
376 configSettings->beginGroup(objectName());
377 configSettings->setValue("/showName", showName);
378 configSettings->setValue("/optionMode", (int)optMode);
379 configSettings->endGroup();
383 ConfigItem* ConfigList::findConfigItem(struct menu *menu)
385 ConfigItem* item = (ConfigItem*)menu->data;
387 for (; item; item = item->nextItem) {
388 if (this == item->listView())
395 void ConfigList::updateSelection(void)
400 if (selectedItems().count() == 0)
403 ConfigItem* item = (ConfigItem*)selectedItems().first();
408 emit menuChanged(menu);
411 type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
412 if (mode == menuMode && type == P_MENU)
413 emit menuSelected(menu);
416 void ConfigList::updateList()
418 ConfigItem* last = 0;
422 if (mode != listMode)
424 QTreeWidgetItemIterator it(this);
427 item = (ConfigItem*)(*it);
430 item->testUpdateMenu(menu_is_visible(item->menu));
437 if (rootEntry != &rootmenu && (mode == singleMode ||
438 (mode == symbolMode && rootEntry->parent != &rootmenu))) {
439 item = (ConfigItem *)topLevelItem(0);
441 item = new ConfigItem(this, 0, true);
444 if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) &&
445 rootEntry->sym && rootEntry->prompt) {
446 item = last ? last->nextSibling() : nullptr;
448 item = new ConfigItem(this, last, rootEntry, true);
450 item->testUpdateMenu(true);
452 updateMenuList(item, rootEntry);
454 resizeColumnToContents(0);
458 updateMenuList(rootEntry);
460 resizeColumnToContents(0);
463 void ConfigList::updateListForAll()
465 QListIterator<ConfigList *> it(allLists);
467 while (it.hasNext()) {
468 ConfigList *list = it.next();
474 void ConfigList::updateListAllForAll()
476 QListIterator<ConfigList *> it(allLists);
478 while (it.hasNext()) {
479 ConfigList *list = it.next();
485 void ConfigList::setValue(ConfigItem* item, tristate val)
491 sym = item->menu ? item->menu->sym : 0;
495 type = sym_get_type(sym);
499 oldval = sym_get_tristate_value(sym);
501 if (!sym_set_tristate_value(sym, val))
503 if (oldval == no && item->menu->list)
504 item->setExpanded(true);
505 ConfigList::updateListForAll();
510 void ConfigList::changeValue(ConfigItem* item)
514 int type, oldexpr, newexpr;
521 if (item->menu->list)
522 item->setExpanded(!item->isExpanded());
526 type = sym_get_type(sym);
530 oldexpr = sym_get_tristate_value(sym);
531 newexpr = sym_toggle_tristate_value(sym);
532 if (item->menu->list) {
533 if (oldexpr == newexpr)
534 item->setExpanded(!item->isExpanded());
535 else if (oldexpr == no)
536 item->setExpanded(true);
538 if (oldexpr != newexpr)
539 ConfigList::updateListForAll();
546 void ConfigList::setRootMenu(struct menu *menu)
550 if (rootEntry == menu)
552 type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
559 setSelected(currentItem(), hasFocus());
560 scrollToItem(currentItem());
564 void ConfigList::setParentMenu(void)
567 struct menu *oldroot;
570 if (rootEntry == &rootmenu)
572 setRootMenu(menu_get_parent_menu(rootEntry->parent));
574 QTreeWidgetItemIterator it(this);
576 item = (ConfigItem *)(*it);
577 if (item->menu == oldroot) {
578 setCurrentItem(item);
588 * update all the children of a menu entry
589 * removes/adds the entries from the parent widget as necessary
591 * parent: either the menu list widget or a menu entry widget
592 * menu: entry to be updated
594 void ConfigList::updateMenuList(ConfigItem *parent, struct menu* menu)
603 while (parent->childCount() > 0)
605 delete parent->takeChild(0);
611 last = parent->firstChild();
612 if (last && !last->goParent)
614 for (child = menu->list; child; child = child->next) {
615 item = last ? last->nextSibling() : parent->firstChild();
616 type = child->prompt ? child->prompt->type : P_UNKNOWN;
620 if (!(child->flags & MENU_ROOT))
624 if (child->flags & MENU_ROOT)
631 visible = menu_is_visible(child);
632 if (!menuSkip(child)) {
633 if (!child->sym && !child->list && !child->prompt)
635 if (!item || item->menu != child)
636 item = new ConfigItem(parent, last, child, visible);
638 item->testUpdateMenu(visible);
640 if (mode == fullMode || mode == menuMode || type != P_MENU)
641 updateMenuList(item, child);
643 updateMenuList(item, 0);
648 if (item && item->menu == child) {
649 last = parent->firstChild();
652 else while (last->nextSibling() != item)
653 last = last->nextSibling();
659 void ConfigList::updateMenuList(struct menu *menu)
668 while (topLevelItemCount() > 0)
670 delete takeTopLevelItem(0);
676 last = (ConfigItem *)topLevelItem(0);
677 if (last && !last->goParent)
679 for (child = menu->list; child; child = child->next) {
680 item = last ? last->nextSibling() : (ConfigItem *)topLevelItem(0);
681 type = child->prompt ? child->prompt->type : P_UNKNOWN;
685 if (!(child->flags & MENU_ROOT))
689 if (child->flags & MENU_ROOT)
696 visible = menu_is_visible(child);
697 if (!menuSkip(child)) {
698 if (!child->sym && !child->list && !child->prompt)
700 if (!item || item->menu != child)
701 item = new ConfigItem(this, last, child, visible);
703 item->testUpdateMenu(visible);
705 if (mode == fullMode || mode == menuMode || type != P_MENU)
706 updateMenuList(item, child);
708 updateMenuList(item, 0);
713 if (item && item->menu == child) {
714 last = (ConfigItem *)topLevelItem(0);
717 else while (last->nextSibling() != item)
718 last = last->nextSibling();
724 void ConfigList::keyPressEvent(QKeyEvent* ev)
726 QTreeWidgetItem* i = currentItem();
731 if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) {
732 emit parentSelected();
738 Parent::keyPressEvent(ev);
741 item = (ConfigItem*)i;
746 if (item->goParent) {
747 emit parentSelected();
753 type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
754 if (type == P_MENU && rootEntry != menu &&
755 mode != fullMode && mode != menuMode) {
756 if (mode == menuMode)
757 emit menuSelected(menu);
759 emit itemSelected(menu);
775 Parent::keyPressEvent(ev);
781 void ConfigList::mousePressEvent(QMouseEvent* e)
783 //QPoint p(contentsToViewport(e->pos()));
784 //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
785 Parent::mousePressEvent(e);
788 void ConfigList::mouseReleaseEvent(QMouseEvent* e)
791 ConfigItem* item = (ConfigItem*)itemAt(p);
793 enum prop_type ptype;
801 x = header()->offset() + p.x();
802 idx = header()->logicalIndexAt(x);
805 icon = item->icon(promptColIdx);
806 if (!icon.isNull()) {
807 int off = header()->sectionPosition(0) + visualRect(indexAt(p)).x() + 4; // 4 is Hardcoded image offset. There might be a way to do it properly.
808 if (x >= off && x < off + icon.availableSizes().first().width()) {
809 if (item->goParent) {
810 emit parentSelected();
814 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
815 if (ptype == P_MENU && rootEntry != menu &&
816 mode != fullMode && mode != menuMode &&
818 emit menuSelected(menu);
830 //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
831 Parent::mouseReleaseEvent(e);
834 void ConfigList::mouseMoveEvent(QMouseEvent* e)
836 //QPoint p(contentsToViewport(e->pos()));
837 //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
838 Parent::mouseMoveEvent(e);
841 void ConfigList::mouseDoubleClickEvent(QMouseEvent* e)
844 ConfigItem* item = (ConfigItem*)itemAt(p);
846 enum prop_type ptype;
850 if (item->goParent) {
851 emit parentSelected();
857 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
858 if (ptype == P_MENU && mode != listMode) {
859 if (mode == singleMode)
860 emit itemSelected(menu);
861 else if (mode == symbolMode)
862 emit menuSelected(menu);
863 } else if (menu->sym)
867 //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
868 Parent::mouseDoubleClickEvent(e);
871 void ConfigList::focusInEvent(QFocusEvent *e)
873 struct menu *menu = NULL;
875 Parent::focusInEvent(e);
877 ConfigItem* item = (ConfigItem *)currentItem();
879 setSelected(item, true);
885 void ConfigList::contextMenuEvent(QContextMenuEvent *e)
890 headerPopup = new QMenu(this);
891 action = new QAction("Show Name", this);
892 action->setCheckable(true);
893 connect(action, &QAction::toggled,
894 this, &ConfigList::setShowName);
895 connect(this, &ConfigList::showNameChanged,
896 action, &QAction::setChecked);
897 action->setChecked(showName);
898 headerPopup->addAction(action);
901 headerPopup->exec(e->globalPos());
905 void ConfigList::setShowName(bool on)
912 emit showNameChanged(on);
915 QList<ConfigList *> ConfigList::allLists;
916 QAction *ConfigList::showNormalAction;
917 QAction *ConfigList::showAllAction;
918 QAction *ConfigList::showPromptAction;
920 void ConfigList::setAllOpen(bool open)
922 QTreeWidgetItemIterator it(this);
925 (*it)->setExpanded(open);
931 ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
932 : Parent(parent), sym(0), _menu(0)
937 if (!objectName().isEmpty()) {
938 configSettings->beginGroup(objectName());
939 setShowDebug(configSettings->value("/showDebug", false).toBool());
940 configSettings->endGroup();
941 connect(configApp, &QApplication::aboutToQuit,
942 this, &ConfigInfoView::saveSettings);
945 contextMenu = createStandardContextMenu();
946 QAction *action = new QAction("Show Debug Info", contextMenu);
948 action->setCheckable(true);
949 connect(action, &QAction::toggled,
950 this, &ConfigInfoView::setShowDebug);
951 connect(this, &ConfigInfoView::showDebugChanged,
952 action, &QAction::setChecked);
953 action->setChecked(showDebug());
954 contextMenu->addSeparator();
955 contextMenu->addAction(action);
958 void ConfigInfoView::saveSettings(void)
960 if (!objectName().isEmpty()) {
961 configSettings->beginGroup(objectName());
962 configSettings->setValue("/showDebug", showDebug());
963 configSettings->endGroup();
967 void ConfigInfoView::setShowDebug(bool b)
969 if (_showDebug != b) {
975 emit showDebugChanged(b);
979 void ConfigInfoView::setInfo(struct menu *m)
991 void ConfigInfoView::symbolInfo(void)
995 str += "<big>Symbol: <b>";
996 str += print_filter(sym->name);
997 str += "</b></big><br><br>value: ";
998 str += print_filter(sym_get_string_value(sym));
999 str += "<br>visibility: ";
1000 str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n";
1002 str += debug_info(sym);
1007 void ConfigInfoView::menuInfo(void)
1011 QTextStream stream(&info);
1015 if (_menu->prompt) {
1016 stream << "<big><b>";
1017 stream << print_filter(_menu->prompt->text);
1018 stream << "</b></big>";
1022 stream << "<a href=\"s" << sym->name << "\">";
1023 stream << print_filter(sym->name);
1028 } else if (sym->name) {
1029 stream << "<big><b>";
1031 stream << "<a href=\"s" << sym->name << "\">";
1032 stream << print_filter(sym->name);
1035 stream << "</b></big>";
1037 stream << "<br><br>";
1040 stream << debug_info(sym);
1042 struct gstr help_gstr = str_new();
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>";
1052 if (_menu->prompt->visible.expr) {
1053 stream << " dep: ";
1054 expr_print(_menu->prompt->visible.expr,
1055 expr_print_help, &stream, E_NONE);
1056 stream << "<br><br>";
1059 stream << "defined at " << _menu->file->name << ":"
1060 << _menu->lineno << "<br><br>";
1067 QString ConfigInfoView::debug_info(struct symbol *sym)
1070 QTextStream stream(&debug);
1073 stream << print_filter(sym_type_name(sym->type));
1074 if (sym_is_choice(sym))
1075 stream << " (choice)";
1077 if (sym->rev_dep.expr) {
1078 stream << "reverse dep: ";
1079 expr_print(sym->rev_dep.expr, expr_print_help, &stream, E_NONE);
1082 for (struct property *prop = sym->prop; prop; prop = prop->next) {
1083 switch (prop->type) {
1086 stream << "prompt: <a href=\"m" << sym->name << "\">";
1087 stream << print_filter(prop->text);
1088 stream << "</a><br>";
1096 stream << prop_get_type_name(prop->type);
1098 expr_print(prop->expr, expr_print_help,
1103 if (sym_is_choice(sym)) {
1104 stream << "choice: ";
1105 expr_print(prop->expr, expr_print_help,
1111 stream << "unknown property: ";
1112 stream << prop_get_type_name(prop->type);
1115 if (prop->visible.expr) {
1116 stream << " dep: ";
1117 expr_print(prop->visible.expr, expr_print_help,
1127 QString ConfigInfoView::print_filter(const QString &str)
1129 QRegExp re("[<>&\"\\n]");
1131 for (int i = 0; (i = res.indexOf(re, i)) >= 0;) {
1132 switch (res[i].toLatin1()) {
1134 res.replace(i, 1, "<");
1138 res.replace(i, 1, ">");
1142 res.replace(i, 1, "&");
1146 res.replace(i, 1, """);
1150 res.replace(i, 1, "<br>");
1158 void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str)
1160 QTextStream *stream = reinterpret_cast<QTextStream *>(data);
1162 if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
1163 *stream << "<a href=\"s" << sym->name << "\">";
1164 *stream << print_filter(str);
1167 *stream << print_filter(str);
1171 void ConfigInfoView::clicked(const QUrl &url)
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;
1184 memcpy(data, str.constData(), count);
1187 /* Seek for exact match */
1190 result = sym_re_search(data);
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)
1207 /* Symbol is not visible as a menu */
1209 emit showDebugChanged(true);
1211 emit menuSelected(m);
1218 void ConfigInfoView::contextMenuEvent(QContextMenuEvent *event)
1220 contextMenu->popup(event->globalPos());
1224 ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow *parent)
1225 : Parent(parent), result(NULL)
1227 setObjectName("search");
1228 setWindowTitle("Search Config");
1230 QVBoxLayout* layout1 = new QVBoxLayout(this);
1231 layout1->setContentsMargins(11, 11, 11, 11);
1232 layout1->setSpacing(6);
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);
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);
1259 layout1->addWidget(split);
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);
1275 split->setSizes(sizes);
1276 configSettings->endGroup();
1277 connect(configApp, &QApplication::aboutToQuit,
1278 this, &ConfigSearchWindow::saveSettings);
1281 void ConfigSearchWindow::saveSettings(void)
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();
1294 void ConfigSearchWindow::search(void)
1297 struct property *prop;
1298 ConfigItem *lastItem = NULL;
1304 result = sym_re_search(editField->text().toLatin1());
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));
1315 * Construct the complete config widget
1317 ConfigMainWindow::ConfigMainWindow(void)
1325 QDesktopWidget *d = configApp->desktop();
1326 snprintf(title, sizeof(title), "%s%s",
1327 rootmenu.prompt->text,
1330 setWindowTitle(title);
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());
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));
1349 QWidget *widget = new QWidget(this);
1350 QVBoxLayout *layout = new QVBoxLayout(widget);
1351 setCentralWidget(widget);
1353 split1 = new QSplitter(widget);
1354 split1->setOrientation(Qt::Horizontal);
1355 split1->setChildrenCollapsible(false);
1357 menuList = new ConfigList(widget, "menu");
1359 split2 = new QSplitter(widget);
1360 split2->setChildrenCollapsible(false);
1361 split2->setOrientation(Qt::Vertical);
1363 // create config tree
1364 configList = new ConfigList(widget, "config");
1366 helpText = new ConfigInfoView(widget, "help");
1368 layout->addWidget(split2);
1369 split2->addWidget(split1);
1370 split1->addWidget(configList);
1371 split1->addWidget(menuList);
1372 split2->addWidget(helpText);
1374 setTabOrder(configList, helpText);
1375 configList->setFocus();
1377 backAction = new QAction(QPixmap(xpm_back), "Back", this);
1378 connect(backAction, &QAction::triggered,
1379 this, &ConfigMainWindow::goBack);
1381 QAction *quitAction = new QAction("&Quit", this);
1382 quitAction->setShortcut(Qt::CTRL + Qt::Key_Q);
1383 connect(quitAction, &QAction::triggered,
1384 this, &ConfigMainWindow::close);
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);
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);
1396 conf_set_changed_callback(conf_changed);
1398 // Set saveAction's initial state
1400 configname = xstrdup(conf_get_configname());
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);
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);
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);
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);
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());
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);
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);
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);
1475 menu = menuBar()->addMenu("&Edit");
1476 menu->addAction(searchAction);
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);
1487 menu = menuBar()->addMenu("&Help");
1488 menu->addAction(showIntroAction);
1489 menu->addAction(showAboutAction);
1491 connect(helpText, &ConfigInfoView::anchorClicked,
1492 helpText, &ConfigInfoView::clicked);
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);
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);
1516 QString listMode = configSettings->value("/listMode", "symbol").toString();
1517 if (listMode == "single")
1519 else if (listMode == "full")
1521 else /*if (listMode == "split")*/
1524 // UI setup done, restore splitter positions
1525 QList<int> sizes = configSettings->readSizes("/split1", &ok);
1527 split1->setSizes(sizes);
1529 sizes = configSettings->readSizes("/split2", &ok);
1531 split2->setSizes(sizes);
1534 void ConfigMainWindow::loadConfig(void)
1540 str = QFileDialog::getOpenFileName(this, "", configname);
1544 ba = str.toLocal8Bit();
1547 if (conf_read(name))
1548 QMessageBox::information(this, "qconf", "Unable to load configuration!");
1551 configname = xstrdup(name);
1553 ConfigList::updateListAllForAll();
1556 bool ConfigMainWindow::saveConfig(void)
1558 if (conf_write(configname)) {
1559 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1562 conf_write_autoconf(0);
1567 void ConfigMainWindow::saveConfigAs(void)
1573 str = QFileDialog::getSaveFileName(this, "", configname);
1577 ba = str.toLocal8Bit();
1580 if (conf_write(name)) {
1581 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1583 conf_write_autoconf(0);
1586 configname = xstrdup(name);
1589 void ConfigMainWindow::searchConfig(void)
1592 searchWindow = new ConfigSearchWindow(this);
1593 searchWindow->show();
1596 void ConfigMainWindow::changeItens(struct menu *menu)
1598 configList->setRootMenu(menu);
1601 void ConfigMainWindow::changeMenu(struct menu *menu)
1603 menuList->setRootMenu(menu);
1606 void ConfigMainWindow::setMenuLink(struct menu *menu)
1608 struct menu *parent;
1609 ConfigList* list = NULL;
1612 if (configList->menuSkip(menu))
1615 switch (configList->mode) {
1618 parent = menu_get_parent_menu(menu);
1621 list->setRootMenu(parent);
1624 if (menu->flags & MENU_ROOT) {
1625 menuList->setRootMenu(menu);
1626 configList->clearSelection();
1629 parent = menu_get_parent_menu(menu->parent);
1633 /* Select the config view */
1634 item = configList->findConfigItem(parent);
1636 configList->setSelected(item, true);
1637 configList->scrollToItem(item);
1640 menuList->setRootMenu(parent);
1641 menuList->clearSelection();
1653 item = list->findConfigItem(menu);
1655 list->setSelected(item, true);
1656 list->scrollToItem(item);
1658 helpText->setInfo(menu);
1663 void ConfigMainWindow::listFocusChanged(void)
1665 if (menuList->mode == menuMode)
1666 configList->clearSelection();
1669 void ConfigMainWindow::goBack(void)
1671 if (configList->rootEntry == &rootmenu)
1674 configList->setParentMenu();
1677 void ConfigMainWindow::showSingleView(void)
1679 singleViewAction->setEnabled(false);
1680 singleViewAction->setChecked(true);
1681 splitViewAction->setEnabled(true);
1682 splitViewAction->setChecked(false);
1683 fullViewAction->setEnabled(true);
1684 fullViewAction->setChecked(false);
1686 backAction->setEnabled(true);
1689 menuList->setRootMenu(0);
1690 configList->mode = singleMode;
1691 if (configList->rootEntry == &rootmenu)
1692 configList->updateListAll();
1694 configList->setRootMenu(&rootmenu);
1695 configList->setFocus();
1698 void ConfigMainWindow::showSplitView(void)
1700 singleViewAction->setEnabled(true);
1701 singleViewAction->setChecked(false);
1702 splitViewAction->setEnabled(false);
1703 splitViewAction->setChecked(true);
1704 fullViewAction->setEnabled(true);
1705 fullViewAction->setChecked(false);
1707 backAction->setEnabled(false);
1709 configList->mode = menuMode;
1710 if (configList->rootEntry == &rootmenu)
1711 configList->updateListAll();
1713 configList->setRootMenu(&rootmenu);
1714 configList->setAllOpen(true);
1715 configApp->processEvents();
1716 menuList->mode = symbolMode;
1717 menuList->setRootMenu(&rootmenu);
1718 menuList->setAllOpen(true);
1720 menuList->setFocus();
1723 void ConfigMainWindow::showFullView(void)
1725 singleViewAction->setEnabled(true);
1726 singleViewAction->setChecked(false);
1727 splitViewAction->setEnabled(true);
1728 splitViewAction->setChecked(false);
1729 fullViewAction->setEnabled(false);
1730 fullViewAction->setChecked(true);
1732 backAction->setEnabled(false);
1735 menuList->setRootMenu(0);
1736 configList->mode = fullMode;
1737 if (configList->rootEntry == &rootmenu)
1738 configList->updateListAll();
1740 configList->setRootMenu(&rootmenu);
1741 configList->setFocus();
1745 * ask for saving configuration before quitting
1747 void ConfigMainWindow::closeEvent(QCloseEvent* e)
1749 if (!conf_get_changed()) {
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:
1765 case QMessageBox::No:
1768 case QMessageBox::Cancel:
1774 void ConfigMainWindow::showIntro(void)
1776 static const QString str =
1777 "Welcome to the qconf graphical configuration tool.\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"
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 "
1793 "Toggling Show Debug Info under the Options menu will show the "
1794 "dependencies, which you can then match by examining other "
1797 QMessageBox::information(this, "qconf", str);
1800 void ConfigMainWindow::showAbout(void)
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"
1805 "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n"
1809 QMessageBox::information(this, "qconf", str + qVersion());
1812 void ConfigMainWindow::saveSettings(void)
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());
1820 switch(configList->mode) {
1836 configSettings->setValue("/listMode", entry);
1838 configSettings->writeSizes("/split1", split1->sizes());
1839 configSettings->writeSizes("/split2", split2->sizes());
1842 void ConfigMainWindow::conf_changed(void)
1845 saveAction->setEnabled(conf_get_changed());
1848 void fixup_rootmenu(struct menu *menu)
1851 static int menu_cnt = 0;
1853 menu->flags |= MENU_ROOT;
1854 for (child = menu->list; child; child = child->next) {
1855 if (child->prompt && child->prompt->type == P_MENU) {
1857 fixup_rootmenu(child);
1859 } else if (!menu_cnt)
1860 fixup_rootmenu(child);
1864 static const char *progname;
1866 static void usage(void)
1868 printf("%s [-s] <config>\n", progname);
1872 int main(int ac, char** av)
1874 ConfigMainWindow* v;
1878 if (ac > 1 && av[1][0] == '-') {
1881 conf_set_message_callback(NULL);
1894 fixup_rootmenu(&rootmenu);
1896 //zconfdump(stdout);
1898 configApp = new QApplication(ac, av);
1900 configSettings = new ConfigSettings();
1901 configSettings->beginGroup("/kconfig/qconf");
1902 v = new ConfigMainWindow();
1904 //zconfdump(stdout);
1905 configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
1906 configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1910 configSettings->endGroup();
1911 delete configSettings;