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)
789 emit menuSelected(menu);
810 //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
811 Parent::mouseReleaseEvent(e);
814 void ConfigList::mouseMoveEvent(QMouseEvent* e)
816 //QPoint p(contentsToViewport(e->pos()));
817 //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
818 Parent::mouseMoveEvent(e);
821 void ConfigList::mouseDoubleClickEvent(QMouseEvent* e)
824 ConfigItem* item = (ConfigItem*)itemAt(p);
826 enum prop_type ptype;
830 if (item->goParent) {
831 emit parentSelected();
837 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
838 if (ptype == P_MENU) {
839 if (mode == singleMode)
840 emit itemSelected(menu);
841 else if (mode == symbolMode)
842 emit menuSelected(menu);
843 } else if (menu->sym)
847 //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
848 Parent::mouseDoubleClickEvent(e);
851 void ConfigList::focusInEvent(QFocusEvent *e)
853 struct menu *menu = NULL;
855 Parent::focusInEvent(e);
857 ConfigItem* item = (ConfigItem *)currentItem();
859 setSelected(item, true);
865 void ConfigList::contextMenuEvent(QContextMenuEvent *e)
867 if (e->y() <= header()->geometry().bottom()) {
871 headerPopup = new QMenu(this);
872 action = new QAction("Show Name", this);
873 action->setCheckable(true);
874 connect(action, SIGNAL(toggled(bool)),
875 parent(), SLOT(setShowName(bool)));
876 connect(parent(), SIGNAL(showNameChanged(bool)),
877 action, SLOT(setOn(bool)));
878 action->setChecked(showName);
879 headerPopup->addAction(action);
880 action = new QAction("Show Range", this);
881 action->setCheckable(true);
882 connect(action, SIGNAL(toggled(bool)),
883 parent(), SLOT(setShowRange(bool)));
884 connect(parent(), SIGNAL(showRangeChanged(bool)),
885 action, SLOT(setOn(bool)));
886 action->setChecked(showRange);
887 headerPopup->addAction(action);
888 action = new QAction("Show Data", this);
889 action->setCheckable(true);
890 connect(action, SIGNAL(toggled(bool)),
891 parent(), SLOT(setShowData(bool)));
892 connect(parent(), SIGNAL(showDataChanged(bool)),
893 action, SLOT(setOn(bool)));
894 action->setChecked(showData);
895 headerPopup->addAction(action);
897 headerPopup->exec(e->globalPos());
903 ConfigView*ConfigView::viewList;
904 QAction *ConfigView::showNormalAction;
905 QAction *ConfigView::showAllAction;
906 QAction *ConfigView::showPromptAction;
908 ConfigView::ConfigView(QWidget* parent, const char *name)
912 QVBoxLayout *verticalLayout = new QVBoxLayout(this);
913 verticalLayout->setContentsMargins(0, 0, 0, 0);
915 list = new ConfigList(this);
916 verticalLayout->addWidget(list);
917 lineEdit = new ConfigLineEdit(this);
919 verticalLayout->addWidget(lineEdit);
921 this->nextView = viewList;
925 ConfigView::~ConfigView(void)
929 for (vp = &viewList; *vp; vp = &(*vp)->nextView) {
937 void ConfigView::setOptionMode(QAction *act)
939 if (act == showNormalAction)
940 list->optMode = normalOpt;
941 else if (act == showAllAction)
942 list->optMode = allOpt;
944 list->optMode = promptOpt;
946 list->updateListAll();
949 void ConfigView::setShowName(bool b)
951 if (list->showName != b) {
954 emit showNameChanged(b);
958 void ConfigView::setShowRange(bool b)
960 if (list->showRange != b) {
963 emit showRangeChanged(b);
967 void ConfigView::setShowData(bool b)
969 if (list->showData != b) {
972 emit showDataChanged(b);
976 void ConfigList::setAllOpen(bool open)
978 QTreeWidgetItemIterator it(this);
981 (*it)->setExpanded(open);
987 void ConfigView::updateList(ConfigItem* item)
991 for (v = viewList; v; v = v->nextView)
992 v->list->updateList(item);
995 void ConfigView::updateListAll(void)
999 for (v = viewList; v; v = v->nextView)
1000 v->list->updateListAll();
1003 ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
1004 : Parent(parent), sym(0), _menu(0)
1006 setObjectName(name);
1007 setOpenLinks(false);
1009 if (!objectName().isEmpty()) {
1010 configSettings->beginGroup(objectName());
1011 setShowDebug(configSettings->value("/showDebug", false).toBool());
1012 configSettings->endGroup();
1013 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
1017 void ConfigInfoView::saveSettings(void)
1019 if (!objectName().isEmpty()) {
1020 configSettings->beginGroup(objectName());
1021 configSettings->setValue("/showDebug", showDebug());
1022 configSettings->endGroup();
1026 void ConfigInfoView::setShowDebug(bool b)
1028 if (_showDebug != b) {
1034 emit showDebugChanged(b);
1038 void ConfigInfoView::setInfo(struct menu *m)
1050 void ConfigInfoView::symbolInfo(void)
1054 str += "<big>Symbol: <b>";
1055 str += print_filter(sym->name);
1056 str += "</b></big><br><br>value: ";
1057 str += print_filter(sym_get_string_value(sym));
1058 str += "<br>visibility: ";
1059 str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n";
1061 str += debug_info(sym);
1066 void ConfigInfoView::menuInfo(void)
1069 QString head, debug, help;
1073 if (_menu->prompt) {
1075 head += print_filter(_menu->prompt->text);
1076 head += "</b></big>";
1080 head += QString().sprintf("<a href=\"s%s\">", sym->name);
1081 head += print_filter(sym->name);
1086 } else if (sym->name) {
1089 head += QString().sprintf("<a href=\"s%s\">", sym->name);
1090 head += print_filter(sym->name);
1093 head += "</b></big>";
1098 debug = debug_info(sym);
1100 struct gstr help_gstr = str_new();
1101 menu_get_ext_help(_menu, &help_gstr);
1102 help = print_filter(str_get(&help_gstr));
1103 str_free(&help_gstr);
1104 } else if (_menu->prompt) {
1106 head += print_filter(_menu->prompt->text);
1107 head += "</b></big><br><br>";
1109 if (_menu->prompt->visible.expr) {
1110 debug += " dep: ";
1111 expr_print(_menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
1112 debug += "<br><br>";
1117 debug += QString().sprintf("defined at %s:%d<br><br>", _menu->file->name, _menu->lineno);
1119 setText(head + debug + help);
1122 QString ConfigInfoView::debug_info(struct symbol *sym)
1127 debug += print_filter(sym_type_name(sym->type));
1128 if (sym_is_choice(sym))
1129 debug += " (choice)";
1131 if (sym->rev_dep.expr) {
1132 debug += "reverse dep: ";
1133 expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
1136 for (struct property *prop = sym->prop; prop; prop = prop->next) {
1137 switch (prop->type) {
1140 debug += QString().sprintf("prompt: <a href=\"m%s\">", sym->name);
1141 debug += print_filter(prop->text);
1142 debug += "</a><br>";
1150 debug += prop_get_type_name(prop->type);
1152 expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1156 if (sym_is_choice(sym)) {
1157 debug += "choice: ";
1158 expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1163 debug += "unknown property: ";
1164 debug += prop_get_type_name(prop->type);
1167 if (prop->visible.expr) {
1168 debug += " dep: ";
1169 expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
1178 QString ConfigInfoView::print_filter(const QString &str)
1180 QRegExp re("[<>&\"\\n]");
1182 for (int i = 0; (i = res.indexOf(re, i)) >= 0;) {
1183 switch (res[i].toLatin1()) {
1185 res.replace(i, 1, "<");
1189 res.replace(i, 1, ">");
1193 res.replace(i, 1, "&");
1197 res.replace(i, 1, """);
1201 res.replace(i, 1, "<br>");
1209 void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str)
1211 QString* text = reinterpret_cast<QString*>(data);
1212 QString str2 = print_filter(str);
1214 if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
1215 *text += QString().sprintf("<a href=\"s%s\">", sym->name);
1222 void ConfigInfoView::clicked(const QUrl &url)
1224 QByteArray str = url.toEncoded();
1225 const std::size_t count = str.size();
1226 char *data = new char[count + 1];
1227 struct symbol **result;
1228 struct menu *m = NULL;
1231 qInfo() << "Clicked link is empty";
1236 memcpy(data, str.constData(), count);
1239 /* Seek for exact match */
1242 result = sym_re_search(data);
1244 qInfo() << "Clicked symbol is invalid:" << data;
1251 /* Seek for the menu which holds the symbol */
1252 for (struct property *prop = sym->prop; prop; prop = prop->next) {
1253 if (prop->type != P_PROMPT && prop->type != P_MENU)
1260 /* Symbol is not visible as a menu */
1262 emit showDebugChanged(true);
1264 emit menuSelected(m);
1271 QMenu* ConfigInfoView::createStandardContextMenu(const QPoint & pos)
1273 QMenu* popup = Parent::createStandardContextMenu(pos);
1274 QAction* action = new QAction("Show Debug Info", popup);
1276 action->setCheckable(true);
1277 connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
1278 connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
1279 action->setChecked(showDebug());
1280 popup->addSeparator();
1281 popup->addAction(action);
1285 void ConfigInfoView::contextMenuEvent(QContextMenuEvent *e)
1287 Parent::contextMenuEvent(e);
1290 ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *name)
1291 : Parent(parent), result(NULL)
1293 setObjectName(name);
1294 setWindowTitle("Search Config");
1296 QVBoxLayout* layout1 = new QVBoxLayout(this);
1297 layout1->setContentsMargins(11, 11, 11, 11);
1298 layout1->setSpacing(6);
1299 QHBoxLayout* layout2 = new QHBoxLayout(0);
1300 layout2->setContentsMargins(0, 0, 0, 0);
1301 layout2->setSpacing(6);
1302 layout2->addWidget(new QLabel("Find:", this));
1303 editField = new QLineEdit(this);
1304 connect(editField, SIGNAL(returnPressed()), SLOT(search()));
1305 layout2->addWidget(editField);
1306 searchButton = new QPushButton("Search", this);
1307 searchButton->setAutoDefault(false);
1308 connect(searchButton, SIGNAL(clicked()), SLOT(search()));
1309 layout2->addWidget(searchButton);
1310 layout1->addLayout(layout2);
1312 split = new QSplitter(this);
1313 split->setOrientation(Qt::Vertical);
1314 list = new ConfigView(split, name);
1315 list->list->mode = listMode;
1316 info = new ConfigInfoView(split, name);
1317 connect(list->list, SIGNAL(menuChanged(struct menu *)),
1318 info, SLOT(setInfo(struct menu *)));
1319 connect(list->list, SIGNAL(menuChanged(struct menu *)),
1320 parent, SLOT(setMenuLink(struct menu *)));
1322 layout1->addWidget(split);
1329 configSettings->beginGroup(name);
1330 width = configSettings->value("/window width", parent->width() / 2).toInt();
1331 height = configSettings->value("/window height", parent->height() / 2).toInt();
1332 resize(width, height);
1333 x = configSettings->value("/window x");
1334 y = configSettings->value("/window y");
1335 if ((x.isValid())&&(y.isValid()))
1336 move(x.toInt(), y.toInt());
1337 QList<int> sizes = configSettings->readSizes("/split", &ok);
1339 split->setSizes(sizes);
1340 configSettings->endGroup();
1341 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
1345 void ConfigSearchWindow::saveSettings(void)
1347 if (!objectName().isEmpty()) {
1348 configSettings->beginGroup(objectName());
1349 configSettings->setValue("/window x", pos().x());
1350 configSettings->setValue("/window y", pos().y());
1351 configSettings->setValue("/window width", size().width());
1352 configSettings->setValue("/window height", size().height());
1353 configSettings->writeSizes("/split", split->sizes());
1354 configSettings->endGroup();
1358 void ConfigSearchWindow::search(void)
1361 struct property *prop;
1362 ConfigItem *lastItem = NULL;
1365 list->list->clear();
1368 result = sym_re_search(editField->text().toLatin1());
1371 for (p = result; *p; p++) {
1372 for_all_prompts((*p), prop)
1373 lastItem = new ConfigItem(list->list, lastItem, prop->menu,
1374 menu_is_visible(prop->menu));
1379 * Construct the complete config widget
1381 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();
1436 toolBar = new QToolBar("Tools", this);
1437 addToolBar(toolBar);
1439 backAction = new QAction(QPixmap(xpm_back), "Back", this);
1440 connect(backAction, SIGNAL(triggered(bool)), SLOT(goBack()));
1442 QAction *quitAction = new QAction("&Quit", this);
1443 quitAction->setShortcut(Qt::CTRL + Qt::Key_Q);
1444 connect(quitAction, SIGNAL(triggered(bool)), SLOT(close()));
1446 QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this);
1447 loadAction->setShortcut(Qt::CTRL + Qt::Key_L);
1448 connect(loadAction, SIGNAL(triggered(bool)), SLOT(loadConfig()));
1450 saveAction = new QAction(QPixmap(xpm_save), "&Save", this);
1451 saveAction->setShortcut(Qt::CTRL + Qt::Key_S);
1452 connect(saveAction, SIGNAL(triggered(bool)), SLOT(saveConfig()));
1454 conf_set_changed_callback(conf_changed);
1456 // Set saveAction's initial state
1458 configname = xstrdup(conf_get_configname());
1460 QAction *saveAsAction = new QAction("Save &As...", this);
1461 connect(saveAsAction, SIGNAL(triggered(bool)), SLOT(saveConfigAs()));
1462 QAction *searchAction = new QAction("&Find", this);
1463 searchAction->setShortcut(Qt::CTRL + Qt::Key_F);
1464 connect(searchAction, SIGNAL(triggered(bool)), SLOT(searchConfig()));
1465 singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this);
1466 singleViewAction->setCheckable(true);
1467 connect(singleViewAction, SIGNAL(triggered(bool)), SLOT(showSingleView()));
1468 splitViewAction = new QAction(QPixmap(xpm_split_view), "Split View", this);
1469 splitViewAction->setCheckable(true);
1470 connect(splitViewAction, SIGNAL(triggered(bool)), SLOT(showSplitView()));
1471 fullViewAction = new QAction(QPixmap(xpm_tree_view), "Full View", this);
1472 fullViewAction->setCheckable(true);
1473 connect(fullViewAction, SIGNAL(triggered(bool)), SLOT(showFullView()));
1475 QAction *showNameAction = new QAction("Show Name", this);
1476 showNameAction->setCheckable(true);
1477 connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
1478 showNameAction->setChecked(configView->showName());
1479 QAction *showRangeAction = new QAction("Show Range", this);
1480 showRangeAction->setCheckable(true);
1481 connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
1482 QAction *showDataAction = new QAction("Show Data", this);
1483 showDataAction->setCheckable(true);
1484 connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
1486 QActionGroup *optGroup = new QActionGroup(this);
1487 optGroup->setExclusive(true);
1488 connect(optGroup, SIGNAL(triggered(QAction*)), configView,
1489 SLOT(setOptionMode(QAction *)));
1490 connect(optGroup, SIGNAL(triggered(QAction *)), menuView,
1491 SLOT(setOptionMode(QAction *)));
1493 configView->showNormalAction = new QAction("Show Normal Options", optGroup);
1494 configView->showAllAction = new QAction("Show All Options", optGroup);
1495 configView->showPromptAction = new QAction("Show Prompt Options", optGroup);
1496 configView->showNormalAction->setCheckable(true);
1497 configView->showAllAction->setCheckable(true);
1498 configView->showPromptAction->setCheckable(true);
1500 QAction *showDebugAction = new QAction("Show Debug Info", this);
1501 showDebugAction->setCheckable(true);
1502 connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
1503 showDebugAction->setChecked(helpText->showDebug());
1505 QAction *showIntroAction = new QAction("Introduction", this);
1506 connect(showIntroAction, SIGNAL(triggered(bool)), SLOT(showIntro()));
1507 QAction *showAboutAction = new QAction("About", this);
1508 connect(showAboutAction, SIGNAL(triggered(bool)), SLOT(showAbout()));
1511 toolBar->addAction(backAction);
1512 toolBar->addSeparator();
1513 toolBar->addAction(loadAction);
1514 toolBar->addAction(saveAction);
1515 toolBar->addSeparator();
1516 toolBar->addAction(singleViewAction);
1517 toolBar->addAction(splitViewAction);
1518 toolBar->addAction(fullViewAction);
1520 // create config menu
1521 QMenu* config = menu->addMenu("&File");
1522 config->addAction(loadAction);
1523 config->addAction(saveAction);
1524 config->addAction(saveAsAction);
1525 config->addSeparator();
1526 config->addAction(quitAction);
1529 QMenu* editMenu = menu->addMenu("&Edit");
1530 editMenu->addAction(searchAction);
1532 // create options menu
1533 QMenu* optionMenu = menu->addMenu("&Option");
1534 optionMenu->addAction(showNameAction);
1535 optionMenu->addAction(showRangeAction);
1536 optionMenu->addAction(showDataAction);
1537 optionMenu->addSeparator();
1538 optionMenu->addActions(optGroup->actions());
1539 optionMenu->addSeparator();
1540 optionMenu->addAction(showDebugAction);
1543 menu->addSeparator();
1544 QMenu* helpMenu = menu->addMenu("&Help");
1545 helpMenu->addAction(showIntroAction);
1546 helpMenu->addAction(showAboutAction);
1548 connect (helpText, SIGNAL (anchorClicked (const QUrl &)),
1549 helpText, SLOT (clicked (const QUrl &)) );
1551 connect(configList, SIGNAL(menuChanged(struct menu *)),
1552 helpText, SLOT(setInfo(struct menu *)));
1553 connect(configList, SIGNAL(menuSelected(struct menu *)),
1554 SLOT(changeMenu(struct menu *)));
1555 connect(configList, SIGNAL(itemSelected(struct menu *)),
1556 SLOT(changeItens(struct menu *)));
1557 connect(configList, SIGNAL(parentSelected()),
1559 connect(menuList, SIGNAL(menuChanged(struct menu *)),
1560 helpText, SLOT(setInfo(struct menu *)));
1561 connect(menuList, SIGNAL(menuSelected(struct menu *)),
1562 SLOT(changeMenu(struct menu *)));
1564 connect(configList, SIGNAL(gotFocus(struct menu *)),
1565 helpText, SLOT(setInfo(struct menu *)));
1566 connect(menuList, SIGNAL(gotFocus(struct menu *)),
1567 helpText, SLOT(setInfo(struct menu *)));
1568 connect(menuList, SIGNAL(gotFocus(struct menu *)),
1569 SLOT(listFocusChanged(void)));
1570 connect(helpText, SIGNAL(menuSelected(struct menu *)),
1571 SLOT(setMenuLink(struct menu *)));
1573 QString listMode = configSettings->value("/listMode", "symbol").toString();
1574 if (listMode == "single")
1576 else if (listMode == "full")
1578 else /*if (listMode == "split")*/
1581 // UI setup done, restore splitter positions
1582 QList<int> sizes = configSettings->readSizes("/split1", &ok);
1584 split1->setSizes(sizes);
1586 sizes = configSettings->readSizes("/split2", &ok);
1588 split2->setSizes(sizes);
1591 void ConfigMainWindow::loadConfig(void)
1597 str = QFileDialog::getOpenFileName(this, "", configname);
1601 ba = str.toLocal8Bit();
1604 if (conf_read(name))
1605 QMessageBox::information(this, "qconf", "Unable to load configuration!");
1608 configname = xstrdup(name);
1610 ConfigView::updateListAll();
1613 bool ConfigMainWindow::saveConfig(void)
1615 if (conf_write(configname)) {
1616 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1619 conf_write_autoconf(0);
1624 void ConfigMainWindow::saveConfigAs(void)
1630 str = QFileDialog::getSaveFileName(this, "", configname);
1634 ba = str.toLocal8Bit();
1637 if (conf_write(name)) {
1638 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1640 conf_write_autoconf(0);
1643 configname = xstrdup(name);
1646 void ConfigMainWindow::searchConfig(void)
1649 searchWindow = new ConfigSearchWindow(this, "search");
1650 searchWindow->show();
1653 void ConfigMainWindow::changeItens(struct menu *menu)
1655 configList->setRootMenu(menu);
1658 void ConfigMainWindow::changeMenu(struct menu *menu)
1660 menuList->setRootMenu(menu);
1663 void ConfigMainWindow::setMenuLink(struct menu *menu)
1665 struct menu *parent;
1666 ConfigList* list = NULL;
1669 if (configList->menuSkip(menu))
1672 switch (configList->mode) {
1675 parent = menu_get_parent_menu(menu);
1678 list->setRootMenu(parent);
1681 if (menu->flags & MENU_ROOT) {
1682 menuList->setRootMenu(menu);
1683 configList->clearSelection();
1686 parent = menu_get_parent_menu(menu->parent);
1690 /* Select the config view */
1691 item = configList->findConfigItem(parent);
1693 configList->setSelected(item, true);
1694 configList->scrollToItem(item);
1697 menuList->setRootMenu(parent);
1698 menuList->clearSelection();
1710 item = list->findConfigItem(menu);
1712 list->setSelected(item, true);
1713 list->scrollToItem(item);
1715 helpText->setInfo(menu);
1720 void ConfigMainWindow::listFocusChanged(void)
1722 if (menuList->mode == menuMode)
1723 configList->clearSelection();
1726 void ConfigMainWindow::goBack(void)
1728 if (configList->rootEntry == &rootmenu)
1731 configList->setParentMenu();
1734 void ConfigMainWindow::showSingleView(void)
1736 singleViewAction->setEnabled(false);
1737 singleViewAction->setChecked(true);
1738 splitViewAction->setEnabled(true);
1739 splitViewAction->setChecked(false);
1740 fullViewAction->setEnabled(true);
1741 fullViewAction->setChecked(false);
1743 backAction->setEnabled(true);
1746 menuList->setRootMenu(0);
1747 configList->mode = singleMode;
1748 if (configList->rootEntry == &rootmenu)
1749 configList->updateListAll();
1751 configList->setRootMenu(&rootmenu);
1752 configList->setFocus();
1755 void ConfigMainWindow::showSplitView(void)
1757 singleViewAction->setEnabled(true);
1758 singleViewAction->setChecked(false);
1759 splitViewAction->setEnabled(false);
1760 splitViewAction->setChecked(true);
1761 fullViewAction->setEnabled(true);
1762 fullViewAction->setChecked(false);
1764 backAction->setEnabled(false);
1766 configList->mode = menuMode;
1767 if (configList->rootEntry == &rootmenu)
1768 configList->updateListAll();
1770 configList->setRootMenu(&rootmenu);
1771 configList->setAllOpen(true);
1772 configApp->processEvents();
1773 menuList->mode = symbolMode;
1774 menuList->setRootMenu(&rootmenu);
1775 menuList->setAllOpen(true);
1777 menuList->setFocus();
1780 void ConfigMainWindow::showFullView(void)
1782 singleViewAction->setEnabled(true);
1783 singleViewAction->setChecked(false);
1784 splitViewAction->setEnabled(true);
1785 splitViewAction->setChecked(false);
1786 fullViewAction->setEnabled(false);
1787 fullViewAction->setChecked(true);
1789 backAction->setEnabled(false);
1792 menuList->setRootMenu(0);
1793 configList->mode = fullMode;
1794 if (configList->rootEntry == &rootmenu)
1795 configList->updateListAll();
1797 configList->setRootMenu(&rootmenu);
1798 configList->setFocus();
1802 * ask for saving configuration before quitting
1804 void ConfigMainWindow::closeEvent(QCloseEvent* e)
1806 if (!conf_get_changed()) {
1810 QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning,
1811 QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
1812 mb.setButtonText(QMessageBox::Yes, "&Save Changes");
1813 mb.setButtonText(QMessageBox::No, "&Discard Changes");
1814 mb.setButtonText(QMessageBox::Cancel, "Cancel Exit");
1815 switch (mb.exec()) {
1816 case QMessageBox::Yes:
1822 case QMessageBox::No:
1825 case QMessageBox::Cancel:
1831 void ConfigMainWindow::showIntro(void)
1833 static const QString str = "Welcome to the qconf graphical configuration tool.\n\n"
1834 "For each option, a blank box indicates the feature is disabled, a check\n"
1835 "indicates it is enabled, and a dot indicates that it is to be compiled\n"
1836 "as a module. Clicking on the box will cycle through the three states.\n\n"
1837 "If you do not see an option (e.g., a device driver) that you believe\n"
1838 "should be present, try turning on Show All Options under the Options menu.\n"
1839 "Although there is no cross reference yet to help you figure out what other\n"
1840 "options must be enabled to support the option you are interested in, you can\n"
1841 "still view the help of a grayed-out option.\n\n"
1842 "Toggling Show Debug Info under the Options menu will show the dependencies,\n"
1843 "which you can then match by examining other options.\n\n";
1845 QMessageBox::information(this, "qconf", str);
1848 void ConfigMainWindow::showAbout(void)
1850 static const QString str = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n"
1851 "Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>.\n\n"
1852 "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n";
1854 QMessageBox::information(this, "qconf", str);
1857 void ConfigMainWindow::saveSettings(void)
1859 configSettings->setValue("/window x", pos().x());
1860 configSettings->setValue("/window y", pos().y());
1861 configSettings->setValue("/window width", size().width());
1862 configSettings->setValue("/window height", size().height());
1865 switch(configList->mode) {
1881 configSettings->setValue("/listMode", entry);
1883 configSettings->writeSizes("/split1", split1->sizes());
1884 configSettings->writeSizes("/split2", split2->sizes());
1887 void ConfigMainWindow::conf_changed(void)
1890 saveAction->setEnabled(conf_get_changed());
1893 void fixup_rootmenu(struct menu *menu)
1896 static int menu_cnt = 0;
1898 menu->flags |= MENU_ROOT;
1899 for (child = menu->list; child; child = child->next) {
1900 if (child->prompt && child->prompt->type == P_MENU) {
1902 fixup_rootmenu(child);
1904 } else if (!menu_cnt)
1905 fixup_rootmenu(child);
1909 static const char *progname;
1911 static void usage(void)
1913 printf("%s [-s] <config>\n", progname);
1917 int main(int ac, char** av)
1919 ConfigMainWindow* v;
1923 configApp = new QApplication(ac, av);
1924 if (ac > 1 && av[1][0] == '-') {
1927 conf_set_message_callback(NULL);
1940 fixup_rootmenu(&rootmenu);
1942 //zconfdump(stdout);
1944 configSettings = new ConfigSettings();
1945 configSettings->beginGroup("/kconfig/qconf");
1946 v = new ConfigMainWindow();
1948 //zconfdump(stdout);
1949 configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
1950 configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1954 configSettings->endGroup();
1955 delete configSettings;