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 static inline QString qgettext(const char* str)
36 return QString::fromLocal8Bit(str);
39 ConfigSettings::ConfigSettings()
40 : QSettings("kernel.org", "qconf")
45 * Reads a list of integer values from the application settings.
47 QList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
53 QStringList entryList = value(key).toStringList();
54 QStringList::Iterator it;
56 for (it = entryList.begin(); it != entryList.end(); ++it)
57 result.push_back((*it).toInt());
68 * Writes a list of integer values to the application settings.
70 bool ConfigSettings::writeSizes(const QString& key, const QList<int>& value)
72 QStringList stringList;
73 QList<int>::ConstIterator it;
75 for (it = value.begin(); it != value.end(); ++it)
76 stringList.push_back(QString::number(*it));
77 setValue(key, stringList);
85 * TODO check the value
87 void ConfigItem::okRename(int col)
92 * update the displayed of a menu entry
94 void ConfigItem::updateMenu(void)
98 struct property *prop;
105 setPixmap(promptColIdx, list->menuBackPix);
112 prompt = qgettext(menu_get_prompt(menu));
114 if (prop) switch (prop->type) {
116 if (list->mode == singleMode || list->mode == symbolMode) {
117 /* a menuconfig entry is displayed differently
118 * depending whether it's at the view root or a child.
120 if (sym && list->rootEntry == menu)
122 setPixmap(promptColIdx, list->menuPix);
126 setPixmap(promptColIdx, QIcon());
130 setPixmap(promptColIdx, QIcon());
138 setText(nameColIdx, QString::fromLocal8Bit(sym->name));
140 type = sym_get_type(sym);
146 if (!sym_is_changeable(sym) && list->optMode == normalOpt) {
147 setPixmap(promptColIdx, QIcon());
148 setText(noColIdx, QString());
149 setText(modColIdx, QString());
150 setText(yesColIdx, QString());
153 expr = sym_get_tristate_value(sym);
156 if (sym_is_choice_value(sym) && type == S_BOOLEAN)
157 setPixmap(promptColIdx, list->choiceYesPix);
159 setPixmap(promptColIdx, list->symbolYesPix);
160 setText(yesColIdx, "Y");
164 setPixmap(promptColIdx, list->symbolModPix);
165 setText(modColIdx, "M");
169 if (sym_is_choice_value(sym) && type == S_BOOLEAN)
170 setPixmap(promptColIdx, list->choiceNoPix);
172 setPixmap(promptColIdx, list->symbolNoPix);
173 setText(noColIdx, "N");
178 setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0);
180 setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0);
182 setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0);
184 setText(dataColIdx, QChar(ch));
191 data = sym_get_string_value(sym);
193 setText(dataColIdx, data);
194 if (type == S_STRING)
195 prompt = QString("%1: %2").arg(prompt).arg(data);
197 prompt = QString("(%2) %1").arg(prompt).arg(data);
200 if (!sym_has_value(sym) && visible)
203 setText(promptColIdx, prompt);
206 void ConfigItem::testUpdateMenu(bool v)
214 sym_calc_value(menu->sym);
215 if (menu->flags & MENU_CHANGED) {
216 /* the menu entry changed, so update all list items */
217 menu->flags &= ~MENU_CHANGED;
218 for (i = (ConfigItem*)menu->data; i; i = i->nextItem)
220 } else if (listView()->updateAll)
226 * construct a menu entry
228 void ConfigItem::init(void)
231 ConfigList* list = listView();
232 nextItem = (ConfigItem*)menu->data;
235 if (list->mode != fullMode)
237 sym_calc_value(menu->sym);
243 * destruct a menu entry
245 ConfigItem::~ConfigItem(void)
248 ConfigItem** ip = (ConfigItem**)&menu->data;
249 for (; *ip; ip = &(*ip)->nextItem) {
258 ConfigLineEdit::ConfigLineEdit(ConfigView* parent)
261 connect(this, SIGNAL(editingFinished()), SLOT(hide()));
264 void ConfigLineEdit::show(ConfigItem* i)
267 if (sym_get_string_value(item->menu->sym))
268 setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym)));
275 void ConfigLineEdit::keyPressEvent(QKeyEvent* e)
282 sym_set_string_value(item->menu->sym, text().toLatin1());
283 parent()->updateList(item);
286 Parent::keyPressEvent(e);
290 parent()->list->setFocus();
294 ConfigList::ConfigList(ConfigView* p, const char *name)
297 symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no),
298 choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no),
299 menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void),
300 showName(false), showRange(false), showData(false), mode(singleMode), optMode(normalOpt),
301 rootEntry(0), headerPopup(0)
304 setSortingEnabled(false);
305 setRootIsDecorated(true);
307 setVerticalScrollMode(ScrollPerPixel);
308 setHorizontalScrollMode(ScrollPerPixel);
310 setHeaderLabels(QStringList() << "Option" << "Name" << "N" << "M" << "Y" << "Value");
312 connect(this, SIGNAL(itemSelectionChanged(void)),
313 SLOT(updateSelection(void)));
316 configSettings->beginGroup(name);
317 showName = configSettings->value("/showName", false).toBool();
318 showRange = configSettings->value("/showRange", false).toBool();
319 showData = configSettings->value("/showData", false).toBool();
320 optMode = (enum optionMode)configSettings->value("/optionMode", 0).toInt();
321 configSettings->endGroup();
322 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
325 addColumn(promptColIdx);
330 bool ConfigList::menuSkip(struct menu *menu)
332 if (optMode == normalOpt && menu_is_visible(menu))
334 if (optMode == promptOpt && menu_has_prompt(menu))
336 if (optMode == allOpt)
341 void ConfigList::reinit(void)
343 removeColumn(dataColIdx);
344 removeColumn(yesColIdx);
345 removeColumn(modColIdx);
346 removeColumn(noColIdx);
347 removeColumn(nameColIdx);
350 addColumn(nameColIdx);
353 addColumn(modColIdx);
354 addColumn(yesColIdx);
357 addColumn(dataColIdx);
362 void ConfigList::saveSettings(void)
364 if (!objectName().isEmpty()) {
365 configSettings->beginGroup(objectName());
366 configSettings->setValue("/showName", showName);
367 configSettings->setValue("/showRange", showRange);
368 configSettings->setValue("/showData", showData);
369 configSettings->setValue("/optionMode", (int)optMode);
370 configSettings->endGroup();
374 ConfigItem* ConfigList::findConfigItem(struct menu *menu)
376 ConfigItem* item = (ConfigItem*)menu->data;
378 for (; item; item = item->nextItem) {
379 if (this == item->listView())
386 void ConfigList::updateSelection(void)
391 if (selectedItems().count() == 0)
394 ConfigItem* item = (ConfigItem*)selectedItems().first();
399 emit menuChanged(menu);
402 type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
403 if (mode == menuMode && type == P_MENU)
404 emit menuSelected(menu);
407 void ConfigList::updateList(ConfigItem* item)
409 ConfigItem* last = 0;
412 if (mode != listMode)
414 QTreeWidgetItemIterator it(this);
418 item = (ConfigItem*)(*it);
421 item->testUpdateMenu(menu_is_visible(item->menu));
428 if (rootEntry != &rootmenu && (mode == singleMode ||
429 (mode == symbolMode && rootEntry->parent != &rootmenu))) {
430 item = (ConfigItem *)topLevelItem(0);
432 item = new ConfigItem(this, 0, true);
435 if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) &&
436 rootEntry->sym && rootEntry->prompt) {
437 item = last ? last->nextSibling() : nullptr;
439 item = new ConfigItem(this, last, rootEntry, true);
441 item->testUpdateMenu(true);
443 updateMenuList(item, rootEntry);
445 resizeColumnToContents(0);
449 updateMenuList(this, rootEntry);
451 resizeColumnToContents(0);
454 void ConfigList::setValue(ConfigItem* item, tristate val)
460 sym = item->menu ? item->menu->sym : 0;
464 type = sym_get_type(sym);
468 oldval = sym_get_tristate_value(sym);
470 if (!sym_set_tristate_value(sym, val))
472 if (oldval == no && item->menu->list)
473 item->setExpanded(true);
474 parent()->updateList(item);
479 void ConfigList::changeValue(ConfigItem* item)
483 int type, oldexpr, newexpr;
490 if (item->menu->list)
491 item->setExpanded(!item->isExpanded());
495 type = sym_get_type(sym);
499 oldexpr = sym_get_tristate_value(sym);
500 newexpr = sym_toggle_tristate_value(sym);
501 if (item->menu->list) {
502 if (oldexpr == newexpr)
503 item->setExpanded(!item->isExpanded());
504 else if (oldexpr == no)
505 item->setExpanded(true);
507 if (oldexpr != newexpr)
508 parent()->updateList(item);
513 parent()->lineEdit->show(item);
518 void ConfigList::setRootMenu(struct menu *menu)
522 if (rootEntry == menu)
524 type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
527 updateMenuList(this, 0);
531 setSelected(currentItem(), hasFocus());
532 scrollToItem(currentItem());
536 void ConfigList::setParentMenu(void)
539 struct menu *oldroot;
542 if (rootEntry == &rootmenu)
544 setRootMenu(menu_get_parent_menu(rootEntry->parent));
546 QTreeWidgetItemIterator it(this);
548 item = (ConfigItem *)(*it);
549 if (item->menu == oldroot) {
550 setCurrentItem(item);
560 * update all the children of a menu entry
561 * removes/adds the entries from the parent widget as necessary
563 * parent: either the menu list widget or a menu entry widget
564 * menu: entry to be updated
566 void ConfigList::updateMenuList(ConfigItem *parent, struct menu* menu)
575 while (parent->childCount() > 0)
577 delete parent->takeChild(0);
583 last = parent->firstChild();
584 if (last && !last->goParent)
586 for (child = menu->list; child; child = child->next) {
587 item = last ? last->nextSibling() : parent->firstChild();
588 type = child->prompt ? child->prompt->type : P_UNKNOWN;
592 if (!(child->flags & MENU_ROOT))
596 if (child->flags & MENU_ROOT)
603 visible = menu_is_visible(child);
604 if (!menuSkip(child)) {
605 if (!child->sym && !child->list && !child->prompt)
607 if (!item || item->menu != child)
608 item = new ConfigItem(parent, last, child, visible);
610 item->testUpdateMenu(visible);
612 if (mode == fullMode || mode == menuMode || type != P_MENU)
613 updateMenuList(item, child);
615 updateMenuList(item, 0);
620 if (item && item->menu == child) {
621 last = parent->firstChild();
624 else while (last->nextSibling() != item)
625 last = last->nextSibling();
631 void ConfigList::updateMenuList(ConfigList *parent, struct menu* menu)
640 while (parent->topLevelItemCount() > 0)
642 delete parent->takeTopLevelItem(0);
648 last = (ConfigItem*)parent->topLevelItem(0);
649 if (last && !last->goParent)
651 for (child = menu->list; child; child = child->next) {
652 item = last ? last->nextSibling() : (ConfigItem*)parent->topLevelItem(0);
653 type = child->prompt ? child->prompt->type : P_UNKNOWN;
657 if (!(child->flags & MENU_ROOT))
661 if (child->flags & MENU_ROOT)
668 visible = menu_is_visible(child);
669 if (!menuSkip(child)) {
670 if (!child->sym && !child->list && !child->prompt)
672 if (!item || item->menu != child)
673 item = new ConfigItem(parent, last, child, visible);
675 item->testUpdateMenu(visible);
677 if (mode == fullMode || mode == menuMode || type != P_MENU)
678 updateMenuList(item, child);
680 updateMenuList(item, 0);
685 if (item && item->menu == child) {
686 last = (ConfigItem*)parent->topLevelItem(0);
689 else while (last->nextSibling() != item)
690 last = last->nextSibling();
696 void ConfigList::keyPressEvent(QKeyEvent* ev)
698 QTreeWidgetItem* i = currentItem();
703 if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) {
704 emit parentSelected();
710 Parent::keyPressEvent(ev);
713 item = (ConfigItem*)i;
718 if (item->goParent) {
719 emit parentSelected();
725 type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
726 if (type == P_MENU && rootEntry != menu &&
727 mode != fullMode && mode != menuMode) {
728 if (mode == menuMode)
729 emit menuSelected(menu);
731 emit itemSelected(menu);
747 Parent::keyPressEvent(ev);
753 void ConfigList::mousePressEvent(QMouseEvent* e)
755 //QPoint p(contentsToViewport(e->pos()));
756 //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
757 Parent::mousePressEvent(e);
760 void ConfigList::mouseReleaseEvent(QMouseEvent* e)
763 ConfigItem* item = (ConfigItem*)itemAt(p);
765 enum prop_type ptype;
773 x = header()->offset() + p.x();
774 idx = header()->logicalIndexAt(x);
777 icon = item->pixmap(promptColIdx);
778 if (!icon.isNull()) {
779 int off = header()->sectionPosition(0) + visualRect(indexAt(p)).x() + 4; // 4 is Hardcoded image offset. There might be a way to do it properly.
780 if (x >= off && x < off + icon.availableSizes().first().width()) {
781 if (item->goParent) {
782 emit parentSelected();
786 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
787 if (ptype == P_MENU && rootEntry != menu &&
788 mode != fullMode && mode != menuMode &&
790 emit menuSelected(menu);
811 //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
812 Parent::mouseReleaseEvent(e);
815 void ConfigList::mouseMoveEvent(QMouseEvent* e)
817 //QPoint p(contentsToViewport(e->pos()));
818 //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
819 Parent::mouseMoveEvent(e);
822 void ConfigList::mouseDoubleClickEvent(QMouseEvent* e)
825 ConfigItem* item = (ConfigItem*)itemAt(p);
827 enum prop_type ptype;
831 if (item->goParent) {
832 emit parentSelected();
838 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
839 if (ptype == P_MENU && mode != listMode) {
840 if (mode == singleMode)
841 emit itemSelected(menu);
842 else if (mode == symbolMode)
843 emit menuSelected(menu);
844 } else if (menu->sym)
848 //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
849 Parent::mouseDoubleClickEvent(e);
852 void ConfigList::focusInEvent(QFocusEvent *e)
854 struct menu *menu = NULL;
856 Parent::focusInEvent(e);
858 ConfigItem* item = (ConfigItem *)currentItem();
860 setSelected(item, true);
866 void ConfigList::contextMenuEvent(QContextMenuEvent *e)
868 if (e->y() <= header()->geometry().bottom()) {
872 headerPopup = new QMenu(this);
873 action = new QAction("Show Name", this);
874 action->setCheckable(true);
875 connect(action, SIGNAL(toggled(bool)),
876 parent(), SLOT(setShowName(bool)));
877 connect(parent(), SIGNAL(showNameChanged(bool)),
878 action, SLOT(setOn(bool)));
879 action->setChecked(showName);
880 headerPopup->addAction(action);
881 action = new QAction("Show Range", this);
882 action->setCheckable(true);
883 connect(action, SIGNAL(toggled(bool)),
884 parent(), SLOT(setShowRange(bool)));
885 connect(parent(), SIGNAL(showRangeChanged(bool)),
886 action, SLOT(setOn(bool)));
887 action->setChecked(showRange);
888 headerPopup->addAction(action);
889 action = new QAction("Show Data", this);
890 action->setCheckable(true);
891 connect(action, SIGNAL(toggled(bool)),
892 parent(), SLOT(setShowData(bool)));
893 connect(parent(), SIGNAL(showDataChanged(bool)),
894 action, SLOT(setOn(bool)));
895 action->setChecked(showData);
896 headerPopup->addAction(action);
898 headerPopup->exec(e->globalPos());
904 ConfigView*ConfigView::viewList;
905 QAction *ConfigView::showNormalAction;
906 QAction *ConfigView::showAllAction;
907 QAction *ConfigView::showPromptAction;
909 ConfigView::ConfigView(QWidget* parent, const char *name)
913 QVBoxLayout *verticalLayout = new QVBoxLayout(this);
914 verticalLayout->setContentsMargins(0, 0, 0, 0);
916 list = new ConfigList(this);
917 verticalLayout->addWidget(list);
918 lineEdit = new ConfigLineEdit(this);
920 verticalLayout->addWidget(lineEdit);
922 this->nextView = viewList;
926 ConfigView::~ConfigView(void)
930 for (vp = &viewList; *vp; vp = &(*vp)->nextView) {
938 void ConfigView::setOptionMode(QAction *act)
940 if (act == showNormalAction)
941 list->optMode = normalOpt;
942 else if (act == showAllAction)
943 list->optMode = allOpt;
945 list->optMode = promptOpt;
947 list->updateListAll();
950 void ConfigView::setShowName(bool b)
952 if (list->showName != b) {
955 emit showNameChanged(b);
959 void ConfigView::setShowRange(bool b)
961 if (list->showRange != b) {
964 emit showRangeChanged(b);
968 void ConfigView::setShowData(bool b)
970 if (list->showData != b) {
973 emit showDataChanged(b);
977 void ConfigList::setAllOpen(bool open)
979 QTreeWidgetItemIterator it(this);
982 (*it)->setExpanded(open);
988 void ConfigView::updateList(ConfigItem* item)
992 for (v = viewList; v; v = v->nextView)
993 v->list->updateList(item);
996 void ConfigView::updateListAll(void)
1000 for (v = viewList; v; v = v->nextView)
1001 v->list->updateListAll();
1004 ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
1005 : Parent(parent), sym(0), _menu(0)
1007 setObjectName(name);
1008 setOpenLinks(false);
1010 if (!objectName().isEmpty()) {
1011 configSettings->beginGroup(objectName());
1012 setShowDebug(configSettings->value("/showDebug", false).toBool());
1013 configSettings->endGroup();
1014 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
1018 void ConfigInfoView::saveSettings(void)
1020 if (!objectName().isEmpty()) {
1021 configSettings->beginGroup(objectName());
1022 configSettings->setValue("/showDebug", showDebug());
1023 configSettings->endGroup();
1027 void ConfigInfoView::setShowDebug(bool b)
1029 if (_showDebug != b) {
1035 emit showDebugChanged(b);
1039 void ConfigInfoView::setInfo(struct menu *m)
1051 void ConfigInfoView::symbolInfo(void)
1055 str += "<big>Symbol: <b>";
1056 str += print_filter(sym->name);
1057 str += "</b></big><br><br>value: ";
1058 str += print_filter(sym_get_string_value(sym));
1059 str += "<br>visibility: ";
1060 str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n";
1062 str += debug_info(sym);
1067 void ConfigInfoView::menuInfo(void)
1070 QString head, debug, help;
1074 if (_menu->prompt) {
1076 head += print_filter(_menu->prompt->text);
1077 head += "</b></big>";
1081 head += QString().sprintf("<a href=\"s%s\">", sym->name);
1082 head += print_filter(sym->name);
1087 } else if (sym->name) {
1090 head += QString().sprintf("<a href=\"s%s\">", sym->name);
1091 head += print_filter(sym->name);
1094 head += "</b></big>";
1099 debug = debug_info(sym);
1101 struct gstr help_gstr = str_new();
1102 menu_get_ext_help(_menu, &help_gstr);
1103 help = print_filter(str_get(&help_gstr));
1104 str_free(&help_gstr);
1105 } else if (_menu->prompt) {
1107 head += print_filter(_menu->prompt->text);
1108 head += "</b></big><br><br>";
1110 if (_menu->prompt->visible.expr) {
1111 debug += " dep: ";
1112 expr_print(_menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
1113 debug += "<br><br>";
1118 debug += QString().sprintf("defined at %s:%d<br><br>", _menu->file->name, _menu->lineno);
1120 setText(head + debug + help);
1123 QString ConfigInfoView::debug_info(struct symbol *sym)
1128 debug += print_filter(sym_type_name(sym->type));
1129 if (sym_is_choice(sym))
1130 debug += " (choice)";
1132 if (sym->rev_dep.expr) {
1133 debug += "reverse dep: ";
1134 expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
1137 for (struct property *prop = sym->prop; prop; prop = prop->next) {
1138 switch (prop->type) {
1141 debug += QString().sprintf("prompt: <a href=\"m%s\">", sym->name);
1142 debug += print_filter(prop->text);
1143 debug += "</a><br>";
1151 debug += prop_get_type_name(prop->type);
1153 expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1157 if (sym_is_choice(sym)) {
1158 debug += "choice: ";
1159 expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1164 debug += "unknown property: ";
1165 debug += prop_get_type_name(prop->type);
1168 if (prop->visible.expr) {
1169 debug += " dep: ";
1170 expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
1179 QString ConfigInfoView::print_filter(const QString &str)
1181 QRegExp re("[<>&\"\\n]");
1183 for (int i = 0; (i = res.indexOf(re, i)) >= 0;) {
1184 switch (res[i].toLatin1()) {
1186 res.replace(i, 1, "<");
1190 res.replace(i, 1, ">");
1194 res.replace(i, 1, "&");
1198 res.replace(i, 1, """);
1202 res.replace(i, 1, "<br>");
1210 void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str)
1212 QString* text = reinterpret_cast<QString*>(data);
1213 QString str2 = print_filter(str);
1215 if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
1216 *text += QString().sprintf("<a href=\"s%s\">", sym->name);
1223 void ConfigInfoView::clicked(const QUrl &url)
1225 QByteArray str = url.toEncoded();
1226 const std::size_t count = str.size();
1227 char *data = new char[count + 1];
1228 struct symbol **result;
1229 struct menu *m = NULL;
1232 qInfo() << "Clicked link is empty";
1237 memcpy(data, str.constData(), count);
1240 /* Seek for exact match */
1243 result = sym_re_search(data);
1245 qInfo() << "Clicked symbol is invalid:" << data;
1252 /* Seek for the menu which holds the symbol */
1253 for (struct property *prop = sym->prop; prop; prop = prop->next) {
1254 if (prop->type != P_PROMPT && prop->type != P_MENU)
1261 /* Symbol is not visible as a menu */
1263 emit showDebugChanged(true);
1265 emit menuSelected(m);
1272 QMenu* ConfigInfoView::createStandardContextMenu(const QPoint & pos)
1274 QMenu* popup = Parent::createStandardContextMenu(pos);
1275 QAction* action = new QAction("Show Debug Info", popup);
1277 action->setCheckable(true);
1278 connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
1279 connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
1280 action->setChecked(showDebug());
1281 popup->addSeparator();
1282 popup->addAction(action);
1286 void ConfigInfoView::contextMenuEvent(QContextMenuEvent *e)
1288 Parent::contextMenuEvent(e);
1291 ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *name)
1292 : Parent(parent), result(NULL)
1294 setObjectName(name);
1295 setWindowTitle("Search Config");
1297 QVBoxLayout* layout1 = new QVBoxLayout(this);
1298 layout1->setContentsMargins(11, 11, 11, 11);
1299 layout1->setSpacing(6);
1300 QHBoxLayout* layout2 = new QHBoxLayout(0);
1301 layout2->setContentsMargins(0, 0, 0, 0);
1302 layout2->setSpacing(6);
1303 layout2->addWidget(new QLabel("Find:", this));
1304 editField = new QLineEdit(this);
1305 connect(editField, SIGNAL(returnPressed()), SLOT(search()));
1306 layout2->addWidget(editField);
1307 searchButton = new QPushButton("Search", this);
1308 searchButton->setAutoDefault(false);
1309 connect(searchButton, SIGNAL(clicked()), SLOT(search()));
1310 layout2->addWidget(searchButton);
1311 layout1->addLayout(layout2);
1313 split = new QSplitter(this);
1314 split->setOrientation(Qt::Vertical);
1315 list = new ConfigView(split, name);
1316 list->list->mode = listMode;
1317 info = new ConfigInfoView(split, name);
1318 connect(list->list, SIGNAL(menuChanged(struct menu *)),
1319 info, SLOT(setInfo(struct menu *)));
1320 connect(list->list, SIGNAL(menuChanged(struct menu *)),
1321 parent, SLOT(setMenuLink(struct menu *)));
1323 layout1->addWidget(split);
1330 configSettings->beginGroup(name);
1331 width = configSettings->value("/window width", parent->width() / 2).toInt();
1332 height = configSettings->value("/window height", parent->height() / 2).toInt();
1333 resize(width, height);
1334 x = configSettings->value("/window x");
1335 y = configSettings->value("/window y");
1336 if ((x.isValid())&&(y.isValid()))
1337 move(x.toInt(), y.toInt());
1338 QList<int> sizes = configSettings->readSizes("/split", &ok);
1340 split->setSizes(sizes);
1341 configSettings->endGroup();
1342 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
1346 void ConfigSearchWindow::saveSettings(void)
1348 if (!objectName().isEmpty()) {
1349 configSettings->beginGroup(objectName());
1350 configSettings->setValue("/window x", pos().x());
1351 configSettings->setValue("/window y", pos().y());
1352 configSettings->setValue("/window width", size().width());
1353 configSettings->setValue("/window height", size().height());
1354 configSettings->writeSizes("/split", split->sizes());
1355 configSettings->endGroup();
1359 void ConfigSearchWindow::search(void)
1362 struct property *prop;
1363 ConfigItem *lastItem = NULL;
1366 list->list->clear();
1369 result = sym_re_search(editField->text().toLatin1());
1372 for (p = result; *p; p++) {
1373 for_all_prompts((*p), prop)
1374 lastItem = new ConfigItem(list->list, lastItem, prop->menu,
1375 menu_is_visible(prop->menu));
1380 * Construct the complete config widget
1382 ConfigMainWindow::ConfigMainWindow(void)
1391 QDesktopWidget *d = configApp->desktop();
1392 snprintf(title, sizeof(title), "%s%s",
1393 rootmenu.prompt->text,
1396 setWindowTitle(title);
1398 width = configSettings->value("/window width", d->width() - 64).toInt();
1399 height = configSettings->value("/window height", d->height() - 64).toInt();
1400 resize(width, height);
1401 x = configSettings->value("/window x");
1402 y = configSettings->value("/window y");
1403 if ((x.isValid())&&(y.isValid()))
1404 move(x.toInt(), y.toInt());
1406 QWidget *widget = new QWidget(this);
1407 QVBoxLayout *layout = new QVBoxLayout(widget);
1408 setCentralWidget(widget);
1410 split1 = new QSplitter(widget);
1411 split1->setOrientation(Qt::Horizontal);
1412 split1->setChildrenCollapsible(false);
1414 menuView = new ConfigView(widget, "menu");
1415 menuList = menuView->list;
1417 split2 = new QSplitter(widget);
1418 split2->setChildrenCollapsible(false);
1419 split2->setOrientation(Qt::Vertical);
1421 // create config tree
1422 configView = new ConfigView(widget, "config");
1423 configList = configView->list;
1425 helpText = new ConfigInfoView(widget, "help");
1427 layout->addWidget(split2);
1428 split2->addWidget(split1);
1429 split1->addWidget(configView);
1430 split1->addWidget(menuView);
1431 split2->addWidget(helpText);
1433 setTabOrder(configList, helpText);
1434 configList->setFocus();
1437 toolBar = new QToolBar("Tools", this);
1438 addToolBar(toolBar);
1440 backAction = new QAction(QPixmap(xpm_back), "Back", this);
1441 connect(backAction, SIGNAL(triggered(bool)), SLOT(goBack()));
1443 QAction *quitAction = new QAction("&Quit", this);
1444 quitAction->setShortcut(Qt::CTRL + Qt::Key_Q);
1445 connect(quitAction, SIGNAL(triggered(bool)), SLOT(close()));
1447 QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this);
1448 loadAction->setShortcut(Qt::CTRL + Qt::Key_L);
1449 connect(loadAction, SIGNAL(triggered(bool)), SLOT(loadConfig()));
1451 saveAction = new QAction(QPixmap(xpm_save), "&Save", this);
1452 saveAction->setShortcut(Qt::CTRL + Qt::Key_S);
1453 connect(saveAction, SIGNAL(triggered(bool)), SLOT(saveConfig()));
1455 conf_set_changed_callback(conf_changed);
1457 // Set saveAction's initial state
1459 configname = xstrdup(conf_get_configname());
1461 QAction *saveAsAction = new QAction("Save &As...", this);
1462 connect(saveAsAction, SIGNAL(triggered(bool)), SLOT(saveConfigAs()));
1463 QAction *searchAction = new QAction("&Find", this);
1464 searchAction->setShortcut(Qt::CTRL + Qt::Key_F);
1465 connect(searchAction, SIGNAL(triggered(bool)), SLOT(searchConfig()));
1466 singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this);
1467 singleViewAction->setCheckable(true);
1468 connect(singleViewAction, SIGNAL(triggered(bool)), SLOT(showSingleView()));
1469 splitViewAction = new QAction(QPixmap(xpm_split_view), "Split View", this);
1470 splitViewAction->setCheckable(true);
1471 connect(splitViewAction, SIGNAL(triggered(bool)), SLOT(showSplitView()));
1472 fullViewAction = new QAction(QPixmap(xpm_tree_view), "Full View", this);
1473 fullViewAction->setCheckable(true);
1474 connect(fullViewAction, SIGNAL(triggered(bool)), SLOT(showFullView()));
1476 QAction *showNameAction = new QAction("Show Name", this);
1477 showNameAction->setCheckable(true);
1478 connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
1479 showNameAction->setChecked(configView->showName());
1480 QAction *showRangeAction = new QAction("Show Range", this);
1481 showRangeAction->setCheckable(true);
1482 connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
1483 QAction *showDataAction = new QAction("Show Data", this);
1484 showDataAction->setCheckable(true);
1485 connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
1487 QActionGroup *optGroup = new QActionGroup(this);
1488 optGroup->setExclusive(true);
1489 connect(optGroup, SIGNAL(triggered(QAction*)), configView,
1490 SLOT(setOptionMode(QAction *)));
1491 connect(optGroup, SIGNAL(triggered(QAction *)), menuView,
1492 SLOT(setOptionMode(QAction *)));
1494 configView->showNormalAction = new QAction("Show Normal Options", optGroup);
1495 configView->showAllAction = new QAction("Show All Options", optGroup);
1496 configView->showPromptAction = new QAction("Show Prompt Options", optGroup);
1497 configView->showNormalAction->setCheckable(true);
1498 configView->showAllAction->setCheckable(true);
1499 configView->showPromptAction->setCheckable(true);
1501 QAction *showDebugAction = new QAction("Show Debug Info", this);
1502 showDebugAction->setCheckable(true);
1503 connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
1504 showDebugAction->setChecked(helpText->showDebug());
1506 QAction *showIntroAction = new QAction("Introduction", this);
1507 connect(showIntroAction, SIGNAL(triggered(bool)), SLOT(showIntro()));
1508 QAction *showAboutAction = new QAction("About", this);
1509 connect(showAboutAction, SIGNAL(triggered(bool)), SLOT(showAbout()));
1512 toolBar->addAction(backAction);
1513 toolBar->addSeparator();
1514 toolBar->addAction(loadAction);
1515 toolBar->addAction(saveAction);
1516 toolBar->addSeparator();
1517 toolBar->addAction(singleViewAction);
1518 toolBar->addAction(splitViewAction);
1519 toolBar->addAction(fullViewAction);
1521 // create config menu
1522 QMenu* config = menu->addMenu("&File");
1523 config->addAction(loadAction);
1524 config->addAction(saveAction);
1525 config->addAction(saveAsAction);
1526 config->addSeparator();
1527 config->addAction(quitAction);
1530 QMenu* editMenu = menu->addMenu("&Edit");
1531 editMenu->addAction(searchAction);
1533 // create options menu
1534 QMenu* optionMenu = menu->addMenu("&Option");
1535 optionMenu->addAction(showNameAction);
1536 optionMenu->addAction(showRangeAction);
1537 optionMenu->addAction(showDataAction);
1538 optionMenu->addSeparator();
1539 optionMenu->addActions(optGroup->actions());
1540 optionMenu->addSeparator();
1541 optionMenu->addAction(showDebugAction);
1544 QMenu* helpMenu = menu->addMenu("&Help");
1545 helpMenu->addAction(showIntroAction);
1546 helpMenu->addAction(showAboutAction);
1548 connect (helpText, SIGNAL (anchorClicked (const QUrl &)),
1549 helpText, SLOT (clicked (const QUrl &)) );
1551 connect(configList, SIGNAL(menuChanged(struct menu *)),
1552 helpText, SLOT(setInfo(struct menu *)));
1553 connect(configList, SIGNAL(menuSelected(struct menu *)),
1554 SLOT(changeMenu(struct menu *)));
1555 connect(configList, SIGNAL(itemSelected(struct menu *)),
1556 SLOT(changeItens(struct menu *)));
1557 connect(configList, SIGNAL(parentSelected()),
1559 connect(menuList, SIGNAL(menuChanged(struct menu *)),
1560 helpText, SLOT(setInfo(struct menu *)));
1561 connect(menuList, SIGNAL(menuSelected(struct menu *)),
1562 SLOT(changeMenu(struct menu *)));
1564 connect(configList, SIGNAL(gotFocus(struct menu *)),
1565 helpText, SLOT(setInfo(struct menu *)));
1566 connect(menuList, SIGNAL(gotFocus(struct menu *)),
1567 helpText, SLOT(setInfo(struct menu *)));
1568 connect(menuList, SIGNAL(gotFocus(struct menu *)),
1569 SLOT(listFocusChanged(void)));
1570 connect(helpText, SIGNAL(menuSelected(struct menu *)),
1571 SLOT(setMenuLink(struct menu *)));
1573 QString listMode = configSettings->value("/listMode", "symbol").toString();
1574 if (listMode == "single")
1576 else if (listMode == "full")
1578 else /*if (listMode == "split")*/
1581 // UI setup done, restore splitter positions
1582 QList<int> sizes = configSettings->readSizes("/split1", &ok);
1584 split1->setSizes(sizes);
1586 sizes = configSettings->readSizes("/split2", &ok);
1588 split2->setSizes(sizes);
1591 void ConfigMainWindow::loadConfig(void)
1597 str = QFileDialog::getOpenFileName(this, "", configname);
1601 ba = str.toLocal8Bit();
1604 if (conf_read(name))
1605 QMessageBox::information(this, "qconf", "Unable to load configuration!");
1608 configname = xstrdup(name);
1610 ConfigView::updateListAll();
1613 bool ConfigMainWindow::saveConfig(void)
1615 if (conf_write(configname)) {
1616 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1619 conf_write_autoconf(0);
1624 void ConfigMainWindow::saveConfigAs(void)
1630 str = QFileDialog::getSaveFileName(this, "", configname);
1634 ba = str.toLocal8Bit();
1637 if (conf_write(name)) {
1638 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1640 conf_write_autoconf(0);
1643 configname = xstrdup(name);
1646 void ConfigMainWindow::searchConfig(void)
1649 searchWindow = new ConfigSearchWindow(this, "search");
1650 searchWindow->show();
1653 void ConfigMainWindow::changeItens(struct menu *menu)
1655 configList->setRootMenu(menu);
1658 void ConfigMainWindow::changeMenu(struct menu *menu)
1660 menuList->setRootMenu(menu);
1663 void ConfigMainWindow::setMenuLink(struct menu *menu)
1665 struct menu *parent;
1666 ConfigList* list = NULL;
1669 if (configList->menuSkip(menu))
1672 switch (configList->mode) {
1675 parent = menu_get_parent_menu(menu);
1678 list->setRootMenu(parent);
1681 if (menu->flags & MENU_ROOT) {
1682 menuList->setRootMenu(menu);
1683 configList->clearSelection();
1686 parent = menu_get_parent_menu(menu->parent);
1690 /* Select the config view */
1691 item = configList->findConfigItem(parent);
1693 configList->setSelected(item, true);
1694 configList->scrollToItem(item);
1697 menuList->setRootMenu(parent);
1698 menuList->clearSelection();
1710 item = list->findConfigItem(menu);
1712 list->setSelected(item, true);
1713 list->scrollToItem(item);
1715 helpText->setInfo(menu);
1720 void ConfigMainWindow::listFocusChanged(void)
1722 if (menuList->mode == menuMode)
1723 configList->clearSelection();
1726 void ConfigMainWindow::goBack(void)
1728 if (configList->rootEntry == &rootmenu)
1731 configList->setParentMenu();
1734 void ConfigMainWindow::showSingleView(void)
1736 singleViewAction->setEnabled(false);
1737 singleViewAction->setChecked(true);
1738 splitViewAction->setEnabled(true);
1739 splitViewAction->setChecked(false);
1740 fullViewAction->setEnabled(true);
1741 fullViewAction->setChecked(false);
1743 backAction->setEnabled(true);
1746 menuList->setRootMenu(0);
1747 configList->mode = singleMode;
1748 if (configList->rootEntry == &rootmenu)
1749 configList->updateListAll();
1751 configList->setRootMenu(&rootmenu);
1752 configList->setFocus();
1755 void ConfigMainWindow::showSplitView(void)
1757 singleViewAction->setEnabled(true);
1758 singleViewAction->setChecked(false);
1759 splitViewAction->setEnabled(false);
1760 splitViewAction->setChecked(true);
1761 fullViewAction->setEnabled(true);
1762 fullViewAction->setChecked(false);
1764 backAction->setEnabled(false);
1766 configList->mode = menuMode;
1767 if (configList->rootEntry == &rootmenu)
1768 configList->updateListAll();
1770 configList->setRootMenu(&rootmenu);
1771 configList->setAllOpen(true);
1772 configApp->processEvents();
1773 menuList->mode = symbolMode;
1774 menuList->setRootMenu(&rootmenu);
1775 menuList->setAllOpen(true);
1777 menuList->setFocus();
1780 void ConfigMainWindow::showFullView(void)
1782 singleViewAction->setEnabled(true);
1783 singleViewAction->setChecked(false);
1784 splitViewAction->setEnabled(true);
1785 splitViewAction->setChecked(false);
1786 fullViewAction->setEnabled(false);
1787 fullViewAction->setChecked(true);
1789 backAction->setEnabled(false);
1792 menuList->setRootMenu(0);
1793 configList->mode = fullMode;
1794 if (configList->rootEntry == &rootmenu)
1795 configList->updateListAll();
1797 configList->setRootMenu(&rootmenu);
1798 configList->setFocus();
1802 * ask for saving configuration before quitting
1804 void ConfigMainWindow::closeEvent(QCloseEvent* e)
1806 if (!conf_get_changed()) {
1810 QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning,
1811 QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
1812 mb.setButtonText(QMessageBox::Yes, "&Save Changes");
1813 mb.setButtonText(QMessageBox::No, "&Discard Changes");
1814 mb.setButtonText(QMessageBox::Cancel, "Cancel Exit");
1815 switch (mb.exec()) {
1816 case QMessageBox::Yes:
1822 case QMessageBox::No:
1825 case QMessageBox::Cancel:
1831 void ConfigMainWindow::showIntro(void)
1833 static const QString str = "Welcome to the qconf graphical configuration tool.\n\n"
1834 "For each option, a blank box indicates the feature is disabled, a check\n"
1835 "indicates it is enabled, and a dot indicates that it is to be compiled\n"
1836 "as a module. Clicking on the box will cycle through the three states.\n\n"
1837 "If you do not see an option (e.g., a device driver) that you believe\n"
1838 "should be present, try turning on Show All Options under the Options menu.\n"
1839 "Although there is no cross reference yet to help you figure out what other\n"
1840 "options must be enabled to support the option you are interested in, you can\n"
1841 "still view the help of a grayed-out option.\n\n"
1842 "Toggling Show Debug Info under the Options menu will show the dependencies,\n"
1843 "which you can then match by examining other options.\n\n";
1845 QMessageBox::information(this, "qconf", str);
1848 void ConfigMainWindow::showAbout(void)
1850 static const QString str = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n"
1851 "Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>.\n\n"
1852 "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n";
1854 QMessageBox::information(this, "qconf", str);
1857 void ConfigMainWindow::saveSettings(void)
1859 configSettings->setValue("/window x", pos().x());
1860 configSettings->setValue("/window y", pos().y());
1861 configSettings->setValue("/window width", size().width());
1862 configSettings->setValue("/window height", size().height());
1865 switch(configList->mode) {
1881 configSettings->setValue("/listMode", entry);
1883 configSettings->writeSizes("/split1", split1->sizes());
1884 configSettings->writeSizes("/split2", split2->sizes());
1887 void ConfigMainWindow::conf_changed(void)
1890 saveAction->setEnabled(conf_get_changed());
1893 void fixup_rootmenu(struct menu *menu)
1896 static int menu_cnt = 0;
1898 menu->flags |= MENU_ROOT;
1899 for (child = menu->list; child; child = child->next) {
1900 if (child->prompt && child->prompt->type == P_MENU) {
1902 fixup_rootmenu(child);
1904 } else if (!menu_cnt)
1905 fixup_rootmenu(child);
1909 static const char *progname;
1911 static void usage(void)
1913 printf("%s [-s] <config>\n", progname);
1917 int main(int ac, char** av)
1919 ConfigMainWindow* v;
1923 configApp = new QApplication(ac, av);
1924 if (ac > 1 && av[1][0] == '-') {
1927 conf_set_message_callback(NULL);
1940 fixup_rootmenu(&rootmenu);
1942 //zconfdump(stdout);
1944 configSettings = new ConfigSettings();
1945 configSettings->beginGroup("/kconfig/qconf");
1946 v = new ConfigMainWindow();
1948 //zconfdump(stdout);
1949 configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
1950 configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1954 configSettings->endGroup();
1955 delete configSettings;