1 // SPDX-License-Identifier: GPL-2.0-only
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>
31 static QApplication
*configApp
;
32 static ConfigSettings
*configSettings
;
34 QAction
*ConfigMainWindow::saveAction
;
36 ConfigSettings::ConfigSettings()
37 : QSettings("kernel.org", "qconf")
42 * Reads a list of integer values from the application settings.
44 QList
<int> ConfigSettings::readSizes(const QString
& key
, bool *ok
)
50 QStringList entryList
= value(key
).toStringList();
51 QStringList::Iterator it
;
53 for (it
= entryList
.begin(); it
!= entryList
.end(); ++it
)
54 result
.push_back((*it
).toInt());
65 * Writes a list of integer values to the application settings.
67 bool ConfigSettings::writeSizes(const QString
& key
, const QList
<int>& value
)
69 QStringList stringList
;
70 QList
<int>::ConstIterator it
;
72 for (it
= value
.begin(); it
!= value
.end(); ++it
)
73 stringList
.push_back(QString::number(*it
));
74 setValue(key
, stringList
);
79 QIcon
ConfigItem::symbolYesIcon
;
80 QIcon
ConfigItem::symbolModIcon
;
81 QIcon
ConfigItem::symbolNoIcon
;
82 QIcon
ConfigItem::choiceYesIcon
;
83 QIcon
ConfigItem::choiceNoIcon
;
84 QIcon
ConfigItem::menuIcon
;
85 QIcon
ConfigItem::menubackIcon
;
88 * update the displayed of a menu entry
90 void ConfigItem::updateMenu(void)
94 struct property
*prop
;
101 setIcon(promptColIdx
, menubackIcon
);
108 prompt
= menu_get_prompt(menu
);
110 if (prop
) switch (prop
->type
) {
112 if (list
->mode
== singleMode
|| list
->mode
== symbolMode
) {
113 /* a menuconfig entry is displayed differently
114 * depending whether it's at the view root or a child.
116 if (sym
&& list
->rootEntry
== menu
)
118 setIcon(promptColIdx
, menuIcon
);
122 setIcon(promptColIdx
, QIcon());
126 setIcon(promptColIdx
, QIcon());
127 prompt
= "*** " + prompt
+ " ***";
135 setText(nameColIdx
, sym
->name
);
137 type
= sym_get_type(sym
);
143 if (!sym_is_changeable(sym
) && list
->optMode
== normalOpt
) {
144 setIcon(promptColIdx
, QIcon());
147 expr
= sym_get_tristate_value(sym
);
150 if (sym_is_choice_value(sym
) && type
== S_BOOLEAN
)
151 setIcon(promptColIdx
, choiceYesIcon
);
153 setIcon(promptColIdx
, symbolYesIcon
);
157 setIcon(promptColIdx
, symbolModIcon
);
161 if (sym_is_choice_value(sym
) && type
== S_BOOLEAN
)
162 setIcon(promptColIdx
, choiceNoIcon
);
164 setIcon(promptColIdx
, symbolNoIcon
);
169 setText(dataColIdx
, QChar(ch
));
174 setText(dataColIdx
, sym_get_string_value(sym
));
177 if (!sym_has_value(sym
) && visible
)
180 setText(promptColIdx
, prompt
);
183 void ConfigItem::testUpdateMenu(bool v
)
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);
309 setRootIsDecorated(true);
311 setVerticalScrollMode(ScrollPerPixel
);
312 setHorizontalScrollMode(ScrollPerPixel
);
314 setHeaderLabels(QStringList() << "Option" << "Name" << "Value");
316 connect(this, &ConfigList::itemSelectionChanged
,
317 this, &ConfigList::updateSelection
);
320 configSettings
->beginGroup(name
);
321 showName
= configSettings
->value("/showName", false).toBool();
322 optMode
= (enum optionMode
)configSettings
->value("/optionMode", 0).toInt();
323 configSettings
->endGroup();
324 connect(configApp
, &QApplication::aboutToQuit
,
325 this, &ConfigList::saveSettings
);
328 showColumn(promptColIdx
);
330 setItemDelegate(new ConfigItemDelegate(this));
332 allLists
.append(this);
337 ConfigList::~ConfigList()
339 allLists
.removeOne(this);
342 bool ConfigList::menuSkip(struct menu
*menu
)
344 if (optMode
== normalOpt
&& menu_is_visible(menu
))
346 if (optMode
== promptOpt
&& menu_has_prompt(menu
))
348 if (optMode
== allOpt
)
353 void ConfigList::reinit(void)
355 hideColumn(nameColIdx
);
358 showColumn(nameColIdx
);
363 void ConfigList::setOptionMode(QAction
*action
)
365 if (action
== showNormalAction
)
367 else if (action
== showAllAction
)
375 void ConfigList::saveSettings(void)
377 if (!objectName().isEmpty()) {
378 configSettings
->beginGroup(objectName());
379 configSettings
->setValue("/showName", showName
);
380 configSettings
->setValue("/optionMode", (int)optMode
);
381 configSettings
->endGroup();
385 ConfigItem
* ConfigList::findConfigItem(struct menu
*menu
)
387 ConfigItem
* item
= (ConfigItem
*)menu
->data
;
389 for (; item
; item
= item
->nextItem
) {
390 if (this == item
->listView())
397 void ConfigList::updateSelection(void)
402 if (selectedItems().count() == 0)
405 ConfigItem
* item
= (ConfigItem
*)selectedItems().first();
410 emit
menuChanged(menu
);
413 type
= menu
->prompt
? menu
->prompt
->type
: P_UNKNOWN
;
414 if (mode
== menuMode
&& type
== P_MENU
)
415 emit
menuSelected(menu
);
418 void ConfigList::updateList()
420 ConfigItem
* last
= 0;
424 if (mode
!= listMode
)
426 QTreeWidgetItemIterator
it(this);
429 item
= (ConfigItem
*)(*it
);
432 item
->testUpdateMenu(menu_is_visible(item
->menu
));
439 if (rootEntry
!= &rootmenu
&& (mode
== singleMode
||
440 (mode
== symbolMode
&& rootEntry
->parent
!= &rootmenu
))) {
441 item
= (ConfigItem
*)topLevelItem(0);
443 item
= new ConfigItem(this, 0, true);
446 if ((mode
== singleMode
|| (mode
== symbolMode
&& !(rootEntry
->flags
& MENU_ROOT
))) &&
447 rootEntry
->sym
&& rootEntry
->prompt
) {
448 item
= last
? last
->nextSibling() : nullptr;
450 item
= new ConfigItem(this, last
, rootEntry
, true);
452 item
->testUpdateMenu(true);
454 updateMenuList(item
, rootEntry
);
456 resizeColumnToContents(0);
460 updateMenuList(rootEntry
);
462 resizeColumnToContents(0);
465 void ConfigList::updateListForAll()
467 QListIterator
<ConfigList
*> it(allLists
);
469 while (it
.hasNext()) {
470 ConfigList
*list
= it
.next();
476 void ConfigList::updateListAllForAll()
478 QListIterator
<ConfigList
*> it(allLists
);
480 while (it
.hasNext()) {
481 ConfigList
*list
= it
.next();
487 void ConfigList::setValue(ConfigItem
* item
, tristate val
)
493 sym
= item
->menu
? item
->menu
->sym
: 0;
497 type
= sym_get_type(sym
);
501 oldval
= sym_get_tristate_value(sym
);
503 if (!sym_set_tristate_value(sym
, val
))
505 if (oldval
== no
&& item
->menu
->list
)
506 item
->setExpanded(true);
507 ConfigList::updateListForAll();
512 void ConfigList::changeValue(ConfigItem
* item
)
516 int type
, oldexpr
, newexpr
;
523 if (item
->menu
->list
)
524 item
->setExpanded(!item
->isExpanded());
528 type
= sym_get_type(sym
);
532 oldexpr
= sym_get_tristate_value(sym
);
533 newexpr
= sym_toggle_tristate_value(sym
);
534 if (item
->menu
->list
) {
535 if (oldexpr
== newexpr
)
536 item
->setExpanded(!item
->isExpanded());
537 else if (oldexpr
== no
)
538 item
->setExpanded(true);
540 if (oldexpr
!= newexpr
)
541 ConfigList::updateListForAll();
548 void ConfigList::setRootMenu(struct menu
*menu
)
552 if (rootEntry
== menu
)
554 type
= menu
&& menu
->prompt
? menu
->prompt
->type
: P_UNKNOWN
;
561 setSelected(currentItem(), hasFocus());
562 scrollToItem(currentItem());
566 void ConfigList::setParentMenu(void)
569 struct menu
*oldroot
;
572 if (rootEntry
== &rootmenu
)
574 setRootMenu(menu_get_parent_menu(rootEntry
->parent
));
576 QTreeWidgetItemIterator
it(this);
578 item
= (ConfigItem
*)(*it
);
579 if (item
->menu
== oldroot
) {
580 setCurrentItem(item
);
590 * update all the children of a menu entry
591 * removes/adds the entries from the parent widget as necessary
593 * parent: either the menu list widget or a menu entry widget
594 * menu: entry to be updated
596 void ConfigList::updateMenuList(ConfigItem
*parent
, struct menu
* menu
)
605 while (parent
->childCount() > 0)
607 delete parent
->takeChild(0);
613 last
= parent
->firstChild();
614 if (last
&& !last
->goParent
)
616 for (child
= menu
->list
; child
; child
= child
->next
) {
617 item
= last
? last
->nextSibling() : parent
->firstChild();
618 type
= child
->prompt
? child
->prompt
->type
: P_UNKNOWN
;
622 if (!(child
->flags
& MENU_ROOT
))
626 if (child
->flags
& MENU_ROOT
)
633 visible
= menu_is_visible(child
);
634 if (!menuSkip(child
)) {
635 if (!child
->sym
&& !child
->list
&& !child
->prompt
)
637 if (!item
|| item
->menu
!= child
)
638 item
= new ConfigItem(parent
, last
, child
, visible
);
640 item
->testUpdateMenu(visible
);
642 if (mode
== fullMode
|| mode
== menuMode
|| type
!= P_MENU
)
643 updateMenuList(item
, child
);
645 updateMenuList(item
, 0);
650 if (item
&& item
->menu
== child
) {
651 last
= parent
->firstChild();
654 else while (last
->nextSibling() != item
)
655 last
= last
->nextSibling();
661 void ConfigList::updateMenuList(struct menu
*menu
)
670 while (topLevelItemCount() > 0)
672 delete takeTopLevelItem(0);
678 last
= (ConfigItem
*)topLevelItem(0);
679 if (last
&& !last
->goParent
)
681 for (child
= menu
->list
; child
; child
= child
->next
) {
682 item
= last
? last
->nextSibling() : (ConfigItem
*)topLevelItem(0);
683 type
= child
->prompt
? child
->prompt
->type
: P_UNKNOWN
;
687 if (!(child
->flags
& MENU_ROOT
))
691 if (child
->flags
& MENU_ROOT
)
698 visible
= menu_is_visible(child
);
699 if (!menuSkip(child
)) {
700 if (!child
->sym
&& !child
->list
&& !child
->prompt
)
702 if (!item
|| item
->menu
!= child
)
703 item
= new ConfigItem(this, last
, child
, visible
);
705 item
->testUpdateMenu(visible
);
707 if (mode
== fullMode
|| mode
== menuMode
|| type
!= P_MENU
)
708 updateMenuList(item
, child
);
710 updateMenuList(item
, 0);
715 if (item
&& item
->menu
== child
) {
716 last
= (ConfigItem
*)topLevelItem(0);
719 else while (last
->nextSibling() != item
)
720 last
= last
->nextSibling();
726 void ConfigList::keyPressEvent(QKeyEvent
* ev
)
728 QTreeWidgetItem
* i
= currentItem();
733 if (ev
->key() == Qt::Key_Escape
&& mode
!= fullMode
&& mode
!= listMode
) {
734 emit
parentSelected();
740 Parent::keyPressEvent(ev
);
743 item
= (ConfigItem
*)i
;
748 if (item
->goParent
) {
749 emit
parentSelected();
755 type
= menu
->prompt
? menu
->prompt
->type
: P_UNKNOWN
;
756 if (type
== P_MENU
&& rootEntry
!= menu
&&
757 mode
!= fullMode
&& mode
!= menuMode
) {
758 if (mode
== menuMode
)
759 emit
menuSelected(menu
);
761 emit
itemSelected(menu
);
777 Parent::keyPressEvent(ev
);
783 void ConfigList::mousePressEvent(QMouseEvent
* e
)
785 //QPoint p(contentsToViewport(e->pos()));
786 //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
787 Parent::mousePressEvent(e
);
790 void ConfigList::mouseReleaseEvent(QMouseEvent
* e
)
793 ConfigItem
* item
= (ConfigItem
*)itemAt(p
);
795 enum prop_type ptype
;
803 x
= header()->offset() + p
.x();
804 idx
= header()->logicalIndexAt(x
);
807 icon
= item
->icon(promptColIdx
);
808 if (!icon
.isNull()) {
809 int off
= header()->sectionPosition(0) + visualRect(indexAt(p
)).x() + 4; // 4 is Hardcoded image offset. There might be a way to do it properly.
810 if (x
>= off
&& x
< off
+ icon
.availableSizes().first().width()) {
811 if (item
->goParent
) {
812 emit
parentSelected();
816 ptype
= menu
->prompt
? menu
->prompt
->type
: P_UNKNOWN
;
817 if (ptype
== P_MENU
&& rootEntry
!= menu
&&
818 mode
!= fullMode
&& mode
!= menuMode
&&
820 emit
menuSelected(menu
);
832 //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
833 Parent::mouseReleaseEvent(e
);
836 void ConfigList::mouseMoveEvent(QMouseEvent
* e
)
838 //QPoint p(contentsToViewport(e->pos()));
839 //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
840 Parent::mouseMoveEvent(e
);
843 void ConfigList::mouseDoubleClickEvent(QMouseEvent
* e
)
846 ConfigItem
* item
= (ConfigItem
*)itemAt(p
);
848 enum prop_type ptype
;
852 if (item
->goParent
) {
853 emit
parentSelected();
859 ptype
= menu
->prompt
? menu
->prompt
->type
: P_UNKNOWN
;
860 if (ptype
== P_MENU
&& mode
!= listMode
) {
861 if (mode
== singleMode
)
862 emit
itemSelected(menu
);
863 else if (mode
== symbolMode
)
864 emit
menuSelected(menu
);
865 } else if (menu
->sym
)
869 //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
870 Parent::mouseDoubleClickEvent(e
);
873 void ConfigList::focusInEvent(QFocusEvent
*e
)
875 struct menu
*menu
= NULL
;
877 Parent::focusInEvent(e
);
879 ConfigItem
* item
= (ConfigItem
*)currentItem();
881 setSelected(item
, true);
887 void ConfigList::contextMenuEvent(QContextMenuEvent
*e
)
892 headerPopup
= new QMenu(this);
893 action
= new QAction("Show Name", this);
894 action
->setCheckable(true);
895 connect(action
, &QAction::toggled
,
896 this, &ConfigList::setShowName
);
897 connect(this, &ConfigList::showNameChanged
,
898 action
, &QAction::setChecked
);
899 action
->setChecked(showName
);
900 headerPopup
->addAction(action
);
903 headerPopup
->exec(e
->globalPos());
907 void ConfigList::setShowName(bool on
)
914 emit
showNameChanged(on
);
917 QList
<ConfigList
*> ConfigList::allLists
;
918 QAction
*ConfigList::showNormalAction
;
919 QAction
*ConfigList::showAllAction
;
920 QAction
*ConfigList::showPromptAction
;
922 void ConfigList::setAllOpen(bool open
)
924 QTreeWidgetItemIterator
it(this);
927 (*it
)->setExpanded(open
);
933 ConfigInfoView::ConfigInfoView(QWidget
* parent
, const char *name
)
934 : Parent(parent
), sym(0), _menu(0)
939 if (!objectName().isEmpty()) {
940 configSettings
->beginGroup(objectName());
941 setShowDebug(configSettings
->value("/showDebug", false).toBool());
942 configSettings
->endGroup();
943 connect(configApp
, &QApplication::aboutToQuit
,
944 this, &ConfigInfoView::saveSettings
);
947 contextMenu
= createStandardContextMenu();
948 QAction
*action
= new QAction("Show Debug Info", contextMenu
);
950 action
->setCheckable(true);
951 connect(action
, &QAction::toggled
,
952 this, &ConfigInfoView::setShowDebug
);
953 connect(this, &ConfigInfoView::showDebugChanged
,
954 action
, &QAction::setChecked
);
955 action
->setChecked(showDebug());
956 contextMenu
->addSeparator();
957 contextMenu
->addAction(action
);
960 void ConfigInfoView::saveSettings(void)
962 if (!objectName().isEmpty()) {
963 configSettings
->beginGroup(objectName());
964 configSettings
->setValue("/showDebug", showDebug());
965 configSettings
->endGroup();
969 void ConfigInfoView::setShowDebug(bool b
)
971 if (_showDebug
!= b
) {
977 emit
showDebugChanged(b
);
981 void ConfigInfoView::setInfo(struct menu
*m
)
993 void ConfigInfoView::symbolInfo(void)
997 str
+= "<big>Symbol: <b>";
998 str
+= print_filter(sym
->name
);
999 str
+= "</b></big><br><br>value: ";
1000 str
+= print_filter(sym_get_string_value(sym
));
1001 str
+= "<br>visibility: ";
1002 str
+= sym
->visible
== yes
? "y" : sym
->visible
== mod
? "m" : "n";
1004 str
+= debug_info(sym
);
1009 void ConfigInfoView::menuInfo(void)
1013 QTextStream
stream(&info
);
1017 if (_menu
->prompt
) {
1018 stream
<< "<big><b>";
1019 stream
<< print_filter(_menu
->prompt
->text
);
1020 stream
<< "</b></big>";
1024 stream
<< "<a href=\"s" << sym
->name
<< "\">";
1025 stream
<< print_filter(sym
->name
);
1030 } else if (sym
->name
) {
1031 stream
<< "<big><b>";
1033 stream
<< "<a href=\"s" << sym
->name
<< "\">";
1034 stream
<< print_filter(sym
->name
);
1037 stream
<< "</b></big>";
1039 stream
<< "<br><br>";
1042 stream
<< debug_info(sym
);
1044 struct gstr help_gstr
= str_new();
1046 menu_get_ext_help(_menu
, &help_gstr
);
1047 stream
<< print_filter(str_get(&help_gstr
));
1048 str_free(&help_gstr
);
1049 } else if (_menu
->prompt
) {
1050 stream
<< "<big><b>";
1051 stream
<< print_filter(_menu
->prompt
->text
);
1052 stream
<< "</b></big><br><br>";
1054 if (_menu
->prompt
->visible
.expr
) {
1055 stream
<< " dep: ";
1056 expr_print(_menu
->prompt
->visible
.expr
,
1057 expr_print_help
, &stream
, E_NONE
);
1058 stream
<< "<br><br>";
1061 stream
<< "defined at " << _menu
->file
->name
<< ":"
1062 << _menu
->lineno
<< "<br><br>";
1069 QString
ConfigInfoView::debug_info(struct symbol
*sym
)
1072 QTextStream
stream(&debug
);
1075 stream
<< print_filter(sym_type_name(sym
->type
));
1076 if (sym_is_choice(sym
))
1077 stream
<< " (choice)";
1079 if (sym
->rev_dep
.expr
) {
1080 stream
<< "reverse dep: ";
1081 expr_print(sym
->rev_dep
.expr
, expr_print_help
, &stream
, E_NONE
);
1084 for (struct property
*prop
= sym
->prop
; prop
; prop
= prop
->next
) {
1085 switch (prop
->type
) {
1088 stream
<< "prompt: <a href=\"m" << sym
->name
<< "\">";
1089 stream
<< print_filter(prop
->text
);
1090 stream
<< "</a><br>";
1098 stream
<< prop_get_type_name(prop
->type
);
1100 expr_print(prop
->expr
, expr_print_help
,
1105 if (sym_is_choice(sym
)) {
1106 stream
<< "choice: ";
1107 expr_print(prop
->expr
, expr_print_help
,
1113 stream
<< "unknown property: ";
1114 stream
<< prop_get_type_name(prop
->type
);
1117 if (prop
->visible
.expr
) {
1118 stream
<< " dep: ";
1119 expr_print(prop
->visible
.expr
, expr_print_help
,
1129 QString
ConfigInfoView::print_filter(const QString
&str
)
1131 QRegularExpression
re("[<>&\"\\n]");
1133 for (int i
= 0; (i
= res
.indexOf(re
, i
)) >= 0;) {
1134 switch (res
[i
].toLatin1()) {
1136 res
.replace(i
, 1, "<");
1140 res
.replace(i
, 1, ">");
1144 res
.replace(i
, 1, "&");
1148 res
.replace(i
, 1, """);
1152 res
.replace(i
, 1, "<br>");
1160 void ConfigInfoView::expr_print_help(void *data
, struct symbol
*sym
, const char *str
)
1162 QTextStream
*stream
= reinterpret_cast<QTextStream
*>(data
);
1164 if (sym
&& sym
->name
&& !(sym
->flags
& SYMBOL_CONST
)) {
1165 *stream
<< "<a href=\"s" << sym
->name
<< "\">";
1166 *stream
<< print_filter(str
);
1169 *stream
<< print_filter(str
);
1173 void ConfigInfoView::clicked(const QUrl
&url
)
1175 QByteArray str
= url
.toEncoded();
1176 const std::size_t count
= str
.size();
1177 char *data
= new char[count
+ 1];
1178 struct symbol
**result
;
1179 struct menu
*m
= NULL
;
1186 memcpy(data
, str
.constData(), count
);
1189 /* Seek for exact match */
1192 result
= sym_re_search(data
);
1200 /* Seek for the menu which holds the symbol */
1201 for (struct property
*prop
= sym
->prop
; prop
; prop
= prop
->next
) {
1202 if (prop
->type
!= P_PROMPT
&& prop
->type
!= P_MENU
)
1209 /* Symbol is not visible as a menu */
1211 emit
showDebugChanged(true);
1213 emit
menuSelected(m
);
1220 void ConfigInfoView::contextMenuEvent(QContextMenuEvent
*event
)
1222 contextMenu
->popup(event
->globalPos());
1226 ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow
*parent
)
1227 : Parent(parent
), result(NULL
)
1229 setObjectName("search");
1230 setWindowTitle("Search Config");
1232 QVBoxLayout
* layout1
= new QVBoxLayout(this);
1233 layout1
->setContentsMargins(11, 11, 11, 11);
1234 layout1
->setSpacing(6);
1236 QHBoxLayout
* layout2
= new QHBoxLayout();
1237 layout2
->setContentsMargins(0, 0, 0, 0);
1238 layout2
->setSpacing(6);
1239 layout2
->addWidget(new QLabel("Find:", this));
1240 editField
= new QLineEdit(this);
1241 connect(editField
, &QLineEdit::returnPressed
,
1242 this, &ConfigSearchWindow::search
);
1243 layout2
->addWidget(editField
);
1244 searchButton
= new QPushButton("Search", this);
1245 searchButton
->setAutoDefault(false);
1246 connect(searchButton
, &QPushButton::clicked
,
1247 this, &ConfigSearchWindow::search
);
1248 layout2
->addWidget(searchButton
);
1249 layout1
->addLayout(layout2
);
1251 split
= new QSplitter(this);
1252 split
->setOrientation(Qt::Vertical
);
1253 list
= new ConfigList(split
, "search");
1254 list
->mode
= listMode
;
1255 info
= new ConfigInfoView(split
, "search");
1256 connect(list
, &ConfigList::menuChanged
,
1257 info
, &ConfigInfoView::setInfo
);
1258 connect(list
, &ConfigList::menuChanged
,
1259 parent
, &ConfigMainWindow::setMenuLink
);
1261 layout1
->addWidget(split
);
1267 configSettings
->beginGroup("search");
1268 width
= configSettings
->value("/window width", parent
->width() / 2).toInt();
1269 height
= configSettings
->value("/window height", parent
->height() / 2).toInt();
1270 resize(width
, height
);
1271 x
= configSettings
->value("/window x");
1272 y
= configSettings
->value("/window y");
1273 if (x
.isValid() && y
.isValid())
1274 move(x
.toInt(), y
.toInt());
1275 QList
<int> sizes
= configSettings
->readSizes("/split", &ok
);
1277 split
->setSizes(sizes
);
1278 configSettings
->endGroup();
1279 connect(configApp
, &QApplication::aboutToQuit
,
1280 this, &ConfigSearchWindow::saveSettings
);
1283 void ConfigSearchWindow::saveSettings(void)
1285 if (!objectName().isEmpty()) {
1286 configSettings
->beginGroup(objectName());
1287 configSettings
->setValue("/window x", pos().x());
1288 configSettings
->setValue("/window y", pos().y());
1289 configSettings
->setValue("/window width", size().width());
1290 configSettings
->setValue("/window height", size().height());
1291 configSettings
->writeSizes("/split", split
->sizes());
1292 configSettings
->endGroup();
1296 void ConfigSearchWindow::search(void)
1299 struct property
*prop
;
1300 ConfigItem
*lastItem
= NULL
;
1306 result
= sym_re_search(editField
->text().toLatin1());
1309 for (p
= result
; *p
; p
++) {
1310 for_all_prompts((*p
), prop
)
1311 lastItem
= new ConfigItem(list
, lastItem
, prop
->menu
,
1312 menu_is_visible(prop
->menu
));
1317 * Construct the complete config widget
1319 ConfigMainWindow::ConfigMainWindow(void)
1327 snprintf(title
, sizeof(title
), "%s%s",
1328 rootmenu
.prompt
->text
,
1331 setWindowTitle(title
);
1333 QRect g
= configApp
->primaryScreen()->geometry();
1334 width
= configSettings
->value("/window width", g
.width() - 64).toInt();
1335 height
= configSettings
->value("/window height", g
.height() - 64).toInt();
1336 resize(width
, height
);
1337 x
= configSettings
->value("/window x");
1338 y
= configSettings
->value("/window y");
1339 if ((x
.isValid())&&(y
.isValid()))
1340 move(x
.toInt(), y
.toInt());
1343 ConfigItem::symbolYesIcon
= QIcon(QPixmap(xpm_symbol_yes
));
1344 ConfigItem::symbolModIcon
= QIcon(QPixmap(xpm_symbol_mod
));
1345 ConfigItem::symbolNoIcon
= QIcon(QPixmap(xpm_symbol_no
));
1346 ConfigItem::choiceYesIcon
= QIcon(QPixmap(xpm_choice_yes
));
1347 ConfigItem::choiceNoIcon
= QIcon(QPixmap(xpm_choice_no
));
1348 ConfigItem::menuIcon
= QIcon(QPixmap(xpm_menu
));
1349 ConfigItem::menubackIcon
= QIcon(QPixmap(xpm_menuback
));
1351 QWidget
*widget
= new QWidget(this);
1352 QVBoxLayout
*layout
= new QVBoxLayout(widget
);
1353 setCentralWidget(widget
);
1355 split1
= new QSplitter(widget
);
1356 split1
->setOrientation(Qt::Horizontal
);
1357 split1
->setChildrenCollapsible(false);
1359 menuList
= new ConfigList(widget
, "menu");
1361 split2
= new QSplitter(widget
);
1362 split2
->setChildrenCollapsible(false);
1363 split2
->setOrientation(Qt::Vertical
);
1365 // create config tree
1366 configList
= new ConfigList(widget
, "config");
1368 helpText
= new ConfigInfoView(widget
, "help");
1370 layout
->addWidget(split2
);
1371 split2
->addWidget(split1
);
1372 split1
->addWidget(configList
);
1373 split1
->addWidget(menuList
);
1374 split2
->addWidget(helpText
);
1376 setTabOrder(configList
, helpText
);
1377 configList
->setFocus();
1379 backAction
= new QAction(QPixmap(xpm_back
), "Back", this);
1380 connect(backAction
, &QAction::triggered
,
1381 this, &ConfigMainWindow::goBack
);
1383 QAction
*quitAction
= new QAction("&Quit", this);
1384 quitAction
->setShortcut(Qt::CTRL
| Qt::Key_Q
);
1385 connect(quitAction
, &QAction::triggered
,
1386 this, &ConfigMainWindow::close
);
1388 QAction
*loadAction
= new QAction(QPixmap(xpm_load
), "&Load", this);
1389 loadAction
->setShortcut(Qt::CTRL
| Qt::Key_L
);
1390 connect(loadAction
, &QAction::triggered
,
1391 this, &ConfigMainWindow::loadConfig
);
1393 saveAction
= new QAction(QPixmap(xpm_save
), "&Save", this);
1394 saveAction
->setShortcut(Qt::CTRL
| Qt::Key_S
);
1395 connect(saveAction
, &QAction::triggered
,
1396 this, &ConfigMainWindow::saveConfig
);
1398 conf_set_changed_callback(conf_changed
);
1400 // Set saveAction's initial state
1402 configname
= xstrdup(conf_get_configname());
1404 QAction
*saveAsAction
= new QAction("Save &As...", this);
1405 connect(saveAsAction
, &QAction::triggered
,
1406 this, &ConfigMainWindow::saveConfigAs
);
1407 QAction
*searchAction
= new QAction("&Find", this);
1408 searchAction
->setShortcut(Qt::CTRL
| Qt::Key_F
);
1409 connect(searchAction
, &QAction::triggered
,
1410 this, &ConfigMainWindow::searchConfig
);
1411 singleViewAction
= new QAction(QPixmap(xpm_single_view
), "Single View", this);
1412 singleViewAction
->setCheckable(true);
1413 connect(singleViewAction
, &QAction::triggered
,
1414 this, &ConfigMainWindow::showSingleView
);
1415 splitViewAction
= new QAction(QPixmap(xpm_split_view
), "Split View", this);
1416 splitViewAction
->setCheckable(true);
1417 connect(splitViewAction
, &QAction::triggered
,
1418 this, &ConfigMainWindow::showSplitView
);
1419 fullViewAction
= new QAction(QPixmap(xpm_tree_view
), "Full View", this);
1420 fullViewAction
->setCheckable(true);
1421 connect(fullViewAction
, &QAction::triggered
,
1422 this, &ConfigMainWindow::showFullView
);
1424 QAction
*showNameAction
= new QAction("Show Name", this);
1425 showNameAction
->setCheckable(true);
1426 connect(showNameAction
, &QAction::toggled
,
1427 configList
, &ConfigList::setShowName
);
1428 showNameAction
->setChecked(configList
->showName
);
1430 QActionGroup
*optGroup
= new QActionGroup(this);
1431 optGroup
->setExclusive(true);
1432 connect(optGroup
, &QActionGroup::triggered
,
1433 configList
, &ConfigList::setOptionMode
);
1434 connect(optGroup
, &QActionGroup::triggered
,
1435 menuList
, &ConfigList::setOptionMode
);
1437 ConfigList::showNormalAction
= new QAction("Show Normal Options", optGroup
);
1438 ConfigList::showNormalAction
->setCheckable(true);
1439 ConfigList::showAllAction
= new QAction("Show All Options", optGroup
);
1440 ConfigList::showAllAction
->setCheckable(true);
1441 ConfigList::showPromptAction
= new QAction("Show Prompt Options", optGroup
);
1442 ConfigList::showPromptAction
->setCheckable(true);
1444 QAction
*showDebugAction
= new QAction("Show Debug Info", this);
1445 showDebugAction
->setCheckable(true);
1446 connect(showDebugAction
, &QAction::toggled
,
1447 helpText
, &ConfigInfoView::setShowDebug
);
1448 showDebugAction
->setChecked(helpText
->showDebug());
1450 QAction
*showIntroAction
= new QAction("Introduction", this);
1451 connect(showIntroAction
, &QAction::triggered
,
1452 this, &ConfigMainWindow::showIntro
);
1453 QAction
*showAboutAction
= new QAction("About", this);
1454 connect(showAboutAction
, &QAction::triggered
,
1455 this, &ConfigMainWindow::showAbout
);
1458 QToolBar
*toolBar
= addToolBar("Tools");
1459 toolBar
->addAction(backAction
);
1460 toolBar
->addSeparator();
1461 toolBar
->addAction(loadAction
);
1462 toolBar
->addAction(saveAction
);
1463 toolBar
->addSeparator();
1464 toolBar
->addAction(singleViewAction
);
1465 toolBar
->addAction(splitViewAction
);
1466 toolBar
->addAction(fullViewAction
);
1469 QMenu
*menu
= menuBar()->addMenu("&File");
1470 menu
->addAction(loadAction
);
1471 menu
->addAction(saveAction
);
1472 menu
->addAction(saveAsAction
);
1473 menu
->addSeparator();
1474 menu
->addAction(quitAction
);
1477 menu
= menuBar()->addMenu("&Edit");
1478 menu
->addAction(searchAction
);
1480 // create options menu
1481 menu
= menuBar()->addMenu("&Option");
1482 menu
->addAction(showNameAction
);
1483 menu
->addSeparator();
1484 menu
->addActions(optGroup
->actions());
1485 menu
->addSeparator();
1486 menu
->addAction(showDebugAction
);
1489 menu
= menuBar()->addMenu("&Help");
1490 menu
->addAction(showIntroAction
);
1491 menu
->addAction(showAboutAction
);
1493 connect(helpText
, &ConfigInfoView::anchorClicked
,
1494 helpText
, &ConfigInfoView::clicked
);
1496 connect(configList
, &ConfigList::menuChanged
,
1497 helpText
, &ConfigInfoView::setInfo
);
1498 connect(configList
, &ConfigList::menuSelected
,
1499 this, &ConfigMainWindow::changeMenu
);
1500 connect(configList
, &ConfigList::itemSelected
,
1501 this, &ConfigMainWindow::changeItens
);
1502 connect(configList
, &ConfigList::parentSelected
,
1503 this, &ConfigMainWindow::goBack
);
1504 connect(menuList
, &ConfigList::menuChanged
,
1505 helpText
, &ConfigInfoView::setInfo
);
1506 connect(menuList
, &ConfigList::menuSelected
,
1507 this, &ConfigMainWindow::changeMenu
);
1509 connect(configList
, &ConfigList::gotFocus
,
1510 helpText
, &ConfigInfoView::setInfo
);
1511 connect(menuList
, &ConfigList::gotFocus
,
1512 helpText
, &ConfigInfoView::setInfo
);
1513 connect(menuList
, &ConfigList::gotFocus
,
1514 this, &ConfigMainWindow::listFocusChanged
);
1515 connect(helpText
, &ConfigInfoView::menuSelected
,
1516 this, &ConfigMainWindow::setMenuLink
);
1518 QString listMode
= configSettings
->value("/listMode", "symbol").toString();
1519 if (listMode
== "single")
1521 else if (listMode
== "full")
1523 else /*if (listMode == "split")*/
1526 // UI setup done, restore splitter positions
1527 QList
<int> sizes
= configSettings
->readSizes("/split1", &ok
);
1529 split1
->setSizes(sizes
);
1531 sizes
= configSettings
->readSizes("/split2", &ok
);
1533 split2
->setSizes(sizes
);
1536 void ConfigMainWindow::loadConfig(void)
1542 str
= QFileDialog::getOpenFileName(this, "", configname
);
1546 ba
= str
.toLocal8Bit();
1549 if (conf_read(name
))
1550 QMessageBox::information(this, "qconf", "Unable to load configuration!");
1553 configname
= xstrdup(name
);
1555 ConfigList::updateListAllForAll();
1558 bool ConfigMainWindow::saveConfig(void)
1560 if (conf_write(configname
)) {
1561 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1564 conf_write_autoconf(0);
1569 void ConfigMainWindow::saveConfigAs(void)
1575 str
= QFileDialog::getSaveFileName(this, "", configname
);
1579 ba
= str
.toLocal8Bit();
1582 if (conf_write(name
)) {
1583 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1585 conf_write_autoconf(0);
1588 configname
= xstrdup(name
);
1591 void ConfigMainWindow::searchConfig(void)
1594 searchWindow
= new ConfigSearchWindow(this);
1595 searchWindow
->show();
1598 void ConfigMainWindow::changeItens(struct menu
*menu
)
1600 configList
->setRootMenu(menu
);
1603 void ConfigMainWindow::changeMenu(struct menu
*menu
)
1605 menuList
->setRootMenu(menu
);
1608 void ConfigMainWindow::setMenuLink(struct menu
*menu
)
1610 struct menu
*parent
;
1611 ConfigList
* list
= NULL
;
1614 if (configList
->menuSkip(menu
))
1617 switch (configList
->mode
) {
1620 parent
= menu_get_parent_menu(menu
);
1623 list
->setRootMenu(parent
);
1626 if (menu
->flags
& MENU_ROOT
) {
1627 menuList
->setRootMenu(menu
);
1628 configList
->clearSelection();
1631 parent
= menu_get_parent_menu(menu
->parent
);
1635 /* Select the config view */
1636 item
= configList
->findConfigItem(parent
);
1638 configList
->setSelected(item
, true);
1639 configList
->scrollToItem(item
);
1642 menuList
->setRootMenu(parent
);
1643 menuList
->clearSelection();
1655 item
= list
->findConfigItem(menu
);
1657 list
->setSelected(item
, true);
1658 list
->scrollToItem(item
);
1660 helpText
->setInfo(menu
);
1665 void ConfigMainWindow::listFocusChanged(void)
1667 if (menuList
->mode
== menuMode
)
1668 configList
->clearSelection();
1671 void ConfigMainWindow::goBack(void)
1673 if (configList
->rootEntry
== &rootmenu
)
1676 configList
->setParentMenu();
1679 void ConfigMainWindow::showSingleView(void)
1681 singleViewAction
->setEnabled(false);
1682 singleViewAction
->setChecked(true);
1683 splitViewAction
->setEnabled(true);
1684 splitViewAction
->setChecked(false);
1685 fullViewAction
->setEnabled(true);
1686 fullViewAction
->setChecked(false);
1688 backAction
->setEnabled(true);
1691 menuList
->setRootMenu(0);
1692 configList
->mode
= singleMode
;
1693 if (configList
->rootEntry
== &rootmenu
)
1694 configList
->updateListAll();
1696 configList
->setRootMenu(&rootmenu
);
1697 configList
->setFocus();
1700 void ConfigMainWindow::showSplitView(void)
1702 singleViewAction
->setEnabled(true);
1703 singleViewAction
->setChecked(false);
1704 splitViewAction
->setEnabled(false);
1705 splitViewAction
->setChecked(true);
1706 fullViewAction
->setEnabled(true);
1707 fullViewAction
->setChecked(false);
1709 backAction
->setEnabled(false);
1711 configList
->mode
= menuMode
;
1712 if (configList
->rootEntry
== &rootmenu
)
1713 configList
->updateListAll();
1715 configList
->setRootMenu(&rootmenu
);
1716 configList
->setAllOpen(true);
1717 configApp
->processEvents();
1718 menuList
->mode
= symbolMode
;
1719 menuList
->setRootMenu(&rootmenu
);
1720 menuList
->setAllOpen(true);
1722 menuList
->setFocus();
1725 void ConfigMainWindow::showFullView(void)
1727 singleViewAction
->setEnabled(true);
1728 singleViewAction
->setChecked(false);
1729 splitViewAction
->setEnabled(true);
1730 splitViewAction
->setChecked(false);
1731 fullViewAction
->setEnabled(false);
1732 fullViewAction
->setChecked(true);
1734 backAction
->setEnabled(false);
1737 menuList
->setRootMenu(0);
1738 configList
->mode
= fullMode
;
1739 if (configList
->rootEntry
== &rootmenu
)
1740 configList
->updateListAll();
1742 configList
->setRootMenu(&rootmenu
);
1743 configList
->setFocus();
1747 * ask for saving configuration before quitting
1749 void ConfigMainWindow::closeEvent(QCloseEvent
* e
)
1751 if (!conf_get_changed()) {
1756 QMessageBox
mb(QMessageBox::Icon::Warning
, "qconf",
1757 "Save configuration?");
1759 QPushButton
*yb
= mb
.addButton(QMessageBox::Yes
);
1760 QPushButton
*db
= mb
.addButton(QMessageBox::No
);
1761 QPushButton
*cb
= mb
.addButton(QMessageBox::Cancel
);
1763 yb
->setText("&Save Changes");
1764 db
->setText("&Discard Changes");
1765 cb
->setText("Cancel Exit");
1767 mb
.setDefaultButton(yb
);
1768 mb
.setEscapeButton(cb
);
1770 switch (mb
.exec()) {
1771 case QMessageBox::Yes
:
1777 case QMessageBox::No
:
1780 case QMessageBox::Cancel
:
1786 void ConfigMainWindow::showIntro(void)
1788 static const QString str
=
1789 "Welcome to the qconf graphical configuration tool.\n"
1791 "For bool and tristate options, a blank box indicates the "
1792 "feature is disabled, a check indicates it is enabled, and a "
1793 "dot indicates that it is to be compiled as a module. Clicking "
1794 "on the box will cycle through the three states. For int, hex, "
1795 "and string options, double-clicking or pressing F2 on the "
1796 "Value cell will allow you to edit the value.\n"
1798 "If you do not see an option (e.g., a device driver) that you "
1799 "believe should be present, try turning on Show All Options "
1800 "under the Options menu. Enabling Show Debug Info will help you"
1801 "figure out what other options must be enabled to support the "
1802 "option you are interested in, and hyperlinks will navigate to "
1805 "Toggling Show Debug Info under the Options menu will show the "
1806 "dependencies, which you can then match by examining other "
1809 QMessageBox::information(this, "qconf", str
);
1812 void ConfigMainWindow::showAbout(void)
1814 static const QString str
= "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n"
1815 "Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>.\n"
1817 "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n"
1821 QMessageBox::information(this, "qconf", str
+ qVersion());
1824 void ConfigMainWindow::saveSettings(void)
1826 configSettings
->setValue("/window x", pos().x());
1827 configSettings
->setValue("/window y", pos().y());
1828 configSettings
->setValue("/window width", size().width());
1829 configSettings
->setValue("/window height", size().height());
1832 switch(configList
->mode
) {
1848 configSettings
->setValue("/listMode", entry
);
1850 configSettings
->writeSizes("/split1", split1
->sizes());
1851 configSettings
->writeSizes("/split2", split2
->sizes());
1854 void ConfigMainWindow::conf_changed(void)
1857 saveAction
->setEnabled(conf_get_changed());
1860 void fixup_rootmenu(struct menu
*menu
)
1863 static int menu_cnt
= 0;
1865 menu
->flags
|= MENU_ROOT
;
1866 for (child
= menu
->list
; child
; child
= child
->next
) {
1867 if (child
->prompt
&& child
->prompt
->type
== P_MENU
) {
1869 fixup_rootmenu(child
);
1871 } else if (!menu_cnt
)
1872 fixup_rootmenu(child
);
1876 static const char *progname
;
1878 static void usage(void)
1880 printf("%s [-s] <config>\n", progname
);
1884 int main(int ac
, char** av
)
1886 ConfigMainWindow
* v
;
1890 if (ac
> 1 && av
[1][0] == '-') {
1893 conf_set_message_callback(NULL
);
1906 fixup_rootmenu(&rootmenu
);
1908 //zconfdump(stdout);
1910 configApp
= new QApplication(ac
, av
);
1912 configSettings
= new ConfigSettings();
1913 configSettings
->beginGroup("/kconfig/qconf");
1914 v
= new ConfigMainWindow();
1916 //zconfdump(stdout);
1917 configApp
->connect(configApp
, SIGNAL(lastWindowClosed()), SLOT(quit()));
1918 configApp
->connect(configApp
, SIGNAL(aboutToQuit()), v
, SLOT(saveSettings()));
1922 configSettings
->endGroup();
1923 delete configSettings
;