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 <QActionGroup>
9 #include <QApplication>
10 #include <QCloseEvent>
12 #include <QFileDialog>
18 #include <QMessageBox>
19 #include <QRegularExpression>
32 static QApplication
*configApp
;
33 static ConfigSettings
*configSettings
;
35 QAction
*ConfigMainWindow::saveAction
;
37 ConfigSettings::ConfigSettings()
38 : QSettings("kernel.org", "qconf")
43 * Reads a list of integer values from the application settings.
45 QList
<int> ConfigSettings::readSizes(const QString
& key
, bool *ok
)
51 QStringList entryList
= value(key
).toStringList();
52 QStringList::Iterator it
;
54 for (it
= entryList
.begin(); it
!= entryList
.end(); ++it
)
55 result
.push_back((*it
).toInt());
66 * Writes a list of integer values to the application settings.
68 bool ConfigSettings::writeSizes(const QString
& key
, const QList
<int>& value
)
70 QStringList stringList
;
71 QList
<int>::ConstIterator it
;
73 for (it
= value
.begin(); it
!= value
.end(); ++it
)
74 stringList
.push_back(QString::number(*it
));
75 setValue(key
, stringList
);
80 QIcon
ConfigItem::symbolYesIcon
;
81 QIcon
ConfigItem::symbolModIcon
;
82 QIcon
ConfigItem::symbolNoIcon
;
83 QIcon
ConfigItem::choiceYesIcon
;
84 QIcon
ConfigItem::choiceNoIcon
;
85 QIcon
ConfigItem::menuIcon
;
86 QIcon
ConfigItem::menubackIcon
;
89 * update the displayed of a menu entry
91 void ConfigItem::updateMenu(void)
95 struct property
*prop
;
102 setIcon(promptColIdx
, menubackIcon
);
109 prompt
= menu_get_prompt(menu
);
111 if (prop
) switch (prop
->type
) {
113 if (list
->mode
== singleMode
) {
114 /* a menuconfig entry is displayed differently
115 * depending whether it's at the view root or a child.
117 if (sym
&& list
->rootEntry
== menu
)
119 setIcon(promptColIdx
, menuIcon
);
123 setIcon(promptColIdx
, QIcon());
127 setIcon(promptColIdx
, QIcon());
128 prompt
= "*** " + prompt
+ " ***";
136 setText(nameColIdx
, sym
->name
);
138 type
= sym_get_type(sym
);
144 if (!sym_is_changeable(sym
) && list
->optMode
== normalOpt
) {
145 setIcon(promptColIdx
, QIcon());
148 expr
= sym_get_tristate_value(sym
);
151 if (sym_is_choice_value(sym
))
152 setIcon(promptColIdx
, choiceYesIcon
);
154 setIcon(promptColIdx
, symbolYesIcon
);
158 setIcon(promptColIdx
, symbolModIcon
);
162 if (sym_is_choice_value(sym
))
163 setIcon(promptColIdx
, choiceNoIcon
);
165 setIcon(promptColIdx
, symbolNoIcon
);
170 setText(dataColIdx
, QChar(ch
));
175 setText(dataColIdx
, sym_get_string_value(sym
));
178 if (!sym_has_value(sym
))
181 setText(promptColIdx
, prompt
);
184 void ConfigItem::testUpdateMenu(void)
191 sym_calc_value(menu
->sym
);
192 if (menu
->flags
& MENU_CHANGED
) {
193 /* the menu entry changed, so update all list items */
194 menu
->flags
&= ~MENU_CHANGED
;
195 for (i
= (ConfigItem
*)menu
->data
; i
; i
= i
->nextItem
)
197 } else if (listView()->updateAll
)
203 * construct a menu entry
205 void ConfigItem::init(void)
208 ConfigList
* list
= listView();
209 nextItem
= (ConfigItem
*)menu
->data
;
212 if (list
->mode
!= fullMode
)
214 sym_calc_value(menu
->sym
);
217 enum symbol_type type
= menu
->sym
->type
;
219 // Allow to edit "int", "hex", and "string" in-place in
220 // the data column. Unfortunately, you cannot specify
221 // the flags per column. Set ItemIsEditable for all
222 // columns here, and check the column in createEditor().
223 if (type
== S_INT
|| type
== S_HEX
|| type
== S_STRING
)
224 setFlags(flags() | Qt::ItemIsEditable
);
231 * destruct a menu entry
233 ConfigItem::~ConfigItem(void)
236 ConfigItem
** ip
= (ConfigItem
**)&menu
->data
;
237 for (; *ip
; ip
= &(*ip
)->nextItem
) {
246 QWidget
*ConfigItemDelegate::createEditor(QWidget
*parent
,
247 const QStyleOptionViewItem
&option
,
248 const QModelIndex
&index
) const
252 // Only the data column is editable
253 if (index
.column() != dataColIdx
)
256 // You cannot edit invisible menus
257 item
= static_cast<ConfigItem
*>(index
.internalPointer());
258 if (!item
|| !item
->menu
|| !menu_is_visible(item
->menu
))
261 return QStyledItemDelegate::createEditor(parent
, option
, index
);
264 void ConfigItemDelegate::setModelData(QWidget
*editor
,
265 QAbstractItemModel
*model
,
266 const QModelIndex
&index
) const
273 lineEdit
= qobject_cast
<QLineEdit
*>(editor
);
274 // If this is not a QLineEdit, use the parent's default.
275 // (does this happen?)
279 item
= static_cast<ConfigItem
*>(index
.internalPointer());
280 if (!item
|| !item
->menu
)
283 sym
= item
->menu
->sym
;
287 success
= sym_set_string_value(sym
, lineEdit
->text().toUtf8().data());
289 ConfigList::updateListForAll();
291 QMessageBox::information(editor
, "qconf",
292 "Cannot set the data (maybe due to out of range).\n"
293 "Setting the old value.");
294 lineEdit
->setText(sym_get_string_value(sym
));
298 QStyledItemDelegate::setModelData(editor
, model
, index
);
301 ConfigList::ConfigList(QWidget
*parent
, const char *name
)
302 : QTreeWidget(parent
),
304 showName(false), mode(singleMode
), optMode(normalOpt
),
305 rootEntry(0), headerPopup(0)
308 setSortingEnabled(false);
310 setVerticalScrollMode(ScrollPerPixel
);
311 setHorizontalScrollMode(ScrollPerPixel
);
313 setHeaderLabels(QStringList() << "Option" << "Name" << "Value");
315 connect(this, &ConfigList::itemSelectionChanged
,
316 this, &ConfigList::updateSelection
);
319 configSettings
->beginGroup(name
);
320 showName
= configSettings
->value("/showName", false).toBool();
321 optMode
= (enum optionMode
)configSettings
->value("/optionMode", 0).toInt();
322 configSettings
->endGroup();
323 connect(configApp
, &QApplication::aboutToQuit
,
324 this, &ConfigList::saveSettings
);
327 showColumn(promptColIdx
);
329 setItemDelegate(new ConfigItemDelegate(this));
331 allLists
.append(this);
336 ConfigList::~ConfigList()
338 allLists
.removeOne(this);
341 bool ConfigList::menuSkip(struct menu
*menu
)
343 if (optMode
== normalOpt
&& menu_is_visible(menu
))
345 if (optMode
== promptOpt
&& menu_has_prompt(menu
))
347 if (optMode
== allOpt
)
352 void ConfigList::reinit(void)
354 hideColumn(nameColIdx
);
357 showColumn(nameColIdx
);
362 void ConfigList::setOptionMode(QAction
*action
)
364 if (action
== showNormalAction
)
366 else if (action
== showAllAction
)
374 void ConfigList::saveSettings(void)
376 if (!objectName().isEmpty()) {
377 configSettings
->beginGroup(objectName());
378 configSettings
->setValue("/showName", showName
);
379 configSettings
->setValue("/optionMode", (int)optMode
);
380 configSettings
->endGroup();
384 ConfigItem
* ConfigList::findConfigItem(struct menu
*menu
)
386 ConfigItem
* item
= (ConfigItem
*)menu
->data
;
388 for (; item
; item
= item
->nextItem
) {
389 if (this == item
->listView())
396 void ConfigList::updateSelection(void)
401 if (selectedItems().count() == 0)
404 ConfigItem
* item
= (ConfigItem
*)selectedItems().first();
409 emit
menuChanged(menu
);
412 type
= menu
->prompt
? menu
->prompt
->type
: P_UNKNOWN
;
413 if (mode
== menuMode
&& type
== P_MENU
)
414 emit
menuSelected(menu
);
417 void ConfigList::updateList()
419 ConfigItem
* last
= 0;
423 if (mode
!= listMode
)
425 QTreeWidgetItemIterator
it(this);
428 item
= (ConfigItem
*)(*it
);
431 item
->testUpdateMenu();
438 if (rootEntry
!= &rootmenu
&& mode
== singleMode
) {
439 item
= (ConfigItem
*)topLevelItem(0);
441 item
= new ConfigItem(this, 0);
444 if ((mode
== singleMode
|| (mode
== symbolMode
&& !(rootEntry
->flags
& MENU_ROOT
))) &&
445 rootEntry
->sym
&& rootEntry
->prompt
) {
446 item
= last
? last
->nextSibling() : nullptr;
448 item
= new ConfigItem(this, last
, rootEntry
);
450 item
->testUpdateMenu();
452 updateMenuList(item
, rootEntry
);
454 resizeColumnToContents(0);
458 updateMenuList(rootEntry
);
460 resizeColumnToContents(0);
463 void ConfigList::updateListForAll()
465 QListIterator
<ConfigList
*> it(allLists
);
467 while (it
.hasNext()) {
468 ConfigList
*list
= it
.next();
474 void ConfigList::updateListAllForAll()
476 QListIterator
<ConfigList
*> it(allLists
);
478 while (it
.hasNext()) {
479 ConfigList
*list
= it
.next();
485 void ConfigList::setValue(ConfigItem
* item
, tristate val
)
491 sym
= item
->menu
? item
->menu
->sym
: 0;
495 type
= sym_get_type(sym
);
499 oldval
= sym_get_tristate_value(sym
);
501 if (!sym_set_tristate_value(sym
, val
))
503 if (oldval
== no
&& item
->menu
->list
)
504 item
->setExpanded(true);
505 ConfigList::updateListForAll();
510 void ConfigList::changeValue(ConfigItem
* item
)
514 int type
, oldexpr
, newexpr
;
521 if (item
->menu
->list
)
522 item
->setExpanded(!item
->isExpanded());
526 type
= sym_get_type(sym
);
530 oldexpr
= sym_get_tristate_value(sym
);
531 newexpr
= sym_toggle_tristate_value(sym
);
532 if (item
->menu
->list
) {
533 if (oldexpr
== newexpr
)
534 item
->setExpanded(!item
->isExpanded());
535 else if (oldexpr
== no
)
536 item
->setExpanded(true);
538 if (oldexpr
!= newexpr
)
539 ConfigList::updateListForAll();
546 void ConfigList::setRootMenu(struct menu
*menu
)
550 if (rootEntry
== menu
)
552 type
= menu
&& menu
->prompt
? menu
->prompt
->type
: P_UNKNOWN
;
559 setSelected(currentItem(), hasFocus());
560 scrollToItem(currentItem());
564 void ConfigList::setParentMenu(void)
567 struct menu
*oldroot
;
570 if (rootEntry
== &rootmenu
)
572 setRootMenu(menu_get_parent_menu(rootEntry
->parent
));
574 QTreeWidgetItemIterator
it(this);
576 item
= (ConfigItem
*)(*it
);
577 if (item
->menu
== oldroot
) {
578 setCurrentItem(item
);
588 * update all the children of a menu entry
589 * removes/adds the entries from the parent widget as necessary
591 * parent: either the menu list widget or a menu entry widget
592 * menu: entry to be updated
594 void ConfigList::updateMenuList(ConfigItem
*parent
, struct menu
* menu
)
602 while (parent
->childCount() > 0)
604 delete parent
->takeChild(0);
610 last
= parent
->firstChild();
611 if (last
&& !last
->goParent
)
613 for (child
= menu
->list
; child
; child
= child
->next
) {
614 item
= last
? last
->nextSibling() : parent
->firstChild();
615 type
= child
->prompt
? child
->prompt
->type
: P_UNKNOWN
;
619 if (!(child
->flags
& MENU_ROOT
))
623 if (child
->flags
& MENU_ROOT
)
630 if (!menuSkip(child
)) {
631 if (!child
->sym
&& !child
->list
&& !child
->prompt
)
633 if (!item
|| item
->menu
!= child
)
634 item
= new ConfigItem(parent
, last
, child
);
636 item
->testUpdateMenu();
638 if (mode
== fullMode
|| mode
== menuMode
|| type
!= P_MENU
)
639 updateMenuList(item
, child
);
641 updateMenuList(item
, 0);
646 if (item
&& item
->menu
== child
) {
647 last
= parent
->firstChild();
650 else while (last
->nextSibling() != item
)
651 last
= last
->nextSibling();
657 void ConfigList::updateMenuList(struct menu
*menu
)
665 while (topLevelItemCount() > 0)
667 delete takeTopLevelItem(0);
673 last
= (ConfigItem
*)topLevelItem(0);
674 if (last
&& !last
->goParent
)
676 for (child
= menu
->list
; child
; child
= child
->next
) {
677 item
= last
? last
->nextSibling() : (ConfigItem
*)topLevelItem(0);
678 type
= child
->prompt
? child
->prompt
->type
: P_UNKNOWN
;
682 if (!(child
->flags
& MENU_ROOT
))
686 if (child
->flags
& MENU_ROOT
)
693 if (!menuSkip(child
)) {
694 if (!child
->sym
&& !child
->list
&& !child
->prompt
)
696 if (!item
|| item
->menu
!= child
)
697 item
= new ConfigItem(this, last
, child
);
699 item
->testUpdateMenu();
701 if (mode
== fullMode
|| mode
== menuMode
|| type
!= P_MENU
)
702 updateMenuList(item
, child
);
704 updateMenuList(item
, 0);
709 if (item
&& item
->menu
== child
) {
710 last
= (ConfigItem
*)topLevelItem(0);
713 else while (last
->nextSibling() != item
)
714 last
= last
->nextSibling();
720 void ConfigList::keyPressEvent(QKeyEvent
* ev
)
722 QTreeWidgetItem
* i
= currentItem();
727 if (ev
->key() == Qt::Key_Escape
&& mode
== singleMode
) {
728 emit
parentSelected();
734 Parent::keyPressEvent(ev
);
737 item
= (ConfigItem
*)i
;
742 if (item
->goParent
) {
743 emit
parentSelected();
749 type
= menu
->prompt
? menu
->prompt
->type
: P_UNKNOWN
;
750 if (type
== P_MENU
&& rootEntry
!= menu
&&
751 mode
!= fullMode
&& mode
!= menuMode
) {
752 if (mode
== menuMode
)
753 emit
menuSelected(menu
);
755 emit
itemSelected(menu
);
771 Parent::keyPressEvent(ev
);
777 void ConfigList::mouseReleaseEvent(QMouseEvent
* e
)
780 ConfigItem
* item
= (ConfigItem
*)itemAt(p
);
782 enum prop_type ptype
;
790 x
= header()->offset() + p
.x();
791 idx
= header()->logicalIndexAt(x
);
794 icon
= item
->icon(promptColIdx
);
795 if (!icon
.isNull()) {
796 int off
= header()->sectionPosition(0) + visualRect(indexAt(p
)).x() + 4; // 4 is Hardcoded image offset. There might be a way to do it properly.
797 if (x
>= off
&& x
< off
+ icon
.availableSizes().first().width()) {
798 if (item
->goParent
) {
799 emit
parentSelected();
803 ptype
= menu
->prompt
? menu
->prompt
->type
: P_UNKNOWN
;
804 if (ptype
== P_MENU
&& rootEntry
!= menu
&&
805 mode
!= fullMode
&& mode
!= menuMode
&&
807 emit
menuSelected(menu
);
819 //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
820 Parent::mouseReleaseEvent(e
);
823 void ConfigList::mouseDoubleClickEvent(QMouseEvent
* e
)
826 ConfigItem
* item
= (ConfigItem
*)itemAt(p
);
828 enum prop_type ptype
;
832 if (item
->goParent
) {
833 emit
parentSelected();
839 ptype
= menu
->prompt
? menu
->prompt
->type
: P_UNKNOWN
;
840 if (ptype
== P_MENU
&& mode
!= listMode
) {
841 if (mode
== singleMode
)
842 emit
itemSelected(menu
);
843 else if (mode
== symbolMode
)
844 emit
menuSelected(menu
);
845 } else if (menu
->sym
)
849 //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
850 Parent::mouseDoubleClickEvent(e
);
853 void ConfigList::focusInEvent(QFocusEvent
*e
)
855 struct menu
*menu
= NULL
;
857 Parent::focusInEvent(e
);
859 ConfigItem
* item
= (ConfigItem
*)currentItem();
861 setSelected(item
, true);
867 void ConfigList::contextMenuEvent(QContextMenuEvent
*e
)
872 headerPopup
= new QMenu(this);
873 action
= new QAction("Show Name", this);
874 action
->setCheckable(true);
875 connect(action
, &QAction::toggled
,
876 this, &ConfigList::setShowName
);
877 connect(this, &ConfigList::showNameChanged
,
878 action
, &QAction::setChecked
);
879 action
->setChecked(showName
);
880 headerPopup
->addAction(action
);
883 headerPopup
->exec(e
->globalPos());
887 void ConfigList::setShowName(bool on
)
894 emit
showNameChanged(on
);
897 QList
<ConfigList
*> ConfigList::allLists
;
898 QAction
*ConfigList::showNormalAction
;
899 QAction
*ConfigList::showAllAction
;
900 QAction
*ConfigList::showPromptAction
;
902 void ConfigList::setAllOpen(bool open
)
904 QTreeWidgetItemIterator
it(this);
907 (*it
)->setExpanded(open
);
913 ConfigInfoView::ConfigInfoView(QWidget
* parent
, const char *name
)
914 : Parent(parent
), sym(0), _menu(0)
919 if (!objectName().isEmpty()) {
920 configSettings
->beginGroup(objectName());
921 setShowDebug(configSettings
->value("/showDebug", false).toBool());
922 configSettings
->endGroup();
923 connect(configApp
, &QApplication::aboutToQuit
,
924 this, &ConfigInfoView::saveSettings
);
927 contextMenu
= createStandardContextMenu();
928 QAction
*action
= new QAction("Show Debug Info", contextMenu
);
930 action
->setCheckable(true);
931 connect(action
, &QAction::toggled
,
932 this, &ConfigInfoView::setShowDebug
);
933 connect(this, &ConfigInfoView::showDebugChanged
,
934 action
, &QAction::setChecked
);
935 action
->setChecked(showDebug());
936 contextMenu
->addSeparator();
937 contextMenu
->addAction(action
);
940 void ConfigInfoView::saveSettings(void)
942 if (!objectName().isEmpty()) {
943 configSettings
->beginGroup(objectName());
944 configSettings
->setValue("/showDebug", showDebug());
945 configSettings
->endGroup();
949 void ConfigInfoView::setShowDebug(bool b
)
951 if (_showDebug
!= b
) {
957 emit
showDebugChanged(b
);
961 void ConfigInfoView::setInfo(struct menu
*m
)
973 void ConfigInfoView::symbolInfo(void)
977 str
+= "<big>Symbol: <b>";
978 str
+= print_filter(sym
->name
);
979 str
+= "</b></big><br><br>value: ";
980 str
+= print_filter(sym_get_string_value(sym
));
981 str
+= "<br>visibility: ";
982 str
+= sym
->visible
== yes
? "y" : sym
->visible
== mod
? "m" : "n";
984 str
+= debug_info(sym
);
989 void ConfigInfoView::menuInfo(void)
993 QTextStream
stream(&info
);
998 stream
<< "<big><b>";
999 stream
<< print_filter(_menu
->prompt
->text
);
1000 stream
<< "</b></big>";
1004 stream
<< "<a href=\"" << sym
->name
<< "\">";
1005 stream
<< print_filter(sym
->name
);
1010 } else if (sym
->name
) {
1011 stream
<< "<big><b>";
1013 stream
<< "<a href=\"" << sym
->name
<< "\">";
1014 stream
<< print_filter(sym
->name
);
1017 stream
<< "</b></big>";
1019 stream
<< "<br><br>";
1022 stream
<< debug_info(sym
);
1024 struct gstr help_gstr
= str_new();
1026 menu_get_ext_help(_menu
, &help_gstr
);
1027 stream
<< print_filter(str_get(&help_gstr
));
1028 str_free(&help_gstr
);
1029 } else if (_menu
->prompt
) {
1030 stream
<< "<big><b>";
1031 stream
<< print_filter(_menu
->prompt
->text
);
1032 stream
<< "</b></big><br><br>";
1034 if (_menu
->prompt
->visible
.expr
) {
1035 stream
<< " dep: ";
1036 expr_print(_menu
->prompt
->visible
.expr
,
1037 expr_print_help
, &stream
, E_NONE
);
1038 stream
<< "<br><br>";
1041 stream
<< "defined at " << _menu
->filename
<< ":"
1042 << _menu
->lineno
<< "<br><br>";
1049 QString
ConfigInfoView::debug_info(struct symbol
*sym
)
1052 QTextStream
stream(&debug
);
1055 stream
<< print_filter(sym_type_name(sym
->type
));
1056 if (sym_is_choice(sym
))
1057 stream
<< " (choice)";
1059 if (sym
->rev_dep
.expr
) {
1060 stream
<< "reverse dep: ";
1061 expr_print(sym
->rev_dep
.expr
, expr_print_help
, &stream
, E_NONE
);
1064 for (struct property
*prop
= sym
->prop
; prop
; prop
= prop
->next
) {
1065 switch (prop
->type
) {
1068 stream
<< "prompt: ";
1069 stream
<< print_filter(prop
->text
);
1077 stream
<< prop_get_type_name(prop
->type
);
1079 expr_print(prop
->expr
, expr_print_help
,
1084 stream
<< "unknown property: ";
1085 stream
<< prop_get_type_name(prop
->type
);
1088 if (prop
->visible
.expr
) {
1089 stream
<< " dep: ";
1090 expr_print(prop
->visible
.expr
, expr_print_help
,
1100 QString
ConfigInfoView::print_filter(const QString
&str
)
1102 QRegularExpression
re("[<>&\"\\n]");
1105 QHash
<QChar
, QString
> patterns
;
1106 patterns
['<'] = "<";
1107 patterns
['>'] = ">";
1108 patterns
['&'] = "&";
1109 patterns
['"'] = """;
1110 patterns
['\n'] = "<br>";
1112 for (int i
= 0; (i
= res
.indexOf(re
, i
)) >= 0;) {
1113 const QString n
= patterns
.value(res
[i
], QString());
1115 res
.replace(i
, 1, n
);
1122 void ConfigInfoView::expr_print_help(void *data
, struct symbol
*sym
, const char *str
)
1124 QTextStream
*stream
= reinterpret_cast<QTextStream
*>(data
);
1126 if (sym
&& sym
->name
&& !(sym
->flags
& SYMBOL_CONST
)) {
1127 *stream
<< "<a href=\"" << sym
->name
<< "\">";
1128 *stream
<< print_filter(str
);
1131 *stream
<< print_filter(str
);
1135 void ConfigInfoView::clicked(const QUrl
&url
)
1139 sym
= sym_find(url
.toEncoded().constData());
1141 m
= sym_get_prompt_menu(sym
);
1143 /* Symbol is not visible as a menu */
1145 emit
showDebugChanged(true);
1147 emit
menuSelected(m
);
1151 void ConfigInfoView::contextMenuEvent(QContextMenuEvent
*event
)
1153 contextMenu
->popup(event
->globalPos());
1157 ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow
*parent
)
1158 : Parent(parent
), result(NULL
)
1160 setObjectName("search");
1161 setWindowTitle("Search Config");
1163 QVBoxLayout
* layout1
= new QVBoxLayout(this);
1164 layout1
->setContentsMargins(11, 11, 11, 11);
1165 layout1
->setSpacing(6);
1167 QHBoxLayout
* layout2
= new QHBoxLayout();
1168 layout2
->setContentsMargins(0, 0, 0, 0);
1169 layout2
->setSpacing(6);
1170 layout2
->addWidget(new QLabel("Find:", this));
1171 editField
= new QLineEdit(this);
1172 connect(editField
, &QLineEdit::returnPressed
,
1173 this, &ConfigSearchWindow::search
);
1174 layout2
->addWidget(editField
);
1175 searchButton
= new QPushButton("Search", this);
1176 searchButton
->setAutoDefault(false);
1177 connect(searchButton
, &QPushButton::clicked
,
1178 this, &ConfigSearchWindow::search
);
1179 layout2
->addWidget(searchButton
);
1180 layout1
->addLayout(layout2
);
1182 split
= new QSplitter(Qt::Vertical
, this);
1183 list
= new ConfigList(split
, "search");
1184 list
->mode
= listMode
;
1185 info
= new ConfigInfoView(split
, "search");
1186 connect(list
, &ConfigList::menuChanged
,
1187 info
, &ConfigInfoView::setInfo
);
1188 connect(list
, &ConfigList::menuChanged
,
1189 parent
, &ConfigMainWindow::setMenuLink
);
1191 layout1
->addWidget(split
);
1197 configSettings
->beginGroup("search");
1198 width
= configSettings
->value("/window width", parent
->width() / 2).toInt();
1199 height
= configSettings
->value("/window height", parent
->height() / 2).toInt();
1200 resize(width
, height
);
1201 x
= configSettings
->value("/window x");
1202 y
= configSettings
->value("/window y");
1203 if (x
.isValid() && y
.isValid())
1204 move(x
.toInt(), y
.toInt());
1205 QList
<int> sizes
= configSettings
->readSizes("/split", &ok
);
1207 split
->setSizes(sizes
);
1208 configSettings
->endGroup();
1209 connect(configApp
, &QApplication::aboutToQuit
,
1210 this, &ConfigSearchWindow::saveSettings
);
1213 void ConfigSearchWindow::saveSettings(void)
1215 if (!objectName().isEmpty()) {
1216 configSettings
->beginGroup(objectName());
1217 configSettings
->setValue("/window x", pos().x());
1218 configSettings
->setValue("/window y", pos().y());
1219 configSettings
->setValue("/window width", size().width());
1220 configSettings
->setValue("/window height", size().height());
1221 configSettings
->writeSizes("/split", split
->sizes());
1222 configSettings
->endGroup();
1226 void ConfigSearchWindow::search(void)
1229 struct property
*prop
;
1230 ConfigItem
*lastItem
= NULL
;
1236 result
= sym_re_search(editField
->text().toLatin1());
1239 for (p
= result
; *p
; p
++) {
1240 for_all_prompts((*p
), prop
)
1241 lastItem
= new ConfigItem(list
, lastItem
, prop
->menu
);
1246 * Construct the complete config widget
1248 ConfigMainWindow::ConfigMainWindow(void)
1256 snprintf(title
, sizeof(title
), "%s%s",
1257 rootmenu
.prompt
->text
,
1260 setWindowTitle(title
);
1262 QRect g
= configApp
->primaryScreen()->geometry();
1263 width
= configSettings
->value("/window width", g
.width() - 64).toInt();
1264 height
= configSettings
->value("/window height", g
.height() - 64).toInt();
1265 resize(width
, height
);
1266 x
= configSettings
->value("/window x");
1267 y
= configSettings
->value("/window y");
1268 if ((x
.isValid())&&(y
.isValid()))
1269 move(x
.toInt(), y
.toInt());
1272 ConfigItem::symbolYesIcon
= QIcon(QPixmap(xpm_symbol_yes
));
1273 ConfigItem::symbolModIcon
= QIcon(QPixmap(xpm_symbol_mod
));
1274 ConfigItem::symbolNoIcon
= QIcon(QPixmap(xpm_symbol_no
));
1275 ConfigItem::choiceYesIcon
= QIcon(QPixmap(xpm_choice_yes
));
1276 ConfigItem::choiceNoIcon
= QIcon(QPixmap(xpm_choice_no
));
1277 ConfigItem::menuIcon
= QIcon(QPixmap(xpm_menu
));
1278 ConfigItem::menubackIcon
= QIcon(QPixmap(xpm_menuback
));
1280 QWidget
*widget
= new QWidget(this);
1281 setCentralWidget(widget
);
1283 QVBoxLayout
*layout
= new QVBoxLayout(widget
);
1285 split2
= new QSplitter(Qt::Vertical
, widget
);
1286 layout
->addWidget(split2
);
1287 split2
->setChildrenCollapsible(false);
1289 split1
= new QSplitter(Qt::Horizontal
, split2
);
1290 split1
->setChildrenCollapsible(false);
1292 configList
= new ConfigList(split1
, "config");
1294 menuList
= new ConfigList(split1
, "menu");
1296 helpText
= new ConfigInfoView(split2
, "help");
1297 setTabOrder(configList
, helpText
);
1299 configList
->setFocus();
1301 backAction
= new QAction(QPixmap(xpm_back
), "Back", this);
1302 backAction
->setShortcut(QKeySequence::Back
);
1303 connect(backAction
, &QAction::triggered
,
1304 this, &ConfigMainWindow::goBack
);
1306 QAction
*quitAction
= new QAction("&Quit", this);
1307 quitAction
->setShortcut(QKeySequence::Quit
);
1308 connect(quitAction
, &QAction::triggered
,
1309 this, &ConfigMainWindow::close
);
1311 QAction
*loadAction
= new QAction(QPixmap(xpm_load
), "&Open", this);
1312 loadAction
->setShortcut(QKeySequence::Open
);
1313 connect(loadAction
, &QAction::triggered
,
1314 this, &ConfigMainWindow::loadConfig
);
1316 saveAction
= new QAction(QPixmap(xpm_save
), "&Save", this);
1317 saveAction
->setShortcut(QKeySequence::Save
);
1318 connect(saveAction
, &QAction::triggered
,
1319 this, &ConfigMainWindow::saveConfig
);
1321 conf_set_changed_callback(conf_changed
);
1323 configname
= conf_get_configname();
1325 QAction
*saveAsAction
= new QAction("Save &As...", this);
1326 saveAsAction
->setShortcut(QKeySequence::SaveAs
);
1327 connect(saveAsAction
, &QAction::triggered
,
1328 this, &ConfigMainWindow::saveConfigAs
);
1329 QAction
*searchAction
= new QAction("&Find", this);
1330 searchAction
->setShortcut(QKeySequence::Find
);
1331 connect(searchAction
, &QAction::triggered
,
1332 this, &ConfigMainWindow::searchConfig
);
1333 singleViewAction
= new QAction(QPixmap(xpm_single_view
), "Single View", this);
1334 singleViewAction
->setCheckable(true);
1335 connect(singleViewAction
, &QAction::triggered
,
1336 this, &ConfigMainWindow::showSingleView
);
1337 splitViewAction
= new QAction(QPixmap(xpm_split_view
), "Split View", this);
1338 splitViewAction
->setCheckable(true);
1339 connect(splitViewAction
, &QAction::triggered
,
1340 this, &ConfigMainWindow::showSplitView
);
1341 fullViewAction
= new QAction(QPixmap(xpm_tree_view
), "Full View", this);
1342 fullViewAction
->setCheckable(true);
1343 connect(fullViewAction
, &QAction::triggered
,
1344 this, &ConfigMainWindow::showFullView
);
1346 QAction
*showNameAction
= new QAction("Show Name", this);
1347 showNameAction
->setCheckable(true);
1348 connect(showNameAction
, &QAction::toggled
,
1349 configList
, &ConfigList::setShowName
);
1350 showNameAction
->setChecked(configList
->showName
);
1352 QActionGroup
*optGroup
= new QActionGroup(this);
1353 optGroup
->setExclusive(true);
1354 connect(optGroup
, &QActionGroup::triggered
,
1355 configList
, &ConfigList::setOptionMode
);
1356 connect(optGroup
, &QActionGroup::triggered
,
1357 menuList
, &ConfigList::setOptionMode
);
1359 ConfigList::showNormalAction
= new QAction("Show Normal Options", optGroup
);
1360 ConfigList::showNormalAction
->setCheckable(true);
1361 ConfigList::showAllAction
= new QAction("Show All Options", optGroup
);
1362 ConfigList::showAllAction
->setCheckable(true);
1363 ConfigList::showPromptAction
= new QAction("Show Prompt Options", optGroup
);
1364 ConfigList::showPromptAction
->setCheckable(true);
1366 QAction
*showDebugAction
= new QAction("Show Debug Info", this);
1367 showDebugAction
->setCheckable(true);
1368 connect(showDebugAction
, &QAction::toggled
,
1369 helpText
, &ConfigInfoView::setShowDebug
);
1370 showDebugAction
->setChecked(helpText
->showDebug());
1372 QAction
*showIntroAction
= new QAction("Introduction", this);
1373 connect(showIntroAction
, &QAction::triggered
,
1374 this, &ConfigMainWindow::showIntro
);
1375 QAction
*showAboutAction
= new QAction("About", this);
1376 connect(showAboutAction
, &QAction::triggered
,
1377 this, &ConfigMainWindow::showAbout
);
1380 QToolBar
*toolBar
= addToolBar("Tools");
1381 toolBar
->addAction(backAction
);
1382 toolBar
->addSeparator();
1383 toolBar
->addAction(loadAction
);
1384 toolBar
->addAction(saveAction
);
1385 toolBar
->addSeparator();
1386 toolBar
->addAction(singleViewAction
);
1387 toolBar
->addAction(splitViewAction
);
1388 toolBar
->addAction(fullViewAction
);
1391 QMenu
*menu
= menuBar()->addMenu("&File");
1392 menu
->addAction(loadAction
);
1393 menu
->addAction(saveAction
);
1394 menu
->addAction(saveAsAction
);
1395 menu
->addSeparator();
1396 menu
->addAction(quitAction
);
1399 menu
= menuBar()->addMenu("&Edit");
1400 menu
->addAction(searchAction
);
1402 // create options menu
1403 menu
= menuBar()->addMenu("&Option");
1404 menu
->addAction(showNameAction
);
1405 menu
->addSeparator();
1406 menu
->addActions(optGroup
->actions());
1407 menu
->addSeparator();
1408 menu
->addAction(showDebugAction
);
1411 menu
= menuBar()->addMenu("&Help");
1412 menu
->addAction(showIntroAction
);
1413 menu
->addAction(showAboutAction
);
1415 connect(helpText
, &ConfigInfoView::anchorClicked
,
1416 helpText
, &ConfigInfoView::clicked
);
1418 connect(configList
, &ConfigList::menuChanged
,
1419 helpText
, &ConfigInfoView::setInfo
);
1420 connect(configList
, &ConfigList::menuSelected
,
1421 this, &ConfigMainWindow::changeMenu
);
1422 connect(configList
, &ConfigList::itemSelected
,
1423 this, &ConfigMainWindow::changeItens
);
1424 connect(configList
, &ConfigList::parentSelected
,
1425 this, &ConfigMainWindow::goBack
);
1426 connect(menuList
, &ConfigList::menuChanged
,
1427 helpText
, &ConfigInfoView::setInfo
);
1428 connect(menuList
, &ConfigList::menuSelected
,
1429 this, &ConfigMainWindow::changeMenu
);
1431 connect(configList
, &ConfigList::gotFocus
,
1432 helpText
, &ConfigInfoView::setInfo
);
1433 connect(menuList
, &ConfigList::gotFocus
,
1434 helpText
, &ConfigInfoView::setInfo
);
1435 connect(menuList
, &ConfigList::gotFocus
,
1436 this, &ConfigMainWindow::listFocusChanged
);
1437 connect(helpText
, &ConfigInfoView::menuSelected
,
1438 this, &ConfigMainWindow::setMenuLink
);
1440 connect(configApp
, &QApplication::aboutToQuit
,
1441 this, &ConfigMainWindow::saveSettings
);
1445 QString listMode
= configSettings
->value("/listMode", "symbol").toString();
1446 if (listMode
== "single")
1448 else if (listMode
== "full")
1450 else /*if (listMode == "split")*/
1453 // UI setup done, restore splitter positions
1454 QList
<int> sizes
= configSettings
->readSizes("/split1", &ok
);
1456 split1
->setSizes(sizes
);
1458 sizes
= configSettings
->readSizes("/split2", &ok
);
1460 split2
->setSizes(sizes
);
1463 void ConfigMainWindow::loadConfig(void)
1467 str
= QFileDialog::getOpenFileName(this, "", configname
);
1471 if (conf_read(str
.toLocal8Bit().constData()))
1472 QMessageBox::information(this, "qconf", "Unable to load configuration!");
1476 ConfigList::updateListAllForAll();
1479 bool ConfigMainWindow::saveConfig(void)
1481 if (conf_write(configname
.toLocal8Bit().constData())) {
1482 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1485 conf_write_autoconf(0);
1490 void ConfigMainWindow::saveConfigAs(void)
1494 str
= QFileDialog::getSaveFileName(this, "", configname
);
1498 if (conf_write(str
.toLocal8Bit().constData())) {
1499 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1501 conf_write_autoconf(0);
1506 void ConfigMainWindow::searchConfig(void)
1509 searchWindow
= new ConfigSearchWindow(this);
1510 searchWindow
->show();
1513 void ConfigMainWindow::changeItens(struct menu
*menu
)
1515 configList
->setRootMenu(menu
);
1518 void ConfigMainWindow::changeMenu(struct menu
*menu
)
1520 menuList
->setRootMenu(menu
);
1523 void ConfigMainWindow::setMenuLink(struct menu
*menu
)
1525 struct menu
*parent
;
1526 ConfigList
* list
= NULL
;
1529 if (configList
->menuSkip(menu
))
1532 switch (configList
->mode
) {
1535 parent
= menu_get_parent_menu(menu
);
1538 list
->setRootMenu(parent
);
1541 if (menu
->flags
& MENU_ROOT
) {
1542 menuList
->setRootMenu(menu
);
1543 configList
->clearSelection();
1546 parent
= menu_get_parent_menu(menu
->parent
);
1550 /* Select the config view */
1551 item
= configList
->findConfigItem(parent
);
1553 configList
->setSelected(item
, true);
1554 configList
->scrollToItem(item
);
1557 menuList
->setRootMenu(parent
);
1558 menuList
->clearSelection();
1570 item
= list
->findConfigItem(menu
);
1572 list
->setSelected(item
, true);
1573 list
->scrollToItem(item
);
1575 helpText
->setInfo(menu
);
1580 void ConfigMainWindow::listFocusChanged(void)
1582 if (menuList
->mode
== menuMode
)
1583 configList
->clearSelection();
1586 void ConfigMainWindow::goBack(void)
1588 configList
->setParentMenu();
1591 void ConfigMainWindow::showSingleView(void)
1593 singleViewAction
->setEnabled(false);
1594 singleViewAction
->setChecked(true);
1595 splitViewAction
->setEnabled(true);
1596 splitViewAction
->setChecked(false);
1597 fullViewAction
->setEnabled(true);
1598 fullViewAction
->setChecked(false);
1600 backAction
->setEnabled(true);
1603 menuList
->setRootMenu(0);
1604 configList
->mode
= singleMode
;
1605 if (configList
->rootEntry
== &rootmenu
)
1606 configList
->updateListAll();
1608 configList
->setRootMenu(&rootmenu
);
1609 configList
->setFocus();
1612 void ConfigMainWindow::showSplitView(void)
1614 singleViewAction
->setEnabled(true);
1615 singleViewAction
->setChecked(false);
1616 splitViewAction
->setEnabled(false);
1617 splitViewAction
->setChecked(true);
1618 fullViewAction
->setEnabled(true);
1619 fullViewAction
->setChecked(false);
1621 backAction
->setEnabled(false);
1623 configList
->mode
= menuMode
;
1624 if (configList
->rootEntry
== &rootmenu
)
1625 configList
->updateListAll();
1627 configList
->setRootMenu(&rootmenu
);
1628 configList
->setAllOpen(true);
1629 configApp
->processEvents();
1630 menuList
->mode
= symbolMode
;
1631 menuList
->setRootMenu(&rootmenu
);
1632 menuList
->setAllOpen(true);
1634 menuList
->setFocus();
1637 void ConfigMainWindow::showFullView(void)
1639 singleViewAction
->setEnabled(true);
1640 singleViewAction
->setChecked(false);
1641 splitViewAction
->setEnabled(true);
1642 splitViewAction
->setChecked(false);
1643 fullViewAction
->setEnabled(false);
1644 fullViewAction
->setChecked(true);
1646 backAction
->setEnabled(false);
1649 menuList
->setRootMenu(0);
1650 configList
->mode
= fullMode
;
1651 if (configList
->rootEntry
== &rootmenu
)
1652 configList
->updateListAll();
1654 configList
->setRootMenu(&rootmenu
);
1655 configList
->setFocus();
1659 * ask for saving configuration before quitting
1661 void ConfigMainWindow::closeEvent(QCloseEvent
* e
)
1663 if (!conf_get_changed()) {
1668 QMessageBox
mb(QMessageBox::Icon::Warning
, "qconf",
1669 "Save configuration?");
1671 QPushButton
*yb
= mb
.addButton(QMessageBox::Yes
);
1672 QPushButton
*db
= mb
.addButton(QMessageBox::No
);
1673 QPushButton
*cb
= mb
.addButton(QMessageBox::Cancel
);
1675 yb
->setText("&Save Changes");
1676 db
->setText("&Discard Changes");
1677 cb
->setText("Cancel Exit");
1679 mb
.setDefaultButton(yb
);
1680 mb
.setEscapeButton(cb
);
1682 switch (mb
.exec()) {
1683 case QMessageBox::Yes
:
1689 case QMessageBox::No
:
1692 case QMessageBox::Cancel
:
1698 void ConfigMainWindow::showIntro(void)
1700 static const QString str
=
1701 "Welcome to the qconf graphical configuration tool.\n"
1703 "For bool and tristate options, a blank box indicates the "
1704 "feature is disabled, a check indicates it is enabled, and a "
1705 "dot indicates that it is to be compiled as a module. Clicking "
1706 "on the box will cycle through the three states. For int, hex, "
1707 "and string options, double-clicking or pressing F2 on the "
1708 "Value cell will allow you to edit the value.\n"
1710 "If you do not see an option (e.g., a device driver) that you "
1711 "believe should be present, try turning on Show All Options "
1712 "under the Options menu. Enabling Show Debug Info will help you"
1713 "figure out what other options must be enabled to support the "
1714 "option you are interested in, and hyperlinks will navigate to "
1717 "Toggling Show Debug Info under the Options menu will show the "
1718 "dependencies, which you can then match by examining other "
1721 QMessageBox::information(this, "qconf", str
);
1724 void ConfigMainWindow::showAbout(void)
1726 static const QString str
= "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n"
1727 "Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>.\n"
1729 "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n"
1733 QMessageBox::information(this, "qconf", str
+ qVersion());
1736 void ConfigMainWindow::saveSettings(void)
1738 configSettings
->setValue("/window x", pos().x());
1739 configSettings
->setValue("/window y", pos().y());
1740 configSettings
->setValue("/window width", size().width());
1741 configSettings
->setValue("/window height", size().height());
1744 switch(configList
->mode
) {
1760 configSettings
->setValue("/listMode", entry
);
1762 configSettings
->writeSizes("/split1", split1
->sizes());
1763 configSettings
->writeSizes("/split2", split2
->sizes());
1766 void ConfigMainWindow::conf_changed(bool dirty
)
1769 saveAction
->setEnabled(dirty
);
1772 void fixup_rootmenu(struct menu
*menu
)
1775 static int menu_cnt
= 0;
1777 menu
->flags
|= MENU_ROOT
;
1778 for (child
= menu
->list
; child
; child
= child
->next
) {
1779 if (child
->prompt
&& child
->prompt
->type
== P_MENU
) {
1781 fixup_rootmenu(child
);
1783 } else if (!menu_cnt
)
1784 fixup_rootmenu(child
);
1788 static const char *progname
;
1790 static void usage(void)
1792 printf("%s [-s] <config>\n", progname
);
1796 int main(int ac
, char** av
)
1798 ConfigMainWindow
* v
;
1802 if (ac
> 1 && av
[1][0] == '-') {
1805 conf_set_message_callback(NULL
);
1818 fixup_rootmenu(&rootmenu
);
1819 //zconfdump(stdout);
1821 configApp
= new QApplication(ac
, av
);
1823 configSettings
= new ConfigSettings();
1824 configSettings
->beginGroup("/kconfig/qconf");
1825 v
= new ConfigMainWindow();
1827 //zconfdump(stdout);
1832 configSettings
->endGroup();
1833 delete configSettings
;