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)
1292 : Parent(parent), result(NULL)
1294 setObjectName("search");
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, "search");
1316 list->list->mode = listMode;
1317 info = new ConfigInfoView(split, "search");
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);
1329 configSettings->beginGroup("search");
1330 width = configSettings->value("/window width", parent->width() / 2).toInt();
1331 height = configSettings->value("/window height", parent->height() / 2).toInt();
1332 resize(width, height);
1333 x = configSettings->value("/window x");
1334 y = configSettings->value("/window y");
1335 if (x.isValid() && y.isValid())
1336 move(x.toInt(), y.toInt());
1337 QList<int> sizes = configSettings->readSizes("/split", &ok);
1339 split->setSizes(sizes);
1340 configSettings->endGroup();
1341 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
1344 void ConfigSearchWindow::saveSettings(void)
1346 if (!objectName().isEmpty()) {
1347 configSettings->beginGroup(objectName());
1348 configSettings->setValue("/window x", pos().x());
1349 configSettings->setValue("/window y", pos().y());
1350 configSettings->setValue("/window width", size().width());
1351 configSettings->setValue("/window height", size().height());
1352 configSettings->writeSizes("/split", split->sizes());
1353 configSettings->endGroup();
1357 void ConfigSearchWindow::search(void)
1360 struct property *prop;
1361 ConfigItem *lastItem = NULL;
1364 list->list->clear();
1367 result = sym_re_search(editField->text().toLatin1());
1370 for (p = result; *p; p++) {
1371 for_all_prompts((*p), prop)
1372 lastItem = new ConfigItem(list->list, lastItem, prop->menu,
1373 menu_is_visible(prop->menu));
1378 * Construct the complete config widget
1380 ConfigMainWindow::ConfigMainWindow(void)
1388 QDesktopWidget *d = configApp->desktop();
1389 snprintf(title, sizeof(title), "%s%s",
1390 rootmenu.prompt->text,
1393 setWindowTitle(title);
1395 width = configSettings->value("/window width", d->width() - 64).toInt();
1396 height = configSettings->value("/window height", d->height() - 64).toInt();
1397 resize(width, height);
1398 x = configSettings->value("/window x");
1399 y = configSettings->value("/window y");
1400 if ((x.isValid())&&(y.isValid()))
1401 move(x.toInt(), y.toInt());
1403 QWidget *widget = new QWidget(this);
1404 QVBoxLayout *layout = new QVBoxLayout(widget);
1405 setCentralWidget(widget);
1407 split1 = new QSplitter(widget);
1408 split1->setOrientation(Qt::Horizontal);
1409 split1->setChildrenCollapsible(false);
1411 menuView = new ConfigView(widget, "menu");
1412 menuList = menuView->list;
1414 split2 = new QSplitter(widget);
1415 split2->setChildrenCollapsible(false);
1416 split2->setOrientation(Qt::Vertical);
1418 // create config tree
1419 configView = new ConfigView(widget, "config");
1420 configList = configView->list;
1422 helpText = new ConfigInfoView(widget, "help");
1424 layout->addWidget(split2);
1425 split2->addWidget(split1);
1426 split1->addWidget(configView);
1427 split1->addWidget(menuView);
1428 split2->addWidget(helpText);
1430 setTabOrder(configList, helpText);
1431 configList->setFocus();
1433 backAction = new QAction(QPixmap(xpm_back), "Back", this);
1434 connect(backAction, SIGNAL(triggered(bool)), SLOT(goBack()));
1436 QAction *quitAction = new QAction("&Quit", this);
1437 quitAction->setShortcut(Qt::CTRL + Qt::Key_Q);
1438 connect(quitAction, SIGNAL(triggered(bool)), SLOT(close()));
1440 QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this);
1441 loadAction->setShortcut(Qt::CTRL + Qt::Key_L);
1442 connect(loadAction, SIGNAL(triggered(bool)), SLOT(loadConfig()));
1444 saveAction = new QAction(QPixmap(xpm_save), "&Save", this);
1445 saveAction->setShortcut(Qt::CTRL + Qt::Key_S);
1446 connect(saveAction, SIGNAL(triggered(bool)), SLOT(saveConfig()));
1448 conf_set_changed_callback(conf_changed);
1450 // Set saveAction's initial state
1452 configname = xstrdup(conf_get_configname());
1454 QAction *saveAsAction = new QAction("Save &As...", this);
1455 connect(saveAsAction, SIGNAL(triggered(bool)), SLOT(saveConfigAs()));
1456 QAction *searchAction = new QAction("&Find", this);
1457 searchAction->setShortcut(Qt::CTRL + Qt::Key_F);
1458 connect(searchAction, SIGNAL(triggered(bool)), SLOT(searchConfig()));
1459 singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this);
1460 singleViewAction->setCheckable(true);
1461 connect(singleViewAction, SIGNAL(triggered(bool)), SLOT(showSingleView()));
1462 splitViewAction = new QAction(QPixmap(xpm_split_view), "Split View", this);
1463 splitViewAction->setCheckable(true);
1464 connect(splitViewAction, SIGNAL(triggered(bool)), SLOT(showSplitView()));
1465 fullViewAction = new QAction(QPixmap(xpm_tree_view), "Full View", this);
1466 fullViewAction->setCheckable(true);
1467 connect(fullViewAction, SIGNAL(triggered(bool)), SLOT(showFullView()));
1469 QAction *showNameAction = new QAction("Show Name", this);
1470 showNameAction->setCheckable(true);
1471 connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
1472 showNameAction->setChecked(configView->showName());
1473 QAction *showRangeAction = new QAction("Show Range", this);
1474 showRangeAction->setCheckable(true);
1475 connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
1476 QAction *showDataAction = new QAction("Show Data", this);
1477 showDataAction->setCheckable(true);
1478 connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
1480 QActionGroup *optGroup = new QActionGroup(this);
1481 optGroup->setExclusive(true);
1482 connect(optGroup, SIGNAL(triggered(QAction*)), configView,
1483 SLOT(setOptionMode(QAction *)));
1484 connect(optGroup, SIGNAL(triggered(QAction *)), menuView,
1485 SLOT(setOptionMode(QAction *)));
1487 configView->showNormalAction = new QAction("Show Normal Options", optGroup);
1488 configView->showAllAction = new QAction("Show All Options", optGroup);
1489 configView->showPromptAction = new QAction("Show Prompt Options", optGroup);
1490 configView->showNormalAction->setCheckable(true);
1491 configView->showAllAction->setCheckable(true);
1492 configView->showPromptAction->setCheckable(true);
1494 QAction *showDebugAction = new QAction("Show Debug Info", this);
1495 showDebugAction->setCheckable(true);
1496 connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
1497 showDebugAction->setChecked(helpText->showDebug());
1499 QAction *showIntroAction = new QAction("Introduction", this);
1500 connect(showIntroAction, SIGNAL(triggered(bool)), SLOT(showIntro()));
1501 QAction *showAboutAction = new QAction("About", this);
1502 connect(showAboutAction, SIGNAL(triggered(bool)), SLOT(showAbout()));
1505 QToolBar *toolBar = addToolBar("Tools");
1506 toolBar->addAction(backAction);
1507 toolBar->addSeparator();
1508 toolBar->addAction(loadAction);
1509 toolBar->addAction(saveAction);
1510 toolBar->addSeparator();
1511 toolBar->addAction(singleViewAction);
1512 toolBar->addAction(splitViewAction);
1513 toolBar->addAction(fullViewAction);
1516 QMenu *menu = menuBar()->addMenu("&File");
1517 menu->addAction(loadAction);
1518 menu->addAction(saveAction);
1519 menu->addAction(saveAsAction);
1520 menu->addSeparator();
1521 menu->addAction(quitAction);
1524 menu = menuBar()->addMenu("&Edit");
1525 menu->addAction(searchAction);
1527 // create options menu
1528 menu = menuBar()->addMenu("&Option");
1529 menu->addAction(showNameAction);
1530 menu->addAction(showRangeAction);
1531 menu->addAction(showDataAction);
1532 menu->addSeparator();
1533 menu->addActions(optGroup->actions());
1534 menu->addSeparator();
1535 menu->addAction(showDebugAction);
1538 menu = menuBar()->addMenu("&Help");
1539 menu->addAction(showIntroAction);
1540 menu->addAction(showAboutAction);
1542 connect (helpText, SIGNAL (anchorClicked (const QUrl &)),
1543 helpText, SLOT (clicked (const QUrl &)) );
1545 connect(configList, SIGNAL(menuChanged(struct menu *)),
1546 helpText, SLOT(setInfo(struct menu *)));
1547 connect(configList, SIGNAL(menuSelected(struct menu *)),
1548 SLOT(changeMenu(struct menu *)));
1549 connect(configList, SIGNAL(itemSelected(struct menu *)),
1550 SLOT(changeItens(struct menu *)));
1551 connect(configList, SIGNAL(parentSelected()),
1553 connect(menuList, SIGNAL(menuChanged(struct menu *)),
1554 helpText, SLOT(setInfo(struct menu *)));
1555 connect(menuList, SIGNAL(menuSelected(struct menu *)),
1556 SLOT(changeMenu(struct menu *)));
1558 connect(configList, SIGNAL(gotFocus(struct menu *)),
1559 helpText, SLOT(setInfo(struct menu *)));
1560 connect(menuList, SIGNAL(gotFocus(struct menu *)),
1561 helpText, SLOT(setInfo(struct menu *)));
1562 connect(menuList, SIGNAL(gotFocus(struct menu *)),
1563 SLOT(listFocusChanged(void)));
1564 connect(helpText, SIGNAL(menuSelected(struct menu *)),
1565 SLOT(setMenuLink(struct menu *)));
1567 QString listMode = configSettings->value("/listMode", "symbol").toString();
1568 if (listMode == "single")
1570 else if (listMode == "full")
1572 else /*if (listMode == "split")*/
1575 // UI setup done, restore splitter positions
1576 QList<int> sizes = configSettings->readSizes("/split1", &ok);
1578 split1->setSizes(sizes);
1580 sizes = configSettings->readSizes("/split2", &ok);
1582 split2->setSizes(sizes);
1585 void ConfigMainWindow::loadConfig(void)
1591 str = QFileDialog::getOpenFileName(this, "", configname);
1595 ba = str.toLocal8Bit();
1598 if (conf_read(name))
1599 QMessageBox::information(this, "qconf", "Unable to load configuration!");
1602 configname = xstrdup(name);
1604 ConfigView::updateListAll();
1607 bool ConfigMainWindow::saveConfig(void)
1609 if (conf_write(configname)) {
1610 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1613 conf_write_autoconf(0);
1618 void ConfigMainWindow::saveConfigAs(void)
1624 str = QFileDialog::getSaveFileName(this, "", configname);
1628 ba = str.toLocal8Bit();
1631 if (conf_write(name)) {
1632 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1634 conf_write_autoconf(0);
1637 configname = xstrdup(name);
1640 void ConfigMainWindow::searchConfig(void)
1643 searchWindow = new ConfigSearchWindow(this);
1644 searchWindow->show();
1647 void ConfigMainWindow::changeItens(struct menu *menu)
1649 configList->setRootMenu(menu);
1652 void ConfigMainWindow::changeMenu(struct menu *menu)
1654 menuList->setRootMenu(menu);
1657 void ConfigMainWindow::setMenuLink(struct menu *menu)
1659 struct menu *parent;
1660 ConfigList* list = NULL;
1663 if (configList->menuSkip(menu))
1666 switch (configList->mode) {
1669 parent = menu_get_parent_menu(menu);
1672 list->setRootMenu(parent);
1675 if (menu->flags & MENU_ROOT) {
1676 menuList->setRootMenu(menu);
1677 configList->clearSelection();
1680 parent = menu_get_parent_menu(menu->parent);
1684 /* Select the config view */
1685 item = configList->findConfigItem(parent);
1687 configList->setSelected(item, true);
1688 configList->scrollToItem(item);
1691 menuList->setRootMenu(parent);
1692 menuList->clearSelection();
1704 item = list->findConfigItem(menu);
1706 list->setSelected(item, true);
1707 list->scrollToItem(item);
1709 helpText->setInfo(menu);
1714 void ConfigMainWindow::listFocusChanged(void)
1716 if (menuList->mode == menuMode)
1717 configList->clearSelection();
1720 void ConfigMainWindow::goBack(void)
1722 if (configList->rootEntry == &rootmenu)
1725 configList->setParentMenu();
1728 void ConfigMainWindow::showSingleView(void)
1730 singleViewAction->setEnabled(false);
1731 singleViewAction->setChecked(true);
1732 splitViewAction->setEnabled(true);
1733 splitViewAction->setChecked(false);
1734 fullViewAction->setEnabled(true);
1735 fullViewAction->setChecked(false);
1737 backAction->setEnabled(true);
1740 menuList->setRootMenu(0);
1741 configList->mode = singleMode;
1742 if (configList->rootEntry == &rootmenu)
1743 configList->updateListAll();
1745 configList->setRootMenu(&rootmenu);
1746 configList->setFocus();
1749 void ConfigMainWindow::showSplitView(void)
1751 singleViewAction->setEnabled(true);
1752 singleViewAction->setChecked(false);
1753 splitViewAction->setEnabled(false);
1754 splitViewAction->setChecked(true);
1755 fullViewAction->setEnabled(true);
1756 fullViewAction->setChecked(false);
1758 backAction->setEnabled(false);
1760 configList->mode = menuMode;
1761 if (configList->rootEntry == &rootmenu)
1762 configList->updateListAll();
1764 configList->setRootMenu(&rootmenu);
1765 configList->setAllOpen(true);
1766 configApp->processEvents();
1767 menuList->mode = symbolMode;
1768 menuList->setRootMenu(&rootmenu);
1769 menuList->setAllOpen(true);
1771 menuList->setFocus();
1774 void ConfigMainWindow::showFullView(void)
1776 singleViewAction->setEnabled(true);
1777 singleViewAction->setChecked(false);
1778 splitViewAction->setEnabled(true);
1779 splitViewAction->setChecked(false);
1780 fullViewAction->setEnabled(false);
1781 fullViewAction->setChecked(true);
1783 backAction->setEnabled(false);
1786 menuList->setRootMenu(0);
1787 configList->mode = fullMode;
1788 if (configList->rootEntry == &rootmenu)
1789 configList->updateListAll();
1791 configList->setRootMenu(&rootmenu);
1792 configList->setFocus();
1796 * ask for saving configuration before quitting
1798 void ConfigMainWindow::closeEvent(QCloseEvent* e)
1800 if (!conf_get_changed()) {
1804 QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning,
1805 QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
1806 mb.setButtonText(QMessageBox::Yes, "&Save Changes");
1807 mb.setButtonText(QMessageBox::No, "&Discard Changes");
1808 mb.setButtonText(QMessageBox::Cancel, "Cancel Exit");
1809 switch (mb.exec()) {
1810 case QMessageBox::Yes:
1816 case QMessageBox::No:
1819 case QMessageBox::Cancel:
1825 void ConfigMainWindow::showIntro(void)
1827 static const QString str = "Welcome to the qconf graphical configuration tool.\n\n"
1828 "For each option, a blank box indicates the feature is disabled, a check\n"
1829 "indicates it is enabled, and a dot indicates that it is to be compiled\n"
1830 "as a module. Clicking on the box will cycle through the three states.\n\n"
1831 "If you do not see an option (e.g., a device driver) that you believe\n"
1832 "should be present, try turning on Show All Options under the Options menu.\n"
1833 "Although there is no cross reference yet to help you figure out what other\n"
1834 "options must be enabled to support the option you are interested in, you can\n"
1835 "still view the help of a grayed-out option.\n\n"
1836 "Toggling Show Debug Info under the Options menu will show the dependencies,\n"
1837 "which you can then match by examining other options.\n\n";
1839 QMessageBox::information(this, "qconf", str);
1842 void ConfigMainWindow::showAbout(void)
1844 static const QString str = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n"
1845 "Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>.\n\n"
1846 "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n";
1848 QMessageBox::information(this, "qconf", str);
1851 void ConfigMainWindow::saveSettings(void)
1853 configSettings->setValue("/window x", pos().x());
1854 configSettings->setValue("/window y", pos().y());
1855 configSettings->setValue("/window width", size().width());
1856 configSettings->setValue("/window height", size().height());
1859 switch(configList->mode) {
1875 configSettings->setValue("/listMode", entry);
1877 configSettings->writeSizes("/split1", split1->sizes());
1878 configSettings->writeSizes("/split2", split2->sizes());
1881 void ConfigMainWindow::conf_changed(void)
1884 saveAction->setEnabled(conf_get_changed());
1887 void fixup_rootmenu(struct menu *menu)
1890 static int menu_cnt = 0;
1892 menu->flags |= MENU_ROOT;
1893 for (child = menu->list; child; child = child->next) {
1894 if (child->prompt && child->prompt->type == P_MENU) {
1896 fixup_rootmenu(child);
1898 } else if (!menu_cnt)
1899 fixup_rootmenu(child);
1903 static const char *progname;
1905 static void usage(void)
1907 printf("%s [-s] <config>\n", progname);
1911 int main(int ac, char** av)
1913 ConfigMainWindow* v;
1917 configApp = new QApplication(ac, av);
1918 if (ac > 1 && av[1][0] == '-') {
1921 conf_set_message_callback(NULL);
1934 fixup_rootmenu(&rootmenu);
1936 //zconfdump(stdout);
1938 configSettings = new ConfigSettings();
1939 configSettings->beginGroup("/kconfig/qconf");
1940 v = new ConfigMainWindow();
1942 //zconfdump(stdout);
1943 configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
1944 configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1948 configSettings->endGroup();
1949 delete configSettings;