1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
4 * Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>
8 #include <QApplication>
11 #include <QDesktopWidget>
12 #include <QFileDialog>
18 #include <QMessageBox>
29 static QApplication *configApp;
30 static ConfigSettings *configSettings;
32 QAction *ConfigMainWindow::saveAction;
34 ConfigSettings::ConfigSettings()
35 : QSettings("kernel.org", "qconf")
40 * Reads a list of integer values from the application settings.
42 QList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
48 QStringList entryList = value(key).toStringList();
49 QStringList::Iterator it;
51 for (it = entryList.begin(); it != entryList.end(); ++it)
52 result.push_back((*it).toInt());
63 * Writes a list of integer values to the application settings.
65 bool ConfigSettings::writeSizes(const QString& key, const QList<int>& value)
67 QStringList stringList;
68 QList<int>::ConstIterator it;
70 for (it = value.begin(); it != value.end(); ++it)
71 stringList.push_back(QString::number(*it));
72 setValue(key, stringList);
80 * TODO check the value
82 void ConfigItem::okRename(int col)
87 * update the displayed of a menu entry
89 void ConfigItem::updateMenu(void)
93 struct property *prop;
100 setIcon(promptColIdx, list->menuBackPix);
107 prompt = menu_get_prompt(menu);
109 if (prop) switch (prop->type) {
111 if (list->mode == singleMode || list->mode == symbolMode) {
112 /* a menuconfig entry is displayed differently
113 * depending whether it's at the view root or a child.
115 if (sym && list->rootEntry == menu)
117 setIcon(promptColIdx, list->menuPix);
121 setIcon(promptColIdx, QIcon());
125 setIcon(promptColIdx, QIcon());
133 setText(nameColIdx, sym->name);
135 type = sym_get_type(sym);
141 if (!sym_is_changeable(sym) && list->optMode == normalOpt) {
142 setIcon(promptColIdx, QIcon());
143 setText(noColIdx, QString());
144 setText(modColIdx, QString());
145 setText(yesColIdx, QString());
148 expr = sym_get_tristate_value(sym);
151 if (sym_is_choice_value(sym) && type == S_BOOLEAN)
152 setIcon(promptColIdx, list->choiceYesPix);
154 setIcon(promptColIdx, list->symbolYesPix);
155 setText(yesColIdx, "Y");
159 setIcon(promptColIdx, list->symbolModPix);
160 setText(modColIdx, "M");
164 if (sym_is_choice_value(sym) && type == S_BOOLEAN)
165 setIcon(promptColIdx, list->choiceNoPix);
167 setIcon(promptColIdx, list->symbolNoPix);
168 setText(noColIdx, "N");
173 setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0);
175 setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0);
177 setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0);
179 setText(dataColIdx, QChar(ch));
186 data = sym_get_string_value(sym);
188 setText(dataColIdx, data);
189 if (type == S_STRING)
190 prompt = QString("%1: %2").arg(prompt).arg(data);
192 prompt = QString("(%2) %1").arg(prompt).arg(data);
195 if (!sym_has_value(sym) && visible)
198 setText(promptColIdx, prompt);
201 void ConfigItem::testUpdateMenu(bool v)
209 sym_calc_value(menu->sym);
210 if (menu->flags & MENU_CHANGED) {
211 /* the menu entry changed, so update all list items */
212 menu->flags &= ~MENU_CHANGED;
213 for (i = (ConfigItem*)menu->data; i; i = i->nextItem)
215 } else if (listView()->updateAll)
221 * construct a menu entry
223 void ConfigItem::init(void)
226 ConfigList* list = listView();
227 nextItem = (ConfigItem*)menu->data;
230 if (list->mode != fullMode)
232 sym_calc_value(menu->sym);
238 * destruct a menu entry
240 ConfigItem::~ConfigItem(void)
243 ConfigItem** ip = (ConfigItem**)&menu->data;
244 for (; *ip; ip = &(*ip)->nextItem) {
253 ConfigLineEdit::ConfigLineEdit(ConfigView* parent)
256 connect(this, SIGNAL(editingFinished()), SLOT(hide()));
259 void ConfigLineEdit::show(ConfigItem* i)
262 if (sym_get_string_value(item->menu->sym))
263 setText(sym_get_string_value(item->menu->sym));
270 void ConfigLineEdit::keyPressEvent(QKeyEvent* e)
277 sym_set_string_value(item->menu->sym, text().toLatin1());
278 parent()->updateList();
281 Parent::keyPressEvent(e);
285 parent()->list->setFocus();
289 ConfigList::ConfigList(ConfigView* p, const char *name)
292 symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no),
293 choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no),
294 menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void),
295 showName(false), showRange(false), showData(false), mode(singleMode), optMode(normalOpt),
296 rootEntry(0), headerPopup(0)
299 setSortingEnabled(false);
300 setRootIsDecorated(true);
302 setVerticalScrollMode(ScrollPerPixel);
303 setHorizontalScrollMode(ScrollPerPixel);
305 setHeaderLabels(QStringList() << "Option" << "Name" << "N" << "M" << "Y" << "Value");
307 connect(this, SIGNAL(itemSelectionChanged(void)),
308 SLOT(updateSelection(void)));
311 configSettings->beginGroup(name);
312 showName = configSettings->value("/showName", false).toBool();
313 showRange = configSettings->value("/showRange", false).toBool();
314 showData = configSettings->value("/showData", false).toBool();
315 optMode = (enum optionMode)configSettings->value("/optionMode", 0).toInt();
316 configSettings->endGroup();
317 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
320 showColumn(promptColIdx);
325 bool ConfigList::menuSkip(struct menu *menu)
327 if (optMode == normalOpt && menu_is_visible(menu))
329 if (optMode == promptOpt && menu_has_prompt(menu))
331 if (optMode == allOpt)
336 void ConfigList::reinit(void)
338 hideColumn(dataColIdx);
339 hideColumn(yesColIdx);
340 hideColumn(modColIdx);
341 hideColumn(noColIdx);
342 hideColumn(nameColIdx);
345 showColumn(nameColIdx);
347 showColumn(noColIdx);
348 showColumn(modColIdx);
349 showColumn(yesColIdx);
352 showColumn(dataColIdx);
357 void ConfigList::saveSettings(void)
359 if (!objectName().isEmpty()) {
360 configSettings->beginGroup(objectName());
361 configSettings->setValue("/showName", showName);
362 configSettings->setValue("/showRange", showRange);
363 configSettings->setValue("/showData", showData);
364 configSettings->setValue("/optionMode", (int)optMode);
365 configSettings->endGroup();
369 ConfigItem* ConfigList::findConfigItem(struct menu *menu)
371 ConfigItem* item = (ConfigItem*)menu->data;
373 for (; item; item = item->nextItem) {
374 if (this == item->listView())
381 void ConfigList::updateSelection(void)
386 if (selectedItems().count() == 0)
389 ConfigItem* item = (ConfigItem*)selectedItems().first();
394 emit menuChanged(menu);
397 type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
398 if (mode == menuMode && type == P_MENU)
399 emit menuSelected(menu);
402 void ConfigList::updateList()
404 ConfigItem* last = 0;
408 if (mode != listMode)
410 QTreeWidgetItemIterator it(this);
413 item = (ConfigItem*)(*it);
416 item->testUpdateMenu(menu_is_visible(item->menu));
423 if (rootEntry != &rootmenu && (mode == singleMode ||
424 (mode == symbolMode && rootEntry->parent != &rootmenu))) {
425 item = (ConfigItem *)topLevelItem(0);
427 item = new ConfigItem(this, 0, true);
430 if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) &&
431 rootEntry->sym && rootEntry->prompt) {
432 item = last ? last->nextSibling() : nullptr;
434 item = new ConfigItem(this, last, rootEntry, true);
436 item->testUpdateMenu(true);
438 updateMenuList(item, rootEntry);
440 resizeColumnToContents(0);
444 updateMenuList(rootEntry);
446 resizeColumnToContents(0);
449 void ConfigList::setValue(ConfigItem* item, tristate val)
455 sym = item->menu ? item->menu->sym : 0;
459 type = sym_get_type(sym);
463 oldval = sym_get_tristate_value(sym);
465 if (!sym_set_tristate_value(sym, val))
467 if (oldval == no && item->menu->list)
468 item->setExpanded(true);
469 parent()->updateList();
474 void ConfigList::changeValue(ConfigItem* item)
478 int type, oldexpr, newexpr;
485 if (item->menu->list)
486 item->setExpanded(!item->isExpanded());
490 type = sym_get_type(sym);
494 oldexpr = sym_get_tristate_value(sym);
495 newexpr = sym_toggle_tristate_value(sym);
496 if (item->menu->list) {
497 if (oldexpr == newexpr)
498 item->setExpanded(!item->isExpanded());
499 else if (oldexpr == no)
500 item->setExpanded(true);
502 if (oldexpr != newexpr)
503 parent()->updateList();
508 parent()->lineEdit->show(item);
513 void ConfigList::setRootMenu(struct menu *menu)
517 if (rootEntry == menu)
519 type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
526 setSelected(currentItem(), hasFocus());
527 scrollToItem(currentItem());
531 void ConfigList::setParentMenu(void)
534 struct menu *oldroot;
537 if (rootEntry == &rootmenu)
539 setRootMenu(menu_get_parent_menu(rootEntry->parent));
541 QTreeWidgetItemIterator it(this);
543 item = (ConfigItem *)(*it);
544 if (item->menu == oldroot) {
545 setCurrentItem(item);
555 * update all the children of a menu entry
556 * removes/adds the entries from the parent widget as necessary
558 * parent: either the menu list widget or a menu entry widget
559 * menu: entry to be updated
561 void ConfigList::updateMenuList(ConfigItem *parent, struct menu* menu)
570 while (parent->childCount() > 0)
572 delete parent->takeChild(0);
578 last = parent->firstChild();
579 if (last && !last->goParent)
581 for (child = menu->list; child; child = child->next) {
582 item = last ? last->nextSibling() : parent->firstChild();
583 type = child->prompt ? child->prompt->type : P_UNKNOWN;
587 if (!(child->flags & MENU_ROOT))
591 if (child->flags & MENU_ROOT)
598 visible = menu_is_visible(child);
599 if (!menuSkip(child)) {
600 if (!child->sym && !child->list && !child->prompt)
602 if (!item || item->menu != child)
603 item = new ConfigItem(parent, last, child, visible);
605 item->testUpdateMenu(visible);
607 if (mode == fullMode || mode == menuMode || type != P_MENU)
608 updateMenuList(item, child);
610 updateMenuList(item, 0);
615 if (item && item->menu == child) {
616 last = parent->firstChild();
619 else while (last->nextSibling() != item)
620 last = last->nextSibling();
626 void ConfigList::updateMenuList(struct menu *menu)
635 while (topLevelItemCount() > 0)
637 delete takeTopLevelItem(0);
643 last = (ConfigItem *)topLevelItem(0);
644 if (last && !last->goParent)
646 for (child = menu->list; child; child = child->next) {
647 item = last ? last->nextSibling() : (ConfigItem *)topLevelItem(0);
648 type = child->prompt ? child->prompt->type : P_UNKNOWN;
652 if (!(child->flags & MENU_ROOT))
656 if (child->flags & MENU_ROOT)
663 visible = menu_is_visible(child);
664 if (!menuSkip(child)) {
665 if (!child->sym && !child->list && !child->prompt)
667 if (!item || item->menu != child)
668 item = new ConfigItem(this, last, child, visible);
670 item->testUpdateMenu(visible);
672 if (mode == fullMode || mode == menuMode || type != P_MENU)
673 updateMenuList(item, child);
675 updateMenuList(item, 0);
680 if (item && item->menu == child) {
681 last = (ConfigItem *)topLevelItem(0);
684 else while (last->nextSibling() != item)
685 last = last->nextSibling();
691 void ConfigList::keyPressEvent(QKeyEvent* ev)
693 QTreeWidgetItem* i = currentItem();
698 if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) {
699 emit parentSelected();
705 Parent::keyPressEvent(ev);
708 item = (ConfigItem*)i;
713 if (item->goParent) {
714 emit parentSelected();
720 type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
721 if (type == P_MENU && rootEntry != menu &&
722 mode != fullMode && mode != menuMode) {
723 if (mode == menuMode)
724 emit menuSelected(menu);
726 emit itemSelected(menu);
742 Parent::keyPressEvent(ev);
748 void ConfigList::mousePressEvent(QMouseEvent* e)
750 //QPoint p(contentsToViewport(e->pos()));
751 //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
752 Parent::mousePressEvent(e);
755 void ConfigList::mouseReleaseEvent(QMouseEvent* e)
758 ConfigItem* item = (ConfigItem*)itemAt(p);
760 enum prop_type ptype;
768 x = header()->offset() + p.x();
769 idx = header()->logicalIndexAt(x);
772 icon = item->icon(promptColIdx);
773 if (!icon.isNull()) {
774 int off = header()->sectionPosition(0) + visualRect(indexAt(p)).x() + 4; // 4 is Hardcoded image offset. There might be a way to do it properly.
775 if (x >= off && x < off + icon.availableSizes().first().width()) {
776 if (item->goParent) {
777 emit parentSelected();
781 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
782 if (ptype == P_MENU && rootEntry != menu &&
783 mode != fullMode && mode != menuMode &&
785 emit menuSelected(menu);
806 //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
807 Parent::mouseReleaseEvent(e);
810 void ConfigList::mouseMoveEvent(QMouseEvent* e)
812 //QPoint p(contentsToViewport(e->pos()));
813 //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
814 Parent::mouseMoveEvent(e);
817 void ConfigList::mouseDoubleClickEvent(QMouseEvent* e)
820 ConfigItem* item = (ConfigItem*)itemAt(p);
822 enum prop_type ptype;
826 if (item->goParent) {
827 emit parentSelected();
833 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
834 if (ptype == P_MENU && mode != listMode) {
835 if (mode == singleMode)
836 emit itemSelected(menu);
837 else if (mode == symbolMode)
838 emit menuSelected(menu);
839 } else if (menu->sym)
843 //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
844 Parent::mouseDoubleClickEvent(e);
847 void ConfigList::focusInEvent(QFocusEvent *e)
849 struct menu *menu = NULL;
851 Parent::focusInEvent(e);
853 ConfigItem* item = (ConfigItem *)currentItem();
855 setSelected(item, true);
861 void ConfigList::contextMenuEvent(QContextMenuEvent *e)
863 if (e->y() <= header()->geometry().bottom()) {
867 headerPopup = new QMenu(this);
868 action = new QAction("Show Name", this);
869 action->setCheckable(true);
870 connect(action, SIGNAL(toggled(bool)),
871 parent(), SLOT(setShowName(bool)));
872 connect(parent(), SIGNAL(showNameChanged(bool)),
873 action, SLOT(setOn(bool)));
874 action->setChecked(showName);
875 headerPopup->addAction(action);
876 action = new QAction("Show Range", this);
877 action->setCheckable(true);
878 connect(action, SIGNAL(toggled(bool)),
879 parent(), SLOT(setShowRange(bool)));
880 connect(parent(), SIGNAL(showRangeChanged(bool)),
881 action, SLOT(setOn(bool)));
882 action->setChecked(showRange);
883 headerPopup->addAction(action);
884 action = new QAction("Show Data", this);
885 action->setCheckable(true);
886 connect(action, SIGNAL(toggled(bool)),
887 parent(), SLOT(setShowData(bool)));
888 connect(parent(), SIGNAL(showDataChanged(bool)),
889 action, SLOT(setOn(bool)));
890 action->setChecked(showData);
891 headerPopup->addAction(action);
893 headerPopup->exec(e->globalPos());
899 ConfigView*ConfigView::viewList;
900 QAction *ConfigView::showNormalAction;
901 QAction *ConfigView::showAllAction;
902 QAction *ConfigView::showPromptAction;
904 ConfigView::ConfigView(QWidget* parent, const char *name)
908 QVBoxLayout *verticalLayout = new QVBoxLayout(this);
909 verticalLayout->setContentsMargins(0, 0, 0, 0);
911 list = new ConfigList(this);
912 verticalLayout->addWidget(list);
913 lineEdit = new ConfigLineEdit(this);
915 verticalLayout->addWidget(lineEdit);
917 this->nextView = viewList;
921 ConfigView::~ConfigView(void)
925 for (vp = &viewList; *vp; vp = &(*vp)->nextView) {
933 void ConfigView::setOptionMode(QAction *act)
935 if (act == showNormalAction)
936 list->optMode = normalOpt;
937 else if (act == showAllAction)
938 list->optMode = allOpt;
940 list->optMode = promptOpt;
942 list->updateListAll();
945 void ConfigView::setShowName(bool b)
947 if (list->showName != b) {
950 emit showNameChanged(b);
954 void ConfigView::setShowRange(bool b)
956 if (list->showRange != b) {
959 emit showRangeChanged(b);
963 void ConfigView::setShowData(bool b)
965 if (list->showData != b) {
968 emit showDataChanged(b);
972 void ConfigList::setAllOpen(bool open)
974 QTreeWidgetItemIterator it(this);
977 (*it)->setExpanded(open);
983 void ConfigView::updateList()
987 for (v = viewList; v; v = v->nextView)
988 v->list->updateList();
991 void ConfigView::updateListAll(void)
995 for (v = viewList; v; v = v->nextView)
996 v->list->updateListAll();
999 ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
1000 : Parent(parent), sym(0), _menu(0)
1002 setObjectName(name);
1003 setOpenLinks(false);
1005 if (!objectName().isEmpty()) {
1006 configSettings->beginGroup(objectName());
1007 setShowDebug(configSettings->value("/showDebug", false).toBool());
1008 configSettings->endGroup();
1009 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
1013 void ConfigInfoView::saveSettings(void)
1015 if (!objectName().isEmpty()) {
1016 configSettings->beginGroup(objectName());
1017 configSettings->setValue("/showDebug", showDebug());
1018 configSettings->endGroup();
1022 void ConfigInfoView::setShowDebug(bool b)
1024 if (_showDebug != b) {
1030 emit showDebugChanged(b);
1034 void ConfigInfoView::setInfo(struct menu *m)
1046 void ConfigInfoView::symbolInfo(void)
1050 str += "<big>Symbol: <b>";
1051 str += print_filter(sym->name);
1052 str += "</b></big><br><br>value: ";
1053 str += print_filter(sym_get_string_value(sym));
1054 str += "<br>visibility: ";
1055 str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n";
1057 str += debug_info(sym);
1062 void ConfigInfoView::menuInfo(void)
1065 QString head, debug, help;
1069 if (_menu->prompt) {
1071 head += print_filter(_menu->prompt->text);
1072 head += "</b></big>";
1076 head += QString().sprintf("<a href=\"s%s\">", sym->name);
1077 head += print_filter(sym->name);
1082 } else if (sym->name) {
1085 head += QString().sprintf("<a href=\"s%s\">", sym->name);
1086 head += print_filter(sym->name);
1089 head += "</b></big>";
1094 debug = debug_info(sym);
1096 struct gstr help_gstr = str_new();
1097 menu_get_ext_help(_menu, &help_gstr);
1098 help = print_filter(str_get(&help_gstr));
1099 str_free(&help_gstr);
1100 } else if (_menu->prompt) {
1102 head += print_filter(_menu->prompt->text);
1103 head += "</b></big><br><br>";
1105 if (_menu->prompt->visible.expr) {
1106 debug += " dep: ";
1107 expr_print(_menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
1108 debug += "<br><br>";
1113 debug += QString().sprintf("defined at %s:%d<br><br>", _menu->file->name, _menu->lineno);
1115 setText(head + debug + help);
1118 QString ConfigInfoView::debug_info(struct symbol *sym)
1123 debug += print_filter(sym_type_name(sym->type));
1124 if (sym_is_choice(sym))
1125 debug += " (choice)";
1127 if (sym->rev_dep.expr) {
1128 debug += "reverse dep: ";
1129 expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
1132 for (struct property *prop = sym->prop; prop; prop = prop->next) {
1133 switch (prop->type) {
1136 debug += QString().sprintf("prompt: <a href=\"m%s\">", sym->name);
1137 debug += print_filter(prop->text);
1138 debug += "</a><br>";
1146 debug += prop_get_type_name(prop->type);
1148 expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1152 if (sym_is_choice(sym)) {
1153 debug += "choice: ";
1154 expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1159 debug += "unknown property: ";
1160 debug += prop_get_type_name(prop->type);
1163 if (prop->visible.expr) {
1164 debug += " dep: ";
1165 expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
1174 QString ConfigInfoView::print_filter(const QString &str)
1176 QRegExp re("[<>&\"\\n]");
1178 for (int i = 0; (i = res.indexOf(re, i)) >= 0;) {
1179 switch (res[i].toLatin1()) {
1181 res.replace(i, 1, "<");
1185 res.replace(i, 1, ">");
1189 res.replace(i, 1, "&");
1193 res.replace(i, 1, """);
1197 res.replace(i, 1, "<br>");
1205 void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str)
1207 QString* text = reinterpret_cast<QString*>(data);
1208 QString str2 = print_filter(str);
1210 if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
1211 *text += QString().sprintf("<a href=\"s%s\">", sym->name);
1218 void ConfigInfoView::clicked(const QUrl &url)
1220 QByteArray str = url.toEncoded();
1221 const std::size_t count = str.size();
1222 char *data = new char[count + 1];
1223 struct symbol **result;
1224 struct menu *m = NULL;
1227 qInfo() << "Clicked link is empty";
1232 memcpy(data, str.constData(), count);
1235 /* Seek for exact match */
1238 result = sym_re_search(data);
1240 qInfo() << "Clicked symbol is invalid:" << data;
1247 /* Seek for the menu which holds the symbol */
1248 for (struct property *prop = sym->prop; prop; prop = prop->next) {
1249 if (prop->type != P_PROMPT && prop->type != P_MENU)
1256 /* Symbol is not visible as a menu */
1258 emit showDebugChanged(true);
1260 emit menuSelected(m);
1267 QMenu* ConfigInfoView::createStandardContextMenu(const QPoint & pos)
1269 QMenu* popup = Parent::createStandardContextMenu(pos);
1270 QAction* action = new QAction("Show Debug Info", popup);
1272 action->setCheckable(true);
1273 connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
1274 connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
1275 action->setChecked(showDebug());
1276 popup->addSeparator();
1277 popup->addAction(action);
1281 void ConfigInfoView::contextMenuEvent(QContextMenuEvent *e)
1283 Parent::contextMenuEvent(e);
1286 ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow *parent)
1287 : Parent(parent), result(NULL)
1289 setObjectName("search");
1290 setWindowTitle("Search Config");
1292 QVBoxLayout* layout1 = new QVBoxLayout(this);
1293 layout1->setContentsMargins(11, 11, 11, 11);
1294 layout1->setSpacing(6);
1296 QHBoxLayout* layout2 = new QHBoxLayout();
1297 layout2->setContentsMargins(0, 0, 0, 0);
1298 layout2->setSpacing(6);
1299 layout2->addWidget(new QLabel("Find:", this));
1300 editField = new QLineEdit(this);
1301 connect(editField, SIGNAL(returnPressed()), SLOT(search()));
1302 layout2->addWidget(editField);
1303 searchButton = new QPushButton("Search", this);
1304 searchButton->setAutoDefault(false);
1305 connect(searchButton, SIGNAL(clicked()), SLOT(search()));
1306 layout2->addWidget(searchButton);
1307 layout1->addLayout(layout2);
1309 split = new QSplitter(this);
1310 split->setOrientation(Qt::Vertical);
1311 list = new ConfigView(split, "search");
1312 list->list->mode = listMode;
1313 info = new ConfigInfoView(split, "search");
1314 connect(list->list, SIGNAL(menuChanged(struct menu *)),
1315 info, SLOT(setInfo(struct menu *)));
1316 connect(list->list, SIGNAL(menuChanged(struct menu *)),
1317 parent, SLOT(setMenuLink(struct menu *)));
1319 layout1->addWidget(split);
1325 configSettings->beginGroup("search");
1326 width = configSettings->value("/window width", parent->width() / 2).toInt();
1327 height = configSettings->value("/window height", parent->height() / 2).toInt();
1328 resize(width, height);
1329 x = configSettings->value("/window x");
1330 y = configSettings->value("/window y");
1331 if (x.isValid() && y.isValid())
1332 move(x.toInt(), y.toInt());
1333 QList<int> sizes = configSettings->readSizes("/split", &ok);
1335 split->setSizes(sizes);
1336 configSettings->endGroup();
1337 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
1340 void ConfigSearchWindow::saveSettings(void)
1342 if (!objectName().isEmpty()) {
1343 configSettings->beginGroup(objectName());
1344 configSettings->setValue("/window x", pos().x());
1345 configSettings->setValue("/window y", pos().y());
1346 configSettings->setValue("/window width", size().width());
1347 configSettings->setValue("/window height", size().height());
1348 configSettings->writeSizes("/split", split->sizes());
1349 configSettings->endGroup();
1353 void ConfigSearchWindow::search(void)
1356 struct property *prop;
1357 ConfigItem *lastItem = NULL;
1360 list->list->clear();
1363 result = sym_re_search(editField->text().toLatin1());
1366 for (p = result; *p; p++) {
1367 for_all_prompts((*p), prop)
1368 lastItem = new ConfigItem(list->list, lastItem, prop->menu,
1369 menu_is_visible(prop->menu));
1374 * Construct the complete config widget
1376 ConfigMainWindow::ConfigMainWindow(void)
1384 QDesktopWidget *d = configApp->desktop();
1385 snprintf(title, sizeof(title), "%s%s",
1386 rootmenu.prompt->text,
1389 setWindowTitle(title);
1391 width = configSettings->value("/window width", d->width() - 64).toInt();
1392 height = configSettings->value("/window height", d->height() - 64).toInt();
1393 resize(width, height);
1394 x = configSettings->value("/window x");
1395 y = configSettings->value("/window y");
1396 if ((x.isValid())&&(y.isValid()))
1397 move(x.toInt(), y.toInt());
1399 QWidget *widget = new QWidget(this);
1400 QVBoxLayout *layout = new QVBoxLayout(widget);
1401 setCentralWidget(widget);
1403 split1 = new QSplitter(widget);
1404 split1->setOrientation(Qt::Horizontal);
1405 split1->setChildrenCollapsible(false);
1407 menuView = new ConfigView(widget, "menu");
1408 menuList = menuView->list;
1410 split2 = new QSplitter(widget);
1411 split2->setChildrenCollapsible(false);
1412 split2->setOrientation(Qt::Vertical);
1414 // create config tree
1415 configView = new ConfigView(widget, "config");
1416 configList = configView->list;
1418 helpText = new ConfigInfoView(widget, "help");
1420 layout->addWidget(split2);
1421 split2->addWidget(split1);
1422 split1->addWidget(configView);
1423 split1->addWidget(menuView);
1424 split2->addWidget(helpText);
1426 setTabOrder(configList, helpText);
1427 configList->setFocus();
1429 backAction = new QAction(QPixmap(xpm_back), "Back", this);
1430 connect(backAction, SIGNAL(triggered(bool)), SLOT(goBack()));
1432 QAction *quitAction = new QAction("&Quit", this);
1433 quitAction->setShortcut(Qt::CTRL + Qt::Key_Q);
1434 connect(quitAction, SIGNAL(triggered(bool)), SLOT(close()));
1436 QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this);
1437 loadAction->setShortcut(Qt::CTRL + Qt::Key_L);
1438 connect(loadAction, SIGNAL(triggered(bool)), SLOT(loadConfig()));
1440 saveAction = new QAction(QPixmap(xpm_save), "&Save", this);
1441 saveAction->setShortcut(Qt::CTRL + Qt::Key_S);
1442 connect(saveAction, SIGNAL(triggered(bool)), SLOT(saveConfig()));
1444 conf_set_changed_callback(conf_changed);
1446 // Set saveAction's initial state
1448 configname = xstrdup(conf_get_configname());
1450 QAction *saveAsAction = new QAction("Save &As...", this);
1451 connect(saveAsAction, SIGNAL(triggered(bool)), SLOT(saveConfigAs()));
1452 QAction *searchAction = new QAction("&Find", this);
1453 searchAction->setShortcut(Qt::CTRL + Qt::Key_F);
1454 connect(searchAction, SIGNAL(triggered(bool)), SLOT(searchConfig()));
1455 singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this);
1456 singleViewAction->setCheckable(true);
1457 connect(singleViewAction, SIGNAL(triggered(bool)), SLOT(showSingleView()));
1458 splitViewAction = new QAction(QPixmap(xpm_split_view), "Split View", this);
1459 splitViewAction->setCheckable(true);
1460 connect(splitViewAction, SIGNAL(triggered(bool)), SLOT(showSplitView()));
1461 fullViewAction = new QAction(QPixmap(xpm_tree_view), "Full View", this);
1462 fullViewAction->setCheckable(true);
1463 connect(fullViewAction, SIGNAL(triggered(bool)), SLOT(showFullView()));
1465 QAction *showNameAction = new QAction("Show Name", this);
1466 showNameAction->setCheckable(true);
1467 connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
1468 showNameAction->setChecked(configView->showName());
1469 QAction *showRangeAction = new QAction("Show Range", this);
1470 showRangeAction->setCheckable(true);
1471 connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
1472 QAction *showDataAction = new QAction("Show Data", this);
1473 showDataAction->setCheckable(true);
1474 connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
1476 QActionGroup *optGroup = new QActionGroup(this);
1477 optGroup->setExclusive(true);
1478 connect(optGroup, SIGNAL(triggered(QAction*)), configView,
1479 SLOT(setOptionMode(QAction *)));
1480 connect(optGroup, SIGNAL(triggered(QAction *)), menuView,
1481 SLOT(setOptionMode(QAction *)));
1483 configView->showNormalAction = new QAction("Show Normal Options", optGroup);
1484 configView->showAllAction = new QAction("Show All Options", optGroup);
1485 configView->showPromptAction = new QAction("Show Prompt Options", optGroup);
1486 configView->showNormalAction->setCheckable(true);
1487 configView->showAllAction->setCheckable(true);
1488 configView->showPromptAction->setCheckable(true);
1490 QAction *showDebugAction = new QAction("Show Debug Info", this);
1491 showDebugAction->setCheckable(true);
1492 connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
1493 showDebugAction->setChecked(helpText->showDebug());
1495 QAction *showIntroAction = new QAction("Introduction", this);
1496 connect(showIntroAction, SIGNAL(triggered(bool)), SLOT(showIntro()));
1497 QAction *showAboutAction = new QAction("About", this);
1498 connect(showAboutAction, SIGNAL(triggered(bool)), SLOT(showAbout()));
1501 QToolBar *toolBar = addToolBar("Tools");
1502 toolBar->addAction(backAction);
1503 toolBar->addSeparator();
1504 toolBar->addAction(loadAction);
1505 toolBar->addAction(saveAction);
1506 toolBar->addSeparator();
1507 toolBar->addAction(singleViewAction);
1508 toolBar->addAction(splitViewAction);
1509 toolBar->addAction(fullViewAction);
1512 QMenu *menu = menuBar()->addMenu("&File");
1513 menu->addAction(loadAction);
1514 menu->addAction(saveAction);
1515 menu->addAction(saveAsAction);
1516 menu->addSeparator();
1517 menu->addAction(quitAction);
1520 menu = menuBar()->addMenu("&Edit");
1521 menu->addAction(searchAction);
1523 // create options menu
1524 menu = menuBar()->addMenu("&Option");
1525 menu->addAction(showNameAction);
1526 menu->addAction(showRangeAction);
1527 menu->addAction(showDataAction);
1528 menu->addSeparator();
1529 menu->addActions(optGroup->actions());
1530 menu->addSeparator();
1531 menu->addAction(showDebugAction);
1534 menu = menuBar()->addMenu("&Help");
1535 menu->addAction(showIntroAction);
1536 menu->addAction(showAboutAction);
1538 connect (helpText, SIGNAL (anchorClicked (const QUrl &)),
1539 helpText, SLOT (clicked (const QUrl &)) );
1541 connect(configList, SIGNAL(menuChanged(struct menu *)),
1542 helpText, SLOT(setInfo(struct menu *)));
1543 connect(configList, SIGNAL(menuSelected(struct menu *)),
1544 SLOT(changeMenu(struct menu *)));
1545 connect(configList, SIGNAL(itemSelected(struct menu *)),
1546 SLOT(changeItens(struct menu *)));
1547 connect(configList, SIGNAL(parentSelected()),
1549 connect(menuList, SIGNAL(menuChanged(struct menu *)),
1550 helpText, SLOT(setInfo(struct menu *)));
1551 connect(menuList, SIGNAL(menuSelected(struct menu *)),
1552 SLOT(changeMenu(struct menu *)));
1554 connect(configList, SIGNAL(gotFocus(struct menu *)),
1555 helpText, SLOT(setInfo(struct menu *)));
1556 connect(menuList, SIGNAL(gotFocus(struct menu *)),
1557 helpText, SLOT(setInfo(struct menu *)));
1558 connect(menuList, SIGNAL(gotFocus(struct menu *)),
1559 SLOT(listFocusChanged(void)));
1560 connect(helpText, SIGNAL(menuSelected(struct menu *)),
1561 SLOT(setMenuLink(struct menu *)));
1563 QString listMode = configSettings->value("/listMode", "symbol").toString();
1564 if (listMode == "single")
1566 else if (listMode == "full")
1568 else /*if (listMode == "split")*/
1571 // UI setup done, restore splitter positions
1572 QList<int> sizes = configSettings->readSizes("/split1", &ok);
1574 split1->setSizes(sizes);
1576 sizes = configSettings->readSizes("/split2", &ok);
1578 split2->setSizes(sizes);
1581 void ConfigMainWindow::loadConfig(void)
1587 str = QFileDialog::getOpenFileName(this, "", configname);
1591 ba = str.toLocal8Bit();
1594 if (conf_read(name))
1595 QMessageBox::information(this, "qconf", "Unable to load configuration!");
1598 configname = xstrdup(name);
1600 ConfigView::updateListAll();
1603 bool ConfigMainWindow::saveConfig(void)
1605 if (conf_write(configname)) {
1606 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1609 conf_write_autoconf(0);
1614 void ConfigMainWindow::saveConfigAs(void)
1620 str = QFileDialog::getSaveFileName(this, "", configname);
1624 ba = str.toLocal8Bit();
1627 if (conf_write(name)) {
1628 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1630 conf_write_autoconf(0);
1633 configname = xstrdup(name);
1636 void ConfigMainWindow::searchConfig(void)
1639 searchWindow = new ConfigSearchWindow(this);
1640 searchWindow->show();
1643 void ConfigMainWindow::changeItens(struct menu *menu)
1645 configList->setRootMenu(menu);
1648 void ConfigMainWindow::changeMenu(struct menu *menu)
1650 menuList->setRootMenu(menu);
1653 void ConfigMainWindow::setMenuLink(struct menu *menu)
1655 struct menu *parent;
1656 ConfigList* list = NULL;
1659 if (configList->menuSkip(menu))
1662 switch (configList->mode) {
1665 parent = menu_get_parent_menu(menu);
1668 list->setRootMenu(parent);
1671 if (menu->flags & MENU_ROOT) {
1672 menuList->setRootMenu(menu);
1673 configList->clearSelection();
1676 parent = menu_get_parent_menu(menu->parent);
1680 /* Select the config view */
1681 item = configList->findConfigItem(parent);
1683 configList->setSelected(item, true);
1684 configList->scrollToItem(item);
1687 menuList->setRootMenu(parent);
1688 menuList->clearSelection();
1700 item = list->findConfigItem(menu);
1702 list->setSelected(item, true);
1703 list->scrollToItem(item);
1705 helpText->setInfo(menu);
1710 void ConfigMainWindow::listFocusChanged(void)
1712 if (menuList->mode == menuMode)
1713 configList->clearSelection();
1716 void ConfigMainWindow::goBack(void)
1718 if (configList->rootEntry == &rootmenu)
1721 configList->setParentMenu();
1724 void ConfigMainWindow::showSingleView(void)
1726 singleViewAction->setEnabled(false);
1727 singleViewAction->setChecked(true);
1728 splitViewAction->setEnabled(true);
1729 splitViewAction->setChecked(false);
1730 fullViewAction->setEnabled(true);
1731 fullViewAction->setChecked(false);
1733 backAction->setEnabled(true);
1736 menuList->setRootMenu(0);
1737 configList->mode = singleMode;
1738 if (configList->rootEntry == &rootmenu)
1739 configList->updateListAll();
1741 configList->setRootMenu(&rootmenu);
1742 configList->setFocus();
1745 void ConfigMainWindow::showSplitView(void)
1747 singleViewAction->setEnabled(true);
1748 singleViewAction->setChecked(false);
1749 splitViewAction->setEnabled(false);
1750 splitViewAction->setChecked(true);
1751 fullViewAction->setEnabled(true);
1752 fullViewAction->setChecked(false);
1754 backAction->setEnabled(false);
1756 configList->mode = menuMode;
1757 if (configList->rootEntry == &rootmenu)
1758 configList->updateListAll();
1760 configList->setRootMenu(&rootmenu);
1761 configList->setAllOpen(true);
1762 configApp->processEvents();
1763 menuList->mode = symbolMode;
1764 menuList->setRootMenu(&rootmenu);
1765 menuList->setAllOpen(true);
1767 menuList->setFocus();
1770 void ConfigMainWindow::showFullView(void)
1772 singleViewAction->setEnabled(true);
1773 singleViewAction->setChecked(false);
1774 splitViewAction->setEnabled(true);
1775 splitViewAction->setChecked(false);
1776 fullViewAction->setEnabled(false);
1777 fullViewAction->setChecked(true);
1779 backAction->setEnabled(false);
1782 menuList->setRootMenu(0);
1783 configList->mode = fullMode;
1784 if (configList->rootEntry == &rootmenu)
1785 configList->updateListAll();
1787 configList->setRootMenu(&rootmenu);
1788 configList->setFocus();
1792 * ask for saving configuration before quitting
1794 void ConfigMainWindow::closeEvent(QCloseEvent* e)
1796 if (!conf_get_changed()) {
1800 QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning,
1801 QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
1802 mb.setButtonText(QMessageBox::Yes, "&Save Changes");
1803 mb.setButtonText(QMessageBox::No, "&Discard Changes");
1804 mb.setButtonText(QMessageBox::Cancel, "Cancel Exit");
1805 switch (mb.exec()) {
1806 case QMessageBox::Yes:
1812 case QMessageBox::No:
1815 case QMessageBox::Cancel:
1821 void ConfigMainWindow::showIntro(void)
1823 static const QString str = "Welcome to the qconf graphical configuration tool.\n\n"
1824 "For each option, a blank box indicates the feature is disabled, a check\n"
1825 "indicates it is enabled, and a dot indicates that it is to be compiled\n"
1826 "as a module. Clicking on the box will cycle through the three states.\n\n"
1827 "If you do not see an option (e.g., a device driver) that you believe\n"
1828 "should be present, try turning on Show All Options under the Options menu.\n"
1829 "Although there is no cross reference yet to help you figure out what other\n"
1830 "options must be enabled to support the option you are interested in, you can\n"
1831 "still view the help of a grayed-out option.\n\n"
1832 "Toggling Show Debug Info under the Options menu will show the dependencies,\n"
1833 "which you can then match by examining other options.\n\n";
1835 QMessageBox::information(this, "qconf", str);
1838 void ConfigMainWindow::showAbout(void)
1840 static const QString str = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n"
1841 "Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>.\n\n"
1842 "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n";
1844 QMessageBox::information(this, "qconf", str);
1847 void ConfigMainWindow::saveSettings(void)
1849 configSettings->setValue("/window x", pos().x());
1850 configSettings->setValue("/window y", pos().y());
1851 configSettings->setValue("/window width", size().width());
1852 configSettings->setValue("/window height", size().height());
1855 switch(configList->mode) {
1871 configSettings->setValue("/listMode", entry);
1873 configSettings->writeSizes("/split1", split1->sizes());
1874 configSettings->writeSizes("/split2", split2->sizes());
1877 void ConfigMainWindow::conf_changed(void)
1880 saveAction->setEnabled(conf_get_changed());
1883 void fixup_rootmenu(struct menu *menu)
1886 static int menu_cnt = 0;
1888 menu->flags |= MENU_ROOT;
1889 for (child = menu->list; child; child = child->next) {
1890 if (child->prompt && child->prompt->type == P_MENU) {
1892 fixup_rootmenu(child);
1894 } else if (!menu_cnt)
1895 fixup_rootmenu(child);
1899 static const char *progname;
1901 static void usage(void)
1903 printf("%s [-s] <config>\n", progname);
1907 int main(int ac, char** av)
1909 ConfigMainWindow* v;
1913 configApp = new QApplication(ac, av);
1914 if (ac > 1 && av[1][0] == '-') {
1917 conf_set_message_callback(NULL);
1930 fixup_rootmenu(&rootmenu);
1932 //zconfdump(stdout);
1934 configSettings = new ConfigSettings();
1935 configSettings->beginGroup("/kconfig/qconf");
1936 v = new ConfigMainWindow();
1938 //zconfdump(stdout);
1939 configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
1940 configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1944 configSettings->endGroup();
1945 delete configSettings;