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>
30 static QApplication *configApp;
31 static ConfigSettings *configSettings;
33 QAction *ConfigMainWindow::saveAction;
35 static inline QString qgettext(const char* str)
37 return QString::fromLocal8Bit(str);
40 ConfigSettings::ConfigSettings()
41 : QSettings("kernel.org", "qconf")
46 * Reads a list of integer values from the application settings.
48 QList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
54 QStringList entryList = value(key).toStringList();
55 QStringList::Iterator it;
57 for (it = entryList.begin(); it != entryList.end(); ++it)
58 result.push_back((*it).toInt());
69 * Writes a list of integer values to the application settings.
71 bool ConfigSettings::writeSizes(const QString& key, const QList<int>& value)
73 QStringList stringList;
74 QList<int>::ConstIterator it;
76 for (it = value.begin(); it != value.end(); ++it)
77 stringList.push_back(QString::number(*it));
78 setValue(key, stringList);
86 * TODO check the value
88 void ConfigItem::okRename(int col)
93 * update the displayed of a menu entry
95 void ConfigItem::updateMenu(void)
99 struct property *prop;
106 setPixmap(promptColIdx, list->menuBackPix);
113 prompt = qgettext(menu_get_prompt(menu));
115 if (prop) switch (prop->type) {
117 if (list->mode == singleMode || list->mode == symbolMode) {
118 /* a menuconfig entry is displayed differently
119 * depending whether it's at the view root or a child.
121 if (sym && list->rootEntry == menu)
123 setPixmap(promptColIdx, list->menuPix);
127 setPixmap(promptColIdx, QIcon());
131 setPixmap(promptColIdx, QIcon());
139 setText(nameColIdx, QString::fromLocal8Bit(sym->name));
141 type = sym_get_type(sym);
147 if (!sym_is_changeable(sym) && list->optMode == normalOpt) {
148 setPixmap(promptColIdx, QIcon());
149 setText(noColIdx, QString());
150 setText(modColIdx, QString());
151 setText(yesColIdx, QString());
154 expr = sym_get_tristate_value(sym);
157 if (sym_is_choice_value(sym) && type == S_BOOLEAN)
158 setPixmap(promptColIdx, list->choiceYesPix);
160 setPixmap(promptColIdx, list->symbolYesPix);
161 setText(yesColIdx, "Y");
165 setPixmap(promptColIdx, list->symbolModPix);
166 setText(modColIdx, "M");
170 if (sym_is_choice_value(sym) && type == S_BOOLEAN)
171 setPixmap(promptColIdx, list->choiceNoPix);
173 setPixmap(promptColIdx, list->symbolNoPix);
174 setText(noColIdx, "N");
179 setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0);
181 setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0);
183 setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0);
185 setText(dataColIdx, QChar(ch));
192 data = sym_get_string_value(sym);
194 setText(dataColIdx, data);
195 if (type == S_STRING)
196 prompt = QString("%1: %2").arg(prompt).arg(data);
198 prompt = QString("(%2) %1").arg(prompt).arg(data);
201 if (!sym_has_value(sym) && visible)
204 setText(promptColIdx, prompt);
207 void ConfigItem::testUpdateMenu(bool v)
215 sym_calc_value(menu->sym);
216 if (menu->flags & MENU_CHANGED) {
217 /* the menu entry changed, so update all list items */
218 menu->flags &= ~MENU_CHANGED;
219 for (i = (ConfigItem*)menu->data; i; i = i->nextItem)
221 } else if (listView()->updateAll)
227 * construct a menu entry
229 void ConfigItem::init(void)
232 ConfigList* list = listView();
233 nextItem = (ConfigItem*)menu->data;
236 if (list->mode != fullMode)
238 sym_calc_value(menu->sym);
244 * destruct a menu entry
246 ConfigItem::~ConfigItem(void)
249 ConfigItem** ip = (ConfigItem**)&menu->data;
250 for (; *ip; ip = &(*ip)->nextItem) {
259 ConfigLineEdit::ConfigLineEdit(ConfigView* parent)
262 connect(this, SIGNAL(editingFinished()), SLOT(hide()));
265 void ConfigLineEdit::show(ConfigItem* i)
268 if (sym_get_string_value(item->menu->sym))
269 setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym)));
276 void ConfigLineEdit::keyPressEvent(QKeyEvent* e)
283 sym_set_string_value(item->menu->sym, text().toLatin1());
284 parent()->updateList(item);
287 Parent::keyPressEvent(e);
291 parent()->list->setFocus();
295 ConfigList::ConfigList(ConfigView* p, const char *name)
298 symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no),
299 choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no),
300 menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void),
301 showName(false), showRange(false), showData(false), mode(singleMode), optMode(normalOpt),
302 rootEntry(0), headerPopup(0)
305 setSortingEnabled(false);
306 setRootIsDecorated(true);
308 setVerticalScrollMode(ScrollPerPixel);
309 setHorizontalScrollMode(ScrollPerPixel);
311 if (mode == symbolMode)
312 setHeaderLabels(QStringList() << "Item" << "Name" << "N" << "M" << "Y" << "Value");
314 setHeaderLabels(QStringList() << "Option" << "Name" << "N" << "M" << "Y" << "Value");
316 connect(this, SIGNAL(itemSelectionChanged(void)),
317 SLOT(updateSelection(void)));
320 configSettings->beginGroup(name);
321 showName = configSettings->value("/showName", false).toBool();
322 showRange = configSettings->value("/showRange", false).toBool();
323 showData = configSettings->value("/showData", false).toBool();
324 optMode = (enum optionMode)configSettings->value("/optionMode", 0).toInt();
325 configSettings->endGroup();
326 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
329 addColumn(promptColIdx);
334 bool ConfigList::menuSkip(struct menu *menu)
336 if (optMode == normalOpt && menu_is_visible(menu))
338 if (optMode == promptOpt && menu_has_prompt(menu))
340 if (optMode == allOpt)
345 void ConfigList::reinit(void)
347 removeColumn(dataColIdx);
348 removeColumn(yesColIdx);
349 removeColumn(modColIdx);
350 removeColumn(noColIdx);
351 removeColumn(nameColIdx);
354 addColumn(nameColIdx);
357 addColumn(modColIdx);
358 addColumn(yesColIdx);
361 addColumn(dataColIdx);
366 void ConfigList::saveSettings(void)
368 if (!objectName().isEmpty()) {
369 configSettings->beginGroup(objectName());
370 configSettings->setValue("/showName", showName);
371 configSettings->setValue("/showRange", showRange);
372 configSettings->setValue("/showData", showData);
373 configSettings->setValue("/optionMode", (int)optMode);
374 configSettings->endGroup();
378 ConfigItem* ConfigList::findConfigItem(struct menu *menu)
380 ConfigItem* item = (ConfigItem*)menu->data;
382 for (; item; item = item->nextItem) {
383 if (this == item->listView())
390 void ConfigList::updateSelection(void)
395 if (mode == symbolMode)
396 setHeaderLabels(QStringList() << "Item" << "Name" << "N" << "M" << "Y" << "Value");
398 setHeaderLabels(QStringList() << "Option" << "Name" << "N" << "M" << "Y" << "Value");
400 if (selectedItems().count() == 0)
403 ConfigItem* item = (ConfigItem*)selectedItems().first();
408 emit menuChanged(menu);
411 type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
412 if (mode == menuMode && type == P_MENU)
413 emit menuSelected(menu);
416 void ConfigList::updateList(ConfigItem* item)
418 ConfigItem* last = 0;
421 if (mode != listMode)
423 QTreeWidgetItemIterator it(this);
427 item = (ConfigItem*)(*it);
430 item->testUpdateMenu(menu_is_visible(item->menu));
437 if (rootEntry != &rootmenu && (mode == singleMode ||
438 (mode == symbolMode && rootEntry->parent != &rootmenu))) {
439 item = (ConfigItem *)topLevelItem(0);
440 if (!item && mode != symbolMode) {
441 item = new ConfigItem(this, 0, true);
445 if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) &&
446 rootEntry->sym && rootEntry->prompt) {
447 item = last ? last->nextSibling() : firstChild();
449 item = new ConfigItem(this, last, rootEntry, true);
451 item->testUpdateMenu(true);
453 updateMenuList(item, rootEntry);
455 resizeColumnToContents(0);
459 updateMenuList(this, rootEntry);
461 resizeColumnToContents(0);
464 void ConfigList::setValue(ConfigItem* item, tristate val)
470 sym = item->menu ? item->menu->sym : 0;
474 type = sym_get_type(sym);
478 oldval = sym_get_tristate_value(sym);
480 if (!sym_set_tristate_value(sym, val))
482 if (oldval == no && item->menu->list)
483 item->setExpanded(true);
484 parent()->updateList(item);
489 void ConfigList::changeValue(ConfigItem* item)
493 int type, oldexpr, newexpr;
500 if (item->menu->list)
501 item->setExpanded(!item->isExpanded());
505 type = sym_get_type(sym);
509 oldexpr = sym_get_tristate_value(sym);
510 newexpr = sym_toggle_tristate_value(sym);
511 if (item->menu->list) {
512 if (oldexpr == newexpr)
513 item->setExpanded(!item->isExpanded());
514 else if (oldexpr == no)
515 item->setExpanded(true);
517 if (oldexpr != newexpr)
518 parent()->updateList(item);
523 parent()->lineEdit->show(item);
528 void ConfigList::setRootMenu(struct menu *menu)
532 if (rootEntry == menu)
534 type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
537 updateMenuList(this, 0);
541 setSelected(currentItem(), hasFocus());
542 scrollToItem(currentItem());
546 void ConfigList::setParentMenu(void)
549 struct menu *oldroot;
552 if (rootEntry == &rootmenu)
554 setRootMenu(menu_get_parent_menu(rootEntry->parent));
556 QTreeWidgetItemIterator it(this);
558 item = (ConfigItem *)(*it);
559 if (item->menu == oldroot) {
560 setCurrentItem(item);
570 * update all the children of a menu entry
571 * removes/adds the entries from the parent widget as necessary
573 * parent: either the menu list widget or a menu entry widget
574 * menu: entry to be updated
576 void ConfigList::updateMenuList(ConfigItem *parent, struct menu* menu)
585 while (parent->childCount() > 0)
587 delete parent->takeChild(0);
593 last = parent->firstChild();
594 if (last && !last->goParent)
596 for (child = menu->list; child; child = child->next) {
597 item = last ? last->nextSibling() : parent->firstChild();
598 type = child->prompt ? child->prompt->type : P_UNKNOWN;
602 if (!(child->flags & MENU_ROOT))
606 if (child->flags & MENU_ROOT)
613 visible = menu_is_visible(child);
614 if (!menuSkip(child)) {
615 if (!child->sym && !child->list && !child->prompt)
617 if (!item || item->menu != child)
618 item = new ConfigItem(parent, last, child, visible);
620 item->testUpdateMenu(visible);
622 if (mode == fullMode || mode == menuMode || type != P_MENU)
623 updateMenuList(item, child);
625 updateMenuList(item, 0);
630 if (item && item->menu == child) {
631 last = parent->firstChild();
634 else while (last->nextSibling() != item)
635 last = last->nextSibling();
641 void ConfigList::updateMenuList(ConfigList *parent, struct menu* menu)
650 while (parent->topLevelItemCount() > 0)
652 delete parent->takeTopLevelItem(0);
658 last = (ConfigItem*)parent->topLevelItem(0);
659 if (last && !last->goParent)
661 for (child = menu->list; child; child = child->next) {
662 item = last ? last->nextSibling() : (ConfigItem*)parent->topLevelItem(0);
663 type = child->prompt ? child->prompt->type : P_UNKNOWN;
667 if (!(child->flags & MENU_ROOT))
671 if (child->flags & MENU_ROOT)
678 visible = menu_is_visible(child);
679 if (!menuSkip(child)) {
680 if (!child->sym && !child->list && !child->prompt)
682 if (!item || item->menu != child)
683 item = new ConfigItem(parent, last, child, visible);
685 item->testUpdateMenu(visible);
687 if (mode == fullMode || mode == menuMode || type != P_MENU)
688 updateMenuList(item, child);
690 updateMenuList(item, 0);
695 if (item && item->menu == child) {
696 last = (ConfigItem*)parent->topLevelItem(0);
699 else while (last->nextSibling() != item)
700 last = last->nextSibling();
706 void ConfigList::keyPressEvent(QKeyEvent* ev)
708 QTreeWidgetItem* i = currentItem();
713 if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) {
714 emit parentSelected();
720 Parent::keyPressEvent(ev);
723 item = (ConfigItem*)i;
728 if (item->goParent) {
729 emit parentSelected();
735 type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
736 if (type == P_MENU && rootEntry != menu &&
737 mode != fullMode && mode != menuMode) {
738 if (mode == menuMode)
739 emit menuSelected(menu);
741 emit itemSelected(menu);
757 Parent::keyPressEvent(ev);
763 void ConfigList::mousePressEvent(QMouseEvent* e)
765 //QPoint p(contentsToViewport(e->pos()));
766 //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
767 Parent::mousePressEvent(e);
770 void ConfigList::mouseReleaseEvent(QMouseEvent* e)
773 ConfigItem* item = (ConfigItem*)itemAt(p);
775 enum prop_type ptype;
783 x = header()->offset() + p.x();
784 idx = header()->logicalIndexAt(x);
787 icon = item->pixmap(promptColIdx);
788 if (!icon.isNull()) {
789 int off = header()->sectionPosition(0) + visualRect(indexAt(p)).x() + 4; // 4 is Hardcoded image offset. There might be a way to do it properly.
790 if (x >= off && x < off + icon.availableSizes().first().width()) {
791 if (item->goParent) {
792 emit parentSelected();
796 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
797 if (ptype == P_MENU && rootEntry != menu &&
798 mode != fullMode && mode != menuMode)
799 emit menuSelected(menu);
820 //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
821 Parent::mouseReleaseEvent(e);
824 void ConfigList::mouseMoveEvent(QMouseEvent* e)
826 //QPoint p(contentsToViewport(e->pos()));
827 //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
828 Parent::mouseMoveEvent(e);
831 void ConfigList::mouseDoubleClickEvent(QMouseEvent* e)
834 ConfigItem* item = (ConfigItem*)itemAt(p);
836 enum prop_type ptype;
840 if (item->goParent) {
841 emit parentSelected();
847 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
848 if (ptype == P_MENU) {
849 if (mode == singleMode)
850 emit itemSelected(menu);
851 else if (mode == symbolMode)
852 emit menuSelected(menu);
853 } else if (menu->sym)
857 //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
858 Parent::mouseDoubleClickEvent(e);
861 void ConfigList::focusInEvent(QFocusEvent *e)
863 struct menu *menu = NULL;
865 Parent::focusInEvent(e);
867 ConfigItem* item = (ConfigItem *)currentItem();
869 setSelected(item, true);
875 void ConfigList::contextMenuEvent(QContextMenuEvent *e)
877 if (e->y() <= header()->geometry().bottom()) {
881 headerPopup = new QMenu(this);
882 action = new QAction("Show Name", this);
883 action->setCheckable(true);
884 connect(action, SIGNAL(toggled(bool)),
885 parent(), SLOT(setShowName(bool)));
886 connect(parent(), SIGNAL(showNameChanged(bool)),
887 action, SLOT(setOn(bool)));
888 action->setChecked(showName);
889 headerPopup->addAction(action);
890 action = new QAction("Show Range", this);
891 action->setCheckable(true);
892 connect(action, SIGNAL(toggled(bool)),
893 parent(), SLOT(setShowRange(bool)));
894 connect(parent(), SIGNAL(showRangeChanged(bool)),
895 action, SLOT(setOn(bool)));
896 action->setChecked(showRange);
897 headerPopup->addAction(action);
898 action = new QAction("Show Data", this);
899 action->setCheckable(true);
900 connect(action, SIGNAL(toggled(bool)),
901 parent(), SLOT(setShowData(bool)));
902 connect(parent(), SIGNAL(showDataChanged(bool)),
903 action, SLOT(setOn(bool)));
904 action->setChecked(showData);
905 headerPopup->addAction(action);
907 headerPopup->exec(e->globalPos());
913 ConfigView*ConfigView::viewList;
914 QAction *ConfigView::showNormalAction;
915 QAction *ConfigView::showAllAction;
916 QAction *ConfigView::showPromptAction;
918 ConfigView::ConfigView(QWidget* parent, const char *name)
922 QVBoxLayout *verticalLayout = new QVBoxLayout(this);
923 verticalLayout->setContentsMargins(0, 0, 0, 0);
925 list = new ConfigList(this);
926 verticalLayout->addWidget(list);
927 lineEdit = new ConfigLineEdit(this);
929 verticalLayout->addWidget(lineEdit);
931 this->nextView = viewList;
935 ConfigView::~ConfigView(void)
939 for (vp = &viewList; *vp; vp = &(*vp)->nextView) {
947 void ConfigView::setOptionMode(QAction *act)
949 if (act == showNormalAction)
950 list->optMode = normalOpt;
951 else if (act == showAllAction)
952 list->optMode = allOpt;
954 list->optMode = promptOpt;
956 list->updateListAll();
959 void ConfigView::setShowName(bool b)
961 if (list->showName != b) {
964 emit showNameChanged(b);
968 void ConfigView::setShowRange(bool b)
970 if (list->showRange != b) {
973 emit showRangeChanged(b);
977 void ConfigView::setShowData(bool b)
979 if (list->showData != b) {
982 emit showDataChanged(b);
986 void ConfigList::setAllOpen(bool open)
988 QTreeWidgetItemIterator it(this);
991 (*it)->setExpanded(open);
997 void ConfigView::updateList(ConfigItem* item)
1001 for (v = viewList; v; v = v->nextView)
1002 v->list->updateList(item);
1005 void ConfigView::updateListAll(void)
1009 for (v = viewList; v; v = v->nextView)
1010 v->list->updateListAll();
1013 ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
1014 : Parent(parent), sym(0), _menu(0)
1016 setObjectName(name);
1017 setOpenLinks(false);
1019 if (!objectName().isEmpty()) {
1020 configSettings->beginGroup(objectName());
1021 setShowDebug(configSettings->value("/showDebug", false).toBool());
1022 configSettings->endGroup();
1023 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
1027 void ConfigInfoView::saveSettings(void)
1029 if (!objectName().isEmpty()) {
1030 configSettings->beginGroup(objectName());
1031 configSettings->setValue("/showDebug", showDebug());
1032 configSettings->endGroup();
1036 void ConfigInfoView::setShowDebug(bool b)
1038 if (_showDebug != b) {
1044 emit showDebugChanged(b);
1048 void ConfigInfoView::setInfo(struct menu *m)
1060 void ConfigInfoView::symbolInfo(void)
1064 str += "<big>Symbol: <b>";
1065 str += print_filter(sym->name);
1066 str += "</b></big><br><br>value: ";
1067 str += print_filter(sym_get_string_value(sym));
1068 str += "<br>visibility: ";
1069 str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n";
1071 str += debug_info(sym);
1076 void ConfigInfoView::menuInfo(void)
1079 QString head, debug, help;
1083 if (_menu->prompt) {
1085 head += print_filter(_menu->prompt->text);
1086 head += "</b></big>";
1090 head += QString().sprintf("<a href=\"s%s\">", sym->name);
1091 head += print_filter(sym->name);
1096 } else if (sym->name) {
1099 head += QString().sprintf("<a href=\"s%s\">", sym->name);
1100 head += print_filter(sym->name);
1103 head += "</b></big>";
1108 debug = debug_info(sym);
1110 struct gstr help_gstr = str_new();
1111 menu_get_ext_help(_menu, &help_gstr);
1112 help = print_filter(str_get(&help_gstr));
1113 str_free(&help_gstr);
1114 } else if (_menu->prompt) {
1116 head += print_filter(_menu->prompt->text);
1117 head += "</b></big><br><br>";
1119 if (_menu->prompt->visible.expr) {
1120 debug += " dep: ";
1121 expr_print(_menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
1122 debug += "<br><br>";
1127 debug += QString().sprintf("defined at %s:%d<br><br>", _menu->file->name, _menu->lineno);
1129 setText(head + debug + help);
1132 QString ConfigInfoView::debug_info(struct symbol *sym)
1137 debug += print_filter(sym_type_name(sym->type));
1138 if (sym_is_choice(sym))
1139 debug += " (choice)";
1141 if (sym->rev_dep.expr) {
1142 debug += "reverse dep: ";
1143 expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
1146 for (struct property *prop = sym->prop; prop; prop = prop->next) {
1147 switch (prop->type) {
1150 debug += QString().sprintf("prompt: <a href=\"m%s\">", sym->name);
1151 debug += print_filter(prop->text);
1152 debug += "</a><br>";
1160 debug += prop_get_type_name(prop->type);
1162 expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1166 if (sym_is_choice(sym)) {
1167 debug += "choice: ";
1168 expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1173 debug += "unknown property: ";
1174 debug += prop_get_type_name(prop->type);
1177 if (prop->visible.expr) {
1178 debug += " dep: ";
1179 expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
1188 QString ConfigInfoView::print_filter(const QString &str)
1190 QRegExp re("[<>&\"\\n]");
1192 for (int i = 0; (i = res.indexOf(re, i)) >= 0;) {
1193 switch (res[i].toLatin1()) {
1195 res.replace(i, 1, "<");
1199 res.replace(i, 1, ">");
1203 res.replace(i, 1, "&");
1207 res.replace(i, 1, """);
1211 res.replace(i, 1, "<br>");
1219 void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str)
1221 QString* text = reinterpret_cast<QString*>(data);
1222 QString str2 = print_filter(str);
1224 if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
1225 *text += QString().sprintf("<a href=\"s%s\">", sym->name);
1232 void ConfigInfoView::clicked(const QUrl &url)
1234 QByteArray str = url.toEncoded();
1235 const std::size_t count = str.size();
1236 char *data = new char[count + 1];
1237 struct symbol **result;
1238 struct menu *m = NULL;
1241 qInfo() << "Clicked link is empty";
1246 memcpy(data, str.constData(), count);
1249 /* Seek for exact match */
1252 result = sym_re_search(data);
1254 qInfo() << "Clicked symbol is invalid:" << data;
1261 /* Seek for the menu which holds the symbol */
1262 for (struct property *prop = sym->prop; prop; prop = prop->next) {
1263 if (prop->type != P_PROMPT && prop->type != P_MENU)
1270 /* Symbol is not visible as a menu */
1272 emit showDebugChanged(true);
1274 emit menuSelected(m);
1281 QMenu* ConfigInfoView::createStandardContextMenu(const QPoint & pos)
1283 QMenu* popup = Parent::createStandardContextMenu(pos);
1284 QAction* action = new QAction("Show Debug Info", popup);
1286 action->setCheckable(true);
1287 connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
1288 connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
1289 action->setChecked(showDebug());
1290 popup->addSeparator();
1291 popup->addAction(action);
1295 void ConfigInfoView::contextMenuEvent(QContextMenuEvent *e)
1297 Parent::contextMenuEvent(e);
1300 ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *name)
1301 : Parent(parent), result(NULL)
1303 setObjectName(name);
1304 setWindowTitle("Search Config");
1306 QVBoxLayout* layout1 = new QVBoxLayout(this);
1307 layout1->setContentsMargins(11, 11, 11, 11);
1308 layout1->setSpacing(6);
1309 QHBoxLayout* layout2 = new QHBoxLayout(0);
1310 layout2->setContentsMargins(0, 0, 0, 0);
1311 layout2->setSpacing(6);
1312 layout2->addWidget(new QLabel("Find:", this));
1313 editField = new QLineEdit(this);
1314 connect(editField, SIGNAL(returnPressed()), SLOT(search()));
1315 layout2->addWidget(editField);
1316 searchButton = new QPushButton("Search", this);
1317 searchButton->setAutoDefault(false);
1318 connect(searchButton, SIGNAL(clicked()), SLOT(search()));
1319 layout2->addWidget(searchButton);
1320 layout1->addLayout(layout2);
1322 split = new QSplitter(this);
1323 split->setOrientation(Qt::Vertical);
1324 list = new ConfigView(split, name);
1325 list->list->mode = listMode;
1326 info = new ConfigInfoView(split, name);
1327 connect(list->list, SIGNAL(menuChanged(struct menu *)),
1328 info, SLOT(setInfo(struct menu *)));
1329 connect(list->list, SIGNAL(menuChanged(struct menu *)),
1330 parent, SLOT(setMenuLink(struct menu *)));
1332 layout1->addWidget(split);
1339 configSettings->beginGroup(name);
1340 width = configSettings->value("/window width", parent->width() / 2).toInt();
1341 height = configSettings->value("/window height", parent->height() / 2).toInt();
1342 resize(width, height);
1343 x = configSettings->value("/window x");
1344 y = configSettings->value("/window y");
1345 if ((x.isValid())&&(y.isValid()))
1346 move(x.toInt(), y.toInt());
1347 QList<int> sizes = configSettings->readSizes("/split", &ok);
1349 split->setSizes(sizes);
1350 configSettings->endGroup();
1351 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
1355 void ConfigSearchWindow::saveSettings(void)
1357 if (!objectName().isEmpty()) {
1358 configSettings->beginGroup(objectName());
1359 configSettings->setValue("/window x", pos().x());
1360 configSettings->setValue("/window y", pos().y());
1361 configSettings->setValue("/window width", size().width());
1362 configSettings->setValue("/window height", size().height());
1363 configSettings->writeSizes("/split", split->sizes());
1364 configSettings->endGroup();
1368 void ConfigSearchWindow::search(void)
1371 struct property *prop;
1372 ConfigItem *lastItem = NULL;
1375 list->list->clear();
1378 result = sym_re_search(editField->text().toLatin1());
1381 for (p = result; *p; p++) {
1382 for_all_prompts((*p), prop)
1383 lastItem = new ConfigItem(list->list, lastItem, prop->menu,
1384 menu_is_visible(prop->menu));
1389 * Construct the complete config widget
1391 ConfigMainWindow::ConfigMainWindow(void)
1400 QDesktopWidget *d = configApp->desktop();
1401 snprintf(title, sizeof(title), "%s%s",
1402 rootmenu.prompt->text,
1405 setWindowTitle(title);
1407 width = configSettings->value("/window width", d->width() - 64).toInt();
1408 height = configSettings->value("/window height", d->height() - 64).toInt();
1409 resize(width, height);
1410 x = configSettings->value("/window x");
1411 y = configSettings->value("/window y");
1412 if ((x.isValid())&&(y.isValid()))
1413 move(x.toInt(), y.toInt());
1415 QWidget *widget = new QWidget(this);
1416 QVBoxLayout *layout = new QVBoxLayout(widget);
1417 setCentralWidget(widget);
1419 split1 = new QSplitter(widget);
1420 split1->setOrientation(Qt::Horizontal);
1421 split1->setChildrenCollapsible(false);
1423 menuView = new ConfigView(widget, "menu");
1424 menuList = menuView->list;
1426 split2 = new QSplitter(widget);
1427 split2->setChildrenCollapsible(false);
1428 split2->setOrientation(Qt::Vertical);
1430 // create config tree
1431 configView = new ConfigView(widget, "config");
1432 configList = configView->list;
1434 helpText = new ConfigInfoView(widget, "help");
1436 layout->addWidget(split2);
1437 split2->addWidget(split1);
1438 split1->addWidget(configView);
1439 split1->addWidget(menuView);
1440 split2->addWidget(helpText);
1442 setTabOrder(configList, helpText);
1443 configList->setFocus();
1446 toolBar = new QToolBar("Tools", this);
1447 addToolBar(toolBar);
1449 backAction = new QAction(QPixmap(xpm_back), "Back", this);
1450 connect(backAction, SIGNAL(triggered(bool)), SLOT(goBack()));
1452 QAction *quitAction = new QAction("&Quit", this);
1453 quitAction->setShortcut(Qt::CTRL + Qt::Key_Q);
1454 connect(quitAction, SIGNAL(triggered(bool)), SLOT(close()));
1456 QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this);
1457 loadAction->setShortcut(Qt::CTRL + Qt::Key_L);
1458 connect(loadAction, SIGNAL(triggered(bool)), SLOT(loadConfig()));
1460 saveAction = new QAction(QPixmap(xpm_save), "&Save", this);
1461 saveAction->setShortcut(Qt::CTRL + Qt::Key_S);
1462 connect(saveAction, SIGNAL(triggered(bool)), SLOT(saveConfig()));
1464 conf_set_changed_callback(conf_changed);
1466 // Set saveAction's initial state
1468 configname = xstrdup(conf_get_configname());
1470 QAction *saveAsAction = new QAction("Save &As...", this);
1471 connect(saveAsAction, SIGNAL(triggered(bool)), SLOT(saveConfigAs()));
1472 QAction *searchAction = new QAction("&Find", this);
1473 searchAction->setShortcut(Qt::CTRL + Qt::Key_F);
1474 connect(searchAction, SIGNAL(triggered(bool)), SLOT(searchConfig()));
1475 singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this);
1476 singleViewAction->setCheckable(true);
1477 connect(singleViewAction, SIGNAL(triggered(bool)), SLOT(showSingleView()));
1478 splitViewAction = new QAction(QPixmap(xpm_split_view), "Split View", this);
1479 splitViewAction->setCheckable(true);
1480 connect(splitViewAction, SIGNAL(triggered(bool)), SLOT(showSplitView()));
1481 fullViewAction = new QAction(QPixmap(xpm_tree_view), "Full View", this);
1482 fullViewAction->setCheckable(true);
1483 connect(fullViewAction, SIGNAL(triggered(bool)), SLOT(showFullView()));
1485 QAction *showNameAction = new QAction("Show Name", this);
1486 showNameAction->setCheckable(true);
1487 connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
1488 showNameAction->setChecked(configView->showName());
1489 QAction *showRangeAction = new QAction("Show Range", this);
1490 showRangeAction->setCheckable(true);
1491 connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
1492 QAction *showDataAction = new QAction("Show Data", this);
1493 showDataAction->setCheckable(true);
1494 connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
1496 QActionGroup *optGroup = new QActionGroup(this);
1497 optGroup->setExclusive(true);
1498 connect(optGroup, SIGNAL(triggered(QAction*)), configView,
1499 SLOT(setOptionMode(QAction *)));
1500 connect(optGroup, SIGNAL(triggered(QAction *)), menuView,
1501 SLOT(setOptionMode(QAction *)));
1503 configView->showNormalAction = new QAction("Show Normal Options", optGroup);
1504 configView->showAllAction = new QAction("Show All Options", optGroup);
1505 configView->showPromptAction = new QAction("Show Prompt Options", optGroup);
1506 configView->showNormalAction->setCheckable(true);
1507 configView->showAllAction->setCheckable(true);
1508 configView->showPromptAction->setCheckable(true);
1510 QAction *showDebugAction = new QAction("Show Debug Info", this);
1511 showDebugAction->setCheckable(true);
1512 connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
1513 showDebugAction->setChecked(helpText->showDebug());
1515 QAction *showIntroAction = new QAction("Introduction", this);
1516 connect(showIntroAction, SIGNAL(triggered(bool)), SLOT(showIntro()));
1517 QAction *showAboutAction = new QAction("About", this);
1518 connect(showAboutAction, SIGNAL(triggered(bool)), SLOT(showAbout()));
1521 toolBar->addAction(backAction);
1522 toolBar->addSeparator();
1523 toolBar->addAction(loadAction);
1524 toolBar->addAction(saveAction);
1525 toolBar->addSeparator();
1526 toolBar->addAction(singleViewAction);
1527 toolBar->addAction(splitViewAction);
1528 toolBar->addAction(fullViewAction);
1530 // create config menu
1531 QMenu* config = menu->addMenu("&File");
1532 config->addAction(loadAction);
1533 config->addAction(saveAction);
1534 config->addAction(saveAsAction);
1535 config->addSeparator();
1536 config->addAction(quitAction);
1539 QMenu* editMenu = menu->addMenu("&Edit");
1540 editMenu->addAction(searchAction);
1542 // create options menu
1543 QMenu* optionMenu = menu->addMenu("&Option");
1544 optionMenu->addAction(showNameAction);
1545 optionMenu->addAction(showRangeAction);
1546 optionMenu->addAction(showDataAction);
1547 optionMenu->addSeparator();
1548 optionMenu->addActions(optGroup->actions());
1549 optionMenu->addSeparator();
1550 optionMenu->addAction(showDebugAction);
1553 menu->addSeparator();
1554 QMenu* helpMenu = menu->addMenu("&Help");
1555 helpMenu->addAction(showIntroAction);
1556 helpMenu->addAction(showAboutAction);
1558 connect (helpText, SIGNAL (anchorClicked (const QUrl &)),
1559 helpText, SLOT (clicked (const QUrl &)) );
1561 connect(configList, SIGNAL(menuChanged(struct menu *)),
1562 helpText, SLOT(setInfo(struct menu *)));
1563 connect(configList, SIGNAL(menuSelected(struct menu *)),
1564 SLOT(changeMenu(struct menu *)));
1565 connect(configList, SIGNAL(itemSelected(struct menu *)),
1566 SLOT(changeItens(struct menu *)));
1567 connect(configList, SIGNAL(parentSelected()),
1569 connect(menuList, SIGNAL(menuChanged(struct menu *)),
1570 helpText, SLOT(setInfo(struct menu *)));
1571 connect(menuList, SIGNAL(menuSelected(struct menu *)),
1572 SLOT(changeMenu(struct menu *)));
1574 connect(configList, SIGNAL(gotFocus(struct menu *)),
1575 helpText, SLOT(setInfo(struct menu *)));
1576 connect(menuList, SIGNAL(gotFocus(struct menu *)),
1577 helpText, SLOT(setInfo(struct menu *)));
1578 connect(menuList, SIGNAL(gotFocus(struct menu *)),
1579 SLOT(listFocusChanged(void)));
1580 connect(helpText, SIGNAL(menuSelected(struct menu *)),
1581 SLOT(setMenuLink(struct menu *)));
1583 QString listMode = configSettings->value("/listMode", "symbol").toString();
1584 if (listMode == "single")
1586 else if (listMode == "full")
1588 else /*if (listMode == "split")*/
1591 // UI setup done, restore splitter positions
1592 QList<int> sizes = configSettings->readSizes("/split1", &ok);
1594 split1->setSizes(sizes);
1596 sizes = configSettings->readSizes("/split2", &ok);
1598 split2->setSizes(sizes);
1601 void ConfigMainWindow::loadConfig(void)
1607 str = QFileDialog::getOpenFileName(this, "", configname);
1611 ba = str.toLocal8Bit();
1614 if (conf_read(name))
1615 QMessageBox::information(this, "qconf", "Unable to load configuration!");
1618 configname = xstrdup(name);
1620 ConfigView::updateListAll();
1623 bool ConfigMainWindow::saveConfig(void)
1625 if (conf_write(configname)) {
1626 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1629 conf_write_autoconf(0);
1634 void ConfigMainWindow::saveConfigAs(void)
1640 str = QFileDialog::getSaveFileName(this, "", configname);
1644 ba = str.toLocal8Bit();
1647 if (conf_write(name)) {
1648 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1650 conf_write_autoconf(0);
1653 configname = xstrdup(name);
1656 void ConfigMainWindow::searchConfig(void)
1659 searchWindow = new ConfigSearchWindow(this, "search");
1660 searchWindow->show();
1663 void ConfigMainWindow::changeItens(struct menu *menu)
1665 configList->setRootMenu(menu);
1668 void ConfigMainWindow::changeMenu(struct menu *menu)
1670 menuList->setRootMenu(menu);
1673 void ConfigMainWindow::setMenuLink(struct menu *menu)
1675 struct menu *parent;
1676 ConfigList* list = NULL;
1679 if (configList->menuSkip(menu))
1682 switch (configList->mode) {
1685 parent = menu_get_parent_menu(menu);
1688 list->setRootMenu(parent);
1691 if (menu->flags & MENU_ROOT) {
1692 menuList->setRootMenu(menu);
1693 configList->clearSelection();
1696 parent = menu_get_parent_menu(menu->parent);
1700 /* Select the config view */
1701 item = configList->findConfigItem(parent);
1703 configList->setSelected(item, true);
1704 configList->scrollToItem(item);
1707 menuList->setRootMenu(parent);
1708 menuList->clearSelection();
1720 item = list->findConfigItem(menu);
1722 list->setSelected(item, true);
1723 list->scrollToItem(item);
1725 helpText->setInfo(menu);
1730 void ConfigMainWindow::listFocusChanged(void)
1732 if (menuList->mode == menuMode)
1733 configList->clearSelection();
1736 void ConfigMainWindow::goBack(void)
1738 qInfo() << __FUNCTION__;
1739 if (configList->rootEntry == &rootmenu)
1742 configList->setParentMenu();
1745 void ConfigMainWindow::showSingleView(void)
1747 singleViewAction->setEnabled(false);
1748 singleViewAction->setChecked(true);
1749 splitViewAction->setEnabled(true);
1750 splitViewAction->setChecked(false);
1751 fullViewAction->setEnabled(true);
1752 fullViewAction->setChecked(false);
1754 backAction->setEnabled(true);
1757 menuList->setRootMenu(0);
1758 configList->mode = singleMode;
1759 if (configList->rootEntry == &rootmenu)
1760 configList->updateListAll();
1762 configList->setRootMenu(&rootmenu);
1763 configList->setFocus();
1766 void ConfigMainWindow::showSplitView(void)
1768 singleViewAction->setEnabled(true);
1769 singleViewAction->setChecked(false);
1770 splitViewAction->setEnabled(false);
1771 splitViewAction->setChecked(true);
1772 fullViewAction->setEnabled(true);
1773 fullViewAction->setChecked(false);
1775 backAction->setEnabled(false);
1777 configList->mode = menuMode;
1778 if (configList->rootEntry == &rootmenu)
1779 configList->updateListAll();
1781 configList->setRootMenu(&rootmenu);
1782 configList->setAllOpen(true);
1783 configApp->processEvents();
1784 menuList->mode = symbolMode;
1785 menuList->setRootMenu(&rootmenu);
1786 menuList->setAllOpen(true);
1788 menuList->setFocus();
1791 void ConfigMainWindow::showFullView(void)
1793 singleViewAction->setEnabled(true);
1794 singleViewAction->setChecked(false);
1795 splitViewAction->setEnabled(true);
1796 splitViewAction->setChecked(false);
1797 fullViewAction->setEnabled(false);
1798 fullViewAction->setChecked(true);
1800 backAction->setEnabled(false);
1803 menuList->setRootMenu(0);
1804 configList->mode = fullMode;
1805 if (configList->rootEntry == &rootmenu)
1806 configList->updateListAll();
1808 configList->setRootMenu(&rootmenu);
1809 configList->setFocus();
1813 * ask for saving configuration before quitting
1815 void ConfigMainWindow::closeEvent(QCloseEvent* e)
1817 if (!conf_get_changed()) {
1821 QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning,
1822 QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
1823 mb.setButtonText(QMessageBox::Yes, "&Save Changes");
1824 mb.setButtonText(QMessageBox::No, "&Discard Changes");
1825 mb.setButtonText(QMessageBox::Cancel, "Cancel Exit");
1826 switch (mb.exec()) {
1827 case QMessageBox::Yes:
1833 case QMessageBox::No:
1836 case QMessageBox::Cancel:
1842 void ConfigMainWindow::showIntro(void)
1844 static const QString str = "Welcome to the qconf graphical configuration tool.\n\n"
1845 "For each option, a blank box indicates the feature is disabled, a check\n"
1846 "indicates it is enabled, and a dot indicates that it is to be compiled\n"
1847 "as a module. Clicking on the box will cycle through the three states.\n\n"
1848 "If you do not see an option (e.g., a device driver) that you believe\n"
1849 "should be present, try turning on Show All Options under the Options menu.\n"
1850 "Although there is no cross reference yet to help you figure out what other\n"
1851 "options must be enabled to support the option you are interested in, you can\n"
1852 "still view the help of a grayed-out option.\n\n"
1853 "Toggling Show Debug Info under the Options menu will show the dependencies,\n"
1854 "which you can then match by examining other options.\n\n";
1856 QMessageBox::information(this, "qconf", str);
1859 void ConfigMainWindow::showAbout(void)
1861 static const QString str = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n"
1862 "Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>.\n\n"
1863 "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n";
1865 QMessageBox::information(this, "qconf", str);
1868 void ConfigMainWindow::saveSettings(void)
1870 configSettings->setValue("/window x", pos().x());
1871 configSettings->setValue("/window y", pos().y());
1872 configSettings->setValue("/window width", size().width());
1873 configSettings->setValue("/window height", size().height());
1876 switch(configList->mode) {
1892 configSettings->setValue("/listMode", entry);
1894 configSettings->writeSizes("/split1", split1->sizes());
1895 configSettings->writeSizes("/split2", split2->sizes());
1898 void ConfigMainWindow::conf_changed(void)
1901 saveAction->setEnabled(conf_get_changed());
1904 void fixup_rootmenu(struct menu *menu)
1907 static int menu_cnt = 0;
1909 menu->flags |= MENU_ROOT;
1910 for (child = menu->list; child; child = child->next) {
1911 if (child->prompt && child->prompt->type == P_MENU) {
1913 fixup_rootmenu(child);
1915 } else if (!menu_cnt)
1916 fixup_rootmenu(child);
1920 static const char *progname;
1922 static void usage(void)
1924 printf("%s [-s] <config>\n", progname);
1928 int main(int ac, char** av)
1930 ConfigMainWindow* v;
1934 configApp = new QApplication(ac, av);
1935 if (ac > 1 && av[1][0] == '-') {
1938 conf_set_message_callback(NULL);
1951 fixup_rootmenu(&rootmenu);
1953 //zconfdump(stdout);
1955 configSettings = new ConfigSettings();
1956 configSettings->beginGroup("/kconfig/qconf");
1957 v = new ConfigMainWindow();
1959 //zconfdump(stdout);
1960 configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
1961 configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1965 configSettings->endGroup();
1966 delete configSettings;