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)
1390 QDesktopWidget *d = configApp->desktop();
1391 snprintf(title, sizeof(title), "%s%s",
1392 rootmenu.prompt->text,
1395 setWindowTitle(title);
1397 width = configSettings->value("/window width", d->width() - 64).toInt();
1398 height = configSettings->value("/window height", d->height() - 64).toInt();
1399 resize(width, height);
1400 x = configSettings->value("/window x");
1401 y = configSettings->value("/window y");
1402 if ((x.isValid())&&(y.isValid()))
1403 move(x.toInt(), y.toInt());
1405 QWidget *widget = new QWidget(this);
1406 QVBoxLayout *layout = new QVBoxLayout(widget);
1407 setCentralWidget(widget);
1409 split1 = new QSplitter(widget);
1410 split1->setOrientation(Qt::Horizontal);
1411 split1->setChildrenCollapsible(false);
1413 menuView = new ConfigView(widget, "menu");
1414 menuList = menuView->list;
1416 split2 = new QSplitter(widget);
1417 split2->setChildrenCollapsible(false);
1418 split2->setOrientation(Qt::Vertical);
1420 // create config tree
1421 configView = new ConfigView(widget, "config");
1422 configList = configView->list;
1424 helpText = new ConfigInfoView(widget, "help");
1426 layout->addWidget(split2);
1427 split2->addWidget(split1);
1428 split1->addWidget(configView);
1429 split1->addWidget(menuView);
1430 split2->addWidget(helpText);
1432 setTabOrder(configList, helpText);
1433 configList->setFocus();
1435 toolBar = new QToolBar("Tools", this);
1436 addToolBar(toolBar);
1438 backAction = new QAction(QPixmap(xpm_back), "Back", this);
1439 connect(backAction, SIGNAL(triggered(bool)), SLOT(goBack()));
1441 QAction *quitAction = new QAction("&Quit", this);
1442 quitAction->setShortcut(Qt::CTRL + Qt::Key_Q);
1443 connect(quitAction, SIGNAL(triggered(bool)), SLOT(close()));
1445 QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this);
1446 loadAction->setShortcut(Qt::CTRL + Qt::Key_L);
1447 connect(loadAction, SIGNAL(triggered(bool)), SLOT(loadConfig()));
1449 saveAction = new QAction(QPixmap(xpm_save), "&Save", this);
1450 saveAction->setShortcut(Qt::CTRL + Qt::Key_S);
1451 connect(saveAction, SIGNAL(triggered(bool)), SLOT(saveConfig()));
1453 conf_set_changed_callback(conf_changed);
1455 // Set saveAction's initial state
1457 configname = xstrdup(conf_get_configname());
1459 QAction *saveAsAction = new QAction("Save &As...", this);
1460 connect(saveAsAction, SIGNAL(triggered(bool)), SLOT(saveConfigAs()));
1461 QAction *searchAction = new QAction("&Find", this);
1462 searchAction->setShortcut(Qt::CTRL + Qt::Key_F);
1463 connect(searchAction, SIGNAL(triggered(bool)), SLOT(searchConfig()));
1464 singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this);
1465 singleViewAction->setCheckable(true);
1466 connect(singleViewAction, SIGNAL(triggered(bool)), SLOT(showSingleView()));
1467 splitViewAction = new QAction(QPixmap(xpm_split_view), "Split View", this);
1468 splitViewAction->setCheckable(true);
1469 connect(splitViewAction, SIGNAL(triggered(bool)), SLOT(showSplitView()));
1470 fullViewAction = new QAction(QPixmap(xpm_tree_view), "Full View", this);
1471 fullViewAction->setCheckable(true);
1472 connect(fullViewAction, SIGNAL(triggered(bool)), SLOT(showFullView()));
1474 QAction *showNameAction = new QAction("Show Name", this);
1475 showNameAction->setCheckable(true);
1476 connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
1477 showNameAction->setChecked(configView->showName());
1478 QAction *showRangeAction = new QAction("Show Range", this);
1479 showRangeAction->setCheckable(true);
1480 connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
1481 QAction *showDataAction = new QAction("Show Data", this);
1482 showDataAction->setCheckable(true);
1483 connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
1485 QActionGroup *optGroup = new QActionGroup(this);
1486 optGroup->setExclusive(true);
1487 connect(optGroup, SIGNAL(triggered(QAction*)), configView,
1488 SLOT(setOptionMode(QAction *)));
1489 connect(optGroup, SIGNAL(triggered(QAction *)), menuView,
1490 SLOT(setOptionMode(QAction *)));
1492 configView->showNormalAction = new QAction("Show Normal Options", optGroup);
1493 configView->showAllAction = new QAction("Show All Options", optGroup);
1494 configView->showPromptAction = new QAction("Show Prompt Options", optGroup);
1495 configView->showNormalAction->setCheckable(true);
1496 configView->showAllAction->setCheckable(true);
1497 configView->showPromptAction->setCheckable(true);
1499 QAction *showDebugAction = new QAction("Show Debug Info", this);
1500 showDebugAction->setCheckable(true);
1501 connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
1502 showDebugAction->setChecked(helpText->showDebug());
1504 QAction *showIntroAction = new QAction("Introduction", this);
1505 connect(showIntroAction, SIGNAL(triggered(bool)), SLOT(showIntro()));
1506 QAction *showAboutAction = new QAction("About", this);
1507 connect(showAboutAction, SIGNAL(triggered(bool)), SLOT(showAbout()));
1510 toolBar->addAction(backAction);
1511 toolBar->addSeparator();
1512 toolBar->addAction(loadAction);
1513 toolBar->addAction(saveAction);
1514 toolBar->addSeparator();
1515 toolBar->addAction(singleViewAction);
1516 toolBar->addAction(splitViewAction);
1517 toolBar->addAction(fullViewAction);
1520 QMenu *menu = menuBar()->addMenu("&File");
1521 menu->addAction(loadAction);
1522 menu->addAction(saveAction);
1523 menu->addAction(saveAsAction);
1524 menu->addSeparator();
1525 menu->addAction(quitAction);
1528 menu = menuBar()->addMenu("&Edit");
1529 menu->addAction(searchAction);
1531 // create options menu
1532 menu = menuBar()->addMenu("&Option");
1533 menu->addAction(showNameAction);
1534 menu->addAction(showRangeAction);
1535 menu->addAction(showDataAction);
1536 menu->addSeparator();
1537 menu->addActions(optGroup->actions());
1538 menu->addSeparator();
1539 menu->addAction(showDebugAction);
1542 menu = menuBar()->addMenu("&Help");
1543 menu->addAction(showIntroAction);
1544 menu->addAction(showAboutAction);
1546 connect (helpText, SIGNAL (anchorClicked (const QUrl &)),
1547 helpText, SLOT (clicked (const QUrl &)) );
1549 connect(configList, SIGNAL(menuChanged(struct menu *)),
1550 helpText, SLOT(setInfo(struct menu *)));
1551 connect(configList, SIGNAL(menuSelected(struct menu *)),
1552 SLOT(changeMenu(struct menu *)));
1553 connect(configList, SIGNAL(itemSelected(struct menu *)),
1554 SLOT(changeItens(struct menu *)));
1555 connect(configList, SIGNAL(parentSelected()),
1557 connect(menuList, SIGNAL(menuChanged(struct menu *)),
1558 helpText, SLOT(setInfo(struct menu *)));
1559 connect(menuList, SIGNAL(menuSelected(struct menu *)),
1560 SLOT(changeMenu(struct menu *)));
1562 connect(configList, SIGNAL(gotFocus(struct menu *)),
1563 helpText, SLOT(setInfo(struct menu *)));
1564 connect(menuList, SIGNAL(gotFocus(struct menu *)),
1565 helpText, SLOT(setInfo(struct menu *)));
1566 connect(menuList, SIGNAL(gotFocus(struct menu *)),
1567 SLOT(listFocusChanged(void)));
1568 connect(helpText, SIGNAL(menuSelected(struct menu *)),
1569 SLOT(setMenuLink(struct menu *)));
1571 QString listMode = configSettings->value("/listMode", "symbol").toString();
1572 if (listMode == "single")
1574 else if (listMode == "full")
1576 else /*if (listMode == "split")*/
1579 // UI setup done, restore splitter positions
1580 QList<int> sizes = configSettings->readSizes("/split1", &ok);
1582 split1->setSizes(sizes);
1584 sizes = configSettings->readSizes("/split2", &ok);
1586 split2->setSizes(sizes);
1589 void ConfigMainWindow::loadConfig(void)
1595 str = QFileDialog::getOpenFileName(this, "", configname);
1599 ba = str.toLocal8Bit();
1602 if (conf_read(name))
1603 QMessageBox::information(this, "qconf", "Unable to load configuration!");
1606 configname = xstrdup(name);
1608 ConfigView::updateListAll();
1611 bool ConfigMainWindow::saveConfig(void)
1613 if (conf_write(configname)) {
1614 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1617 conf_write_autoconf(0);
1622 void ConfigMainWindow::saveConfigAs(void)
1628 str = QFileDialog::getSaveFileName(this, "", configname);
1632 ba = str.toLocal8Bit();
1635 if (conf_write(name)) {
1636 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1638 conf_write_autoconf(0);
1641 configname = xstrdup(name);
1644 void ConfigMainWindow::searchConfig(void)
1647 searchWindow = new ConfigSearchWindow(this, "search");
1648 searchWindow->show();
1651 void ConfigMainWindow::changeItens(struct menu *menu)
1653 configList->setRootMenu(menu);
1656 void ConfigMainWindow::changeMenu(struct menu *menu)
1658 menuList->setRootMenu(menu);
1661 void ConfigMainWindow::setMenuLink(struct menu *menu)
1663 struct menu *parent;
1664 ConfigList* list = NULL;
1667 if (configList->menuSkip(menu))
1670 switch (configList->mode) {
1673 parent = menu_get_parent_menu(menu);
1676 list->setRootMenu(parent);
1679 if (menu->flags & MENU_ROOT) {
1680 menuList->setRootMenu(menu);
1681 configList->clearSelection();
1684 parent = menu_get_parent_menu(menu->parent);
1688 /* Select the config view */
1689 item = configList->findConfigItem(parent);
1691 configList->setSelected(item, true);
1692 configList->scrollToItem(item);
1695 menuList->setRootMenu(parent);
1696 menuList->clearSelection();
1708 item = list->findConfigItem(menu);
1710 list->setSelected(item, true);
1711 list->scrollToItem(item);
1713 helpText->setInfo(menu);
1718 void ConfigMainWindow::listFocusChanged(void)
1720 if (menuList->mode == menuMode)
1721 configList->clearSelection();
1724 void ConfigMainWindow::goBack(void)
1726 if (configList->rootEntry == &rootmenu)
1729 configList->setParentMenu();
1732 void ConfigMainWindow::showSingleView(void)
1734 singleViewAction->setEnabled(false);
1735 singleViewAction->setChecked(true);
1736 splitViewAction->setEnabled(true);
1737 splitViewAction->setChecked(false);
1738 fullViewAction->setEnabled(true);
1739 fullViewAction->setChecked(false);
1741 backAction->setEnabled(true);
1744 menuList->setRootMenu(0);
1745 configList->mode = singleMode;
1746 if (configList->rootEntry == &rootmenu)
1747 configList->updateListAll();
1749 configList->setRootMenu(&rootmenu);
1750 configList->setFocus();
1753 void ConfigMainWindow::showSplitView(void)
1755 singleViewAction->setEnabled(true);
1756 singleViewAction->setChecked(false);
1757 splitViewAction->setEnabled(false);
1758 splitViewAction->setChecked(true);
1759 fullViewAction->setEnabled(true);
1760 fullViewAction->setChecked(false);
1762 backAction->setEnabled(false);
1764 configList->mode = menuMode;
1765 if (configList->rootEntry == &rootmenu)
1766 configList->updateListAll();
1768 configList->setRootMenu(&rootmenu);
1769 configList->setAllOpen(true);
1770 configApp->processEvents();
1771 menuList->mode = symbolMode;
1772 menuList->setRootMenu(&rootmenu);
1773 menuList->setAllOpen(true);
1775 menuList->setFocus();
1778 void ConfigMainWindow::showFullView(void)
1780 singleViewAction->setEnabled(true);
1781 singleViewAction->setChecked(false);
1782 splitViewAction->setEnabled(true);
1783 splitViewAction->setChecked(false);
1784 fullViewAction->setEnabled(false);
1785 fullViewAction->setChecked(true);
1787 backAction->setEnabled(false);
1790 menuList->setRootMenu(0);
1791 configList->mode = fullMode;
1792 if (configList->rootEntry == &rootmenu)
1793 configList->updateListAll();
1795 configList->setRootMenu(&rootmenu);
1796 configList->setFocus();
1800 * ask for saving configuration before quitting
1802 void ConfigMainWindow::closeEvent(QCloseEvent* e)
1804 if (!conf_get_changed()) {
1808 QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning,
1809 QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
1810 mb.setButtonText(QMessageBox::Yes, "&Save Changes");
1811 mb.setButtonText(QMessageBox::No, "&Discard Changes");
1812 mb.setButtonText(QMessageBox::Cancel, "Cancel Exit");
1813 switch (mb.exec()) {
1814 case QMessageBox::Yes:
1820 case QMessageBox::No:
1823 case QMessageBox::Cancel:
1829 void ConfigMainWindow::showIntro(void)
1831 static const QString str = "Welcome to the qconf graphical configuration tool.\n\n"
1832 "For each option, a blank box indicates the feature is disabled, a check\n"
1833 "indicates it is enabled, and a dot indicates that it is to be compiled\n"
1834 "as a module. Clicking on the box will cycle through the three states.\n\n"
1835 "If you do not see an option (e.g., a device driver) that you believe\n"
1836 "should be present, try turning on Show All Options under the Options menu.\n"
1837 "Although there is no cross reference yet to help you figure out what other\n"
1838 "options must be enabled to support the option you are interested in, you can\n"
1839 "still view the help of a grayed-out option.\n\n"
1840 "Toggling Show Debug Info under the Options menu will show the dependencies,\n"
1841 "which you can then match by examining other options.\n\n";
1843 QMessageBox::information(this, "qconf", str);
1846 void ConfigMainWindow::showAbout(void)
1848 static const QString str = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n"
1849 "Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>.\n\n"
1850 "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n";
1852 QMessageBox::information(this, "qconf", str);
1855 void ConfigMainWindow::saveSettings(void)
1857 configSettings->setValue("/window x", pos().x());
1858 configSettings->setValue("/window y", pos().y());
1859 configSettings->setValue("/window width", size().width());
1860 configSettings->setValue("/window height", size().height());
1863 switch(configList->mode) {
1879 configSettings->setValue("/listMode", entry);
1881 configSettings->writeSizes("/split1", split1->sizes());
1882 configSettings->writeSizes("/split2", split2->sizes());
1885 void ConfigMainWindow::conf_changed(void)
1888 saveAction->setEnabled(conf_get_changed());
1891 void fixup_rootmenu(struct menu *menu)
1894 static int menu_cnt = 0;
1896 menu->flags |= MENU_ROOT;
1897 for (child = menu->list; child; child = child->next) {
1898 if (child->prompt && child->prompt->type == P_MENU) {
1900 fixup_rootmenu(child);
1902 } else if (!menu_cnt)
1903 fixup_rootmenu(child);
1907 static const char *progname;
1909 static void usage(void)
1911 printf("%s [-s] <config>\n", progname);
1915 int main(int ac, char** av)
1917 ConfigMainWindow* v;
1921 configApp = new QApplication(ac, av);
1922 if (ac > 1 && av[1][0] == '-') {
1925 conf_set_message_callback(NULL);
1938 fixup_rootmenu(&rootmenu);
1940 //zconfdump(stdout);
1942 configSettings = new ConfigSettings();
1943 configSettings->beginGroup("/kconfig/qconf");
1944 v = new ConfigMainWindow();
1946 //zconfdump(stdout);
1947 configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
1948 configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1952 configSettings->endGroup();
1953 delete configSettings;