1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
4 * Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>
5 */
6
7 #include <QAction>
8 #include <QApplication>
9 #include <QCloseEvent>
10 #include <QDebug>
11 #include <QDesktopWidget>
12 #include <QFileDialog>
13 #include <QLabel>
14 #include <QLayout>
15 #include <QList>
16 #include <QMenu>
17 #include <QMenuBar>
18 #include <QMessageBox>
19 #include <QToolBar>
20
21 #include <stdlib.h>
22
23 #include "lkc.h"
24 #include "qconf.h"
25
26 #include "images.h"
27
28
29 static QApplication *configApp;
30 static ConfigSettings *configSettings;
31
32 QAction *ConfigMainWindow::saveAction;
33
ConfigSettings()34 ConfigSettings::ConfigSettings()
35 : QSettings("kernel.org", "qconf")
36 {
37 }
38
39 /**
40 * Reads a list of integer values from the application settings.
41 */
readSizes(const QString & key,bool * ok)42 QList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
43 {
44 QList<int> result;
45
46 if (contains(key))
47 {
48 QStringList entryList = value(key).toStringList();
49 QStringList::Iterator it;
50
51 for (it = entryList.begin(); it != entryList.end(); ++it)
52 result.push_back((*it).toInt());
53
54 *ok = true;
55 }
56 else
57 *ok = false;
58
59 return result;
60 }
61
62 /**
63 * Writes a list of integer values to the application settings.
64 */
writeSizes(const QString & key,const QList<int> & value)65 bool ConfigSettings::writeSizes(const QString& key, const QList<int>& value)
66 {
67 QStringList stringList;
68 QList<int>::ConstIterator it;
69
70 for (it = value.begin(); it != value.end(); ++it)
71 stringList.push_back(QString::number(*it));
72 setValue(key, stringList);
73
74 return true;
75 }
76
77 QIcon ConfigItem::symbolYesIcon;
78 QIcon ConfigItem::symbolModIcon;
79 QIcon ConfigItem::symbolNoIcon;
80 QIcon ConfigItem::choiceYesIcon;
81 QIcon ConfigItem::choiceNoIcon;
82 QIcon ConfigItem::menuIcon;
83 QIcon ConfigItem::menubackIcon;
84
85 /*
86 * update the displayed of a menu entry
87 */
updateMenu(void)88 void ConfigItem::updateMenu(void)
89 {
90 ConfigList* list;
91 struct symbol* sym;
92 struct property *prop;
93 QString prompt;
94 int type;
95 tristate expr;
96
97 list = listView();
98 if (goParent) {
99 setIcon(promptColIdx, menubackIcon);
100 prompt = "..";
101 goto set_prompt;
102 }
103
104 sym = menu->sym;
105 prop = menu->prompt;
106 prompt = menu_get_prompt(menu);
107
108 if (prop) switch (prop->type) {
109 case P_MENU:
110 if (list->mode == singleMode || list->mode == symbolMode) {
111 /* a menuconfig entry is displayed differently
112 * depending whether it's at the view root or a child.
113 */
114 if (sym && list->rootEntry == menu)
115 break;
116 setIcon(promptColIdx, menuIcon);
117 } else {
118 if (sym)
119 break;
120 setIcon(promptColIdx, QIcon());
121 }
122 goto set_prompt;
123 case P_COMMENT:
124 setIcon(promptColIdx, QIcon());
125 goto set_prompt;
126 default:
127 ;
128 }
129 if (!sym)
130 goto set_prompt;
131
132 setText(nameColIdx, sym->name);
133
134 type = sym_get_type(sym);
135 switch (type) {
136 case S_BOOLEAN:
137 case S_TRISTATE:
138 char ch;
139
140 if (!sym_is_changeable(sym) && list->optMode == normalOpt) {
141 setIcon(promptColIdx, QIcon());
142 break;
143 }
144 expr = sym_get_tristate_value(sym);
145 switch (expr) {
146 case yes:
147 if (sym_is_choice_value(sym) && type == S_BOOLEAN)
148 setIcon(promptColIdx, choiceYesIcon);
149 else
150 setIcon(promptColIdx, symbolYesIcon);
151 ch = 'Y';
152 break;
153 case mod:
154 setIcon(promptColIdx, symbolModIcon);
155 ch = 'M';
156 break;
157 default:
158 if (sym_is_choice_value(sym) && type == S_BOOLEAN)
159 setIcon(promptColIdx, choiceNoIcon);
160 else
161 setIcon(promptColIdx, symbolNoIcon);
162 ch = 'N';
163 break;
164 }
165
166 setText(dataColIdx, QChar(ch));
167 break;
168 case S_INT:
169 case S_HEX:
170 case S_STRING:
171 setText(dataColIdx, sym_get_string_value(sym));
172 break;
173 }
174 if (!sym_has_value(sym) && visible)
175 prompt += " (NEW)";
176 set_prompt:
177 setText(promptColIdx, prompt);
178 }
179
testUpdateMenu(bool v)180 void ConfigItem::testUpdateMenu(bool v)
181 {
182 ConfigItem* i;
183
184 visible = v;
185 if (!menu)
186 return;
187
188 sym_calc_value(menu->sym);
189 if (menu->flags & MENU_CHANGED) {
190 /* the menu entry changed, so update all list items */
191 menu->flags &= ~MENU_CHANGED;
192 for (i = (ConfigItem*)menu->data; i; i = i->nextItem)
193 i->updateMenu();
194 } else if (listView()->updateAll)
195 updateMenu();
196 }
197
198
199 /*
200 * construct a menu entry
201 */
init(void)202 void ConfigItem::init(void)
203 {
204 if (menu) {
205 ConfigList* list = listView();
206 nextItem = (ConfigItem*)menu->data;
207 menu->data = this;
208
209 if (list->mode != fullMode)
210 setExpanded(true);
211 sym_calc_value(menu->sym);
212
213 if (menu->sym) {
214 enum symbol_type type = menu->sym->type;
215
216 // Allow to edit "int", "hex", and "string" in-place in
217 // the data column. Unfortunately, you cannot specify
218 // the flags per column. Set ItemIsEditable for all
219 // columns here, and check the column in createEditor().
220 if (type == S_INT || type == S_HEX || type == S_STRING)
221 setFlags(flags() | Qt::ItemIsEditable);
222 }
223 }
224 updateMenu();
225 }
226
227 /*
228 * destruct a menu entry
229 */
~ConfigItem(void)230 ConfigItem::~ConfigItem(void)
231 {
232 if (menu) {
233 ConfigItem** ip = (ConfigItem**)&menu->data;
234 for (; *ip; ip = &(*ip)->nextItem) {
235 if (*ip == this) {
236 *ip = nextItem;
237 break;
238 }
239 }
240 }
241 }
242
createEditor(QWidget * parent,const QStyleOptionViewItem & option,const QModelIndex & index) const243 QWidget *ConfigItemDelegate::createEditor(QWidget *parent,
244 const QStyleOptionViewItem &option,
245 const QModelIndex &index) const
246 {
247 ConfigItem *item;
248
249 // Only the data column is editable
250 if (index.column() != dataColIdx)
251 return nullptr;
252
253 // You cannot edit invisible menus
254 item = static_cast<ConfigItem *>(index.internalPointer());
255 if (!item || !item->menu || !menu_is_visible(item->menu))
256 return nullptr;
257
258 return QStyledItemDelegate::createEditor(parent, option, index);
259 }
260
setModelData(QWidget * editor,QAbstractItemModel * model,const QModelIndex & index) const261 void ConfigItemDelegate::setModelData(QWidget *editor,
262 QAbstractItemModel *model,
263 const QModelIndex &index) const
264 {
265 QLineEdit *lineEdit;
266 ConfigItem *item;
267 struct symbol *sym;
268 bool success;
269
270 lineEdit = qobject_cast<QLineEdit *>(editor);
271 // If this is not a QLineEdit, use the parent's default.
272 // (does this happen?)
273 if (!lineEdit)
274 goto parent;
275
276 item = static_cast<ConfigItem *>(index.internalPointer());
277 if (!item || !item->menu)
278 goto parent;
279
280 sym = item->menu->sym;
281 if (!sym)
282 goto parent;
283
284 success = sym_set_string_value(sym, lineEdit->text().toUtf8().data());
285 if (success) {
286 ConfigList::updateListForAll();
287 } else {
288 QMessageBox::information(editor, "qconf",
289 "Cannot set the data (maybe due to out of range).\n"
290 "Setting the old value.");
291 lineEdit->setText(sym_get_string_value(sym));
292 }
293
294 parent:
295 QStyledItemDelegate::setModelData(editor, model, index);
296 }
297
ConfigList(QWidget * parent,const char * name)298 ConfigList::ConfigList(QWidget *parent, const char *name)
299 : QTreeWidget(parent),
300 updateAll(false),
301 showName(false), mode(singleMode), optMode(normalOpt),
302 rootEntry(0), headerPopup(0)
303 {
304 setObjectName(name);
305 setSortingEnabled(false);
306 setRootIsDecorated(true);
307
308 setVerticalScrollMode(ScrollPerPixel);
309 setHorizontalScrollMode(ScrollPerPixel);
310
311 setHeaderLabels(QStringList() << "Option" << "Name" << "Value");
312
313 connect(this, SIGNAL(itemSelectionChanged(void)),
314 SLOT(updateSelection(void)));
315
316 if (name) {
317 configSettings->beginGroup(name);
318 showName = configSettings->value("/showName", false).toBool();
319 optMode = (enum optionMode)configSettings->value("/optionMode", 0).toInt();
320 configSettings->endGroup();
321 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
322 }
323
324 showColumn(promptColIdx);
325
326 setItemDelegate(new ConfigItemDelegate(this));
327
328 allLists.append(this);
329
330 reinit();
331 }
332
~ConfigList()333 ConfigList::~ConfigList()
334 {
335 allLists.removeOne(this);
336 }
337
menuSkip(struct menu * menu)338 bool ConfigList::menuSkip(struct menu *menu)
339 {
340 if (optMode == normalOpt && menu_is_visible(menu))
341 return false;
342 if (optMode == promptOpt && menu_has_prompt(menu))
343 return false;
344 if (optMode == allOpt)
345 return false;
346 return true;
347 }
348
reinit(void)349 void ConfigList::reinit(void)
350 {
351 hideColumn(nameColIdx);
352
353 if (showName)
354 showColumn(nameColIdx);
355
356 updateListAll();
357 }
358
setOptionMode(QAction * action)359 void ConfigList::setOptionMode(QAction *action)
360 {
361 if (action == showNormalAction)
362 optMode = normalOpt;
363 else if (action == showAllAction)
364 optMode = allOpt;
365 else
366 optMode = promptOpt;
367
368 updateListAll();
369 }
370
saveSettings(void)371 void ConfigList::saveSettings(void)
372 {
373 if (!objectName().isEmpty()) {
374 configSettings->beginGroup(objectName());
375 configSettings->setValue("/showName", showName);
376 configSettings->setValue("/optionMode", (int)optMode);
377 configSettings->endGroup();
378 }
379 }
380
findConfigItem(struct menu * menu)381 ConfigItem* ConfigList::findConfigItem(struct menu *menu)
382 {
383 ConfigItem* item = (ConfigItem*)menu->data;
384
385 for (; item; item = item->nextItem) {
386 if (this == item->listView())
387 break;
388 }
389
390 return item;
391 }
392
updateSelection(void)393 void ConfigList::updateSelection(void)
394 {
395 struct menu *menu;
396 enum prop_type type;
397
398 if (selectedItems().count() == 0)
399 return;
400
401 ConfigItem* item = (ConfigItem*)selectedItems().first();
402 if (!item)
403 return;
404
405 menu = item->menu;
406 emit menuChanged(menu);
407 if (!menu)
408 return;
409 type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
410 if (mode == menuMode && type == P_MENU)
411 emit menuSelected(menu);
412 }
413
updateList()414 void ConfigList::updateList()
415 {
416 ConfigItem* last = 0;
417 ConfigItem *item;
418
419 if (!rootEntry) {
420 if (mode != listMode)
421 goto update;
422 QTreeWidgetItemIterator it(this);
423
424 while (*it) {
425 item = (ConfigItem*)(*it);
426 if (!item->menu)
427 continue;
428 item->testUpdateMenu(menu_is_visible(item->menu));
429
430 ++it;
431 }
432 return;
433 }
434
435 if (rootEntry != &rootmenu && (mode == singleMode ||
436 (mode == symbolMode && rootEntry->parent != &rootmenu))) {
437 item = (ConfigItem *)topLevelItem(0);
438 if (!item)
439 item = new ConfigItem(this, 0, true);
440 last = item;
441 }
442 if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) &&
443 rootEntry->sym && rootEntry->prompt) {
444 item = last ? last->nextSibling() : nullptr;
445 if (!item)
446 item = new ConfigItem(this, last, rootEntry, true);
447 else
448 item->testUpdateMenu(true);
449
450 updateMenuList(item, rootEntry);
451 update();
452 resizeColumnToContents(0);
453 return;
454 }
455 update:
456 updateMenuList(rootEntry);
457 update();
458 resizeColumnToContents(0);
459 }
460
updateListForAll()461 void ConfigList::updateListForAll()
462 {
463 QListIterator<ConfigList *> it(allLists);
464
465 while (it.hasNext()) {
466 ConfigList *list = it.next();
467
468 list->updateList();
469 }
470 }
471
updateListAllForAll()472 void ConfigList::updateListAllForAll()
473 {
474 QListIterator<ConfigList *> it(allLists);
475
476 while (it.hasNext()) {
477 ConfigList *list = it.next();
478
479 list->updateList();
480 }
481 }
482
setValue(ConfigItem * item,tristate val)483 void ConfigList::setValue(ConfigItem* item, tristate val)
484 {
485 struct symbol* sym;
486 int type;
487 tristate oldval;
488
489 sym = item->menu ? item->menu->sym : 0;
490 if (!sym)
491 return;
492
493 type = sym_get_type(sym);
494 switch (type) {
495 case S_BOOLEAN:
496 case S_TRISTATE:
497 oldval = sym_get_tristate_value(sym);
498
499 if (!sym_set_tristate_value(sym, val))
500 return;
501 if (oldval == no && item->menu->list)
502 item->setExpanded(true);
503 ConfigList::updateListForAll();
504 break;
505 }
506 }
507
changeValue(ConfigItem * item)508 void ConfigList::changeValue(ConfigItem* item)
509 {
510 struct symbol* sym;
511 struct menu* menu;
512 int type, oldexpr, newexpr;
513
514 menu = item->menu;
515 if (!menu)
516 return;
517 sym = menu->sym;
518 if (!sym) {
519 if (item->menu->list)
520 item->setExpanded(!item->isExpanded());
521 return;
522 }
523
524 type = sym_get_type(sym);
525 switch (type) {
526 case S_BOOLEAN:
527 case S_TRISTATE:
528 oldexpr = sym_get_tristate_value(sym);
529 newexpr = sym_toggle_tristate_value(sym);
530 if (item->menu->list) {
531 if (oldexpr == newexpr)
532 item->setExpanded(!item->isExpanded());
533 else if (oldexpr == no)
534 item->setExpanded(true);
535 }
536 if (oldexpr != newexpr)
537 ConfigList::updateListForAll();
538 break;
539 default:
540 break;
541 }
542 }
543
setRootMenu(struct menu * menu)544 void ConfigList::setRootMenu(struct menu *menu)
545 {
546 enum prop_type type;
547
548 if (rootEntry == menu)
549 return;
550 type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
551 if (type != P_MENU)
552 return;
553 updateMenuList(0);
554 rootEntry = menu;
555 updateListAll();
556 if (currentItem()) {
557 setSelected(currentItem(), hasFocus());
558 scrollToItem(currentItem());
559 }
560 }
561
setParentMenu(void)562 void ConfigList::setParentMenu(void)
563 {
564 ConfigItem* item;
565 struct menu *oldroot;
566
567 oldroot = rootEntry;
568 if (rootEntry == &rootmenu)
569 return;
570 setRootMenu(menu_get_parent_menu(rootEntry->parent));
571
572 QTreeWidgetItemIterator it(this);
573 while (*it) {
574 item = (ConfigItem *)(*it);
575 if (item->menu == oldroot) {
576 setCurrentItem(item);
577 scrollToItem(item);
578 break;
579 }
580
581 ++it;
582 }
583 }
584
585 /*
586 * update all the children of a menu entry
587 * removes/adds the entries from the parent widget as necessary
588 *
589 * parent: either the menu list widget or a menu entry widget
590 * menu: entry to be updated
591 */
updateMenuList(ConfigItem * parent,struct menu * menu)592 void ConfigList::updateMenuList(ConfigItem *parent, struct menu* menu)
593 {
594 struct menu* child;
595 ConfigItem* item;
596 ConfigItem* last;
597 bool visible;
598 enum prop_type type;
599
600 if (!menu) {
601 while (parent->childCount() > 0)
602 {
603 delete parent->takeChild(0);
604 }
605
606 return;
607 }
608
609 last = parent->firstChild();
610 if (last && !last->goParent)
611 last = 0;
612 for (child = menu->list; child; child = child->next) {
613 item = last ? last->nextSibling() : parent->firstChild();
614 type = child->prompt ? child->prompt->type : P_UNKNOWN;
615
616 switch (mode) {
617 case menuMode:
618 if (!(child->flags & MENU_ROOT))
619 goto hide;
620 break;
621 case symbolMode:
622 if (child->flags & MENU_ROOT)
623 goto hide;
624 break;
625 default:
626 break;
627 }
628
629 visible = menu_is_visible(child);
630 if (!menuSkip(child)) {
631 if (!child->sym && !child->list && !child->prompt)
632 continue;
633 if (!item || item->menu != child)
634 item = new ConfigItem(parent, last, child, visible);
635 else
636 item->testUpdateMenu(visible);
637
638 if (mode == fullMode || mode == menuMode || type != P_MENU)
639 updateMenuList(item, child);
640 else
641 updateMenuList(item, 0);
642 last = item;
643 continue;
644 }
645 hide:
646 if (item && item->menu == child) {
647 last = parent->firstChild();
648 if (last == item)
649 last = 0;
650 else while (last->nextSibling() != item)
651 last = last->nextSibling();
652 delete item;
653 }
654 }
655 }
656
updateMenuList(struct menu * menu)657 void ConfigList::updateMenuList(struct menu *menu)
658 {
659 struct menu* child;
660 ConfigItem* item;
661 ConfigItem* last;
662 bool visible;
663 enum prop_type type;
664
665 if (!menu) {
666 while (topLevelItemCount() > 0)
667 {
668 delete takeTopLevelItem(0);
669 }
670
671 return;
672 }
673
674 last = (ConfigItem *)topLevelItem(0);
675 if (last && !last->goParent)
676 last = 0;
677 for (child = menu->list; child; child = child->next) {
678 item = last ? last->nextSibling() : (ConfigItem *)topLevelItem(0);
679 type = child->prompt ? child->prompt->type : P_UNKNOWN;
680
681 switch (mode) {
682 case menuMode:
683 if (!(child->flags & MENU_ROOT))
684 goto hide;
685 break;
686 case symbolMode:
687 if (child->flags & MENU_ROOT)
688 goto hide;
689 break;
690 default:
691 break;
692 }
693
694 visible = menu_is_visible(child);
695 if (!menuSkip(child)) {
696 if (!child->sym && !child->list && !child->prompt)
697 continue;
698 if (!item || item->menu != child)
699 item = new ConfigItem(this, last, child, visible);
700 else
701 item->testUpdateMenu(visible);
702
703 if (mode == fullMode || mode == menuMode || type != P_MENU)
704 updateMenuList(item, child);
705 else
706 updateMenuList(item, 0);
707 last = item;
708 continue;
709 }
710 hide:
711 if (item && item->menu == child) {
712 last = (ConfigItem *)topLevelItem(0);
713 if (last == item)
714 last = 0;
715 else while (last->nextSibling() != item)
716 last = last->nextSibling();
717 delete item;
718 }
719 }
720 }
721
keyPressEvent(QKeyEvent * ev)722 void ConfigList::keyPressEvent(QKeyEvent* ev)
723 {
724 QTreeWidgetItem* i = currentItem();
725 ConfigItem* item;
726 struct menu *menu;
727 enum prop_type type;
728
729 if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) {
730 emit parentSelected();
731 ev->accept();
732 return;
733 }
734
735 if (!i) {
736 Parent::keyPressEvent(ev);
737 return;
738 }
739 item = (ConfigItem*)i;
740
741 switch (ev->key()) {
742 case Qt::Key_Return:
743 case Qt::Key_Enter:
744 if (item->goParent) {
745 emit parentSelected();
746 break;
747 }
748 menu = item->menu;
749 if (!menu)
750 break;
751 type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
752 if (type == P_MENU && rootEntry != menu &&
753 mode != fullMode && mode != menuMode) {
754 if (mode == menuMode)
755 emit menuSelected(menu);
756 else
757 emit itemSelected(menu);
758 break;
759 }
760 case Qt::Key_Space:
761 changeValue(item);
762 break;
763 case Qt::Key_N:
764 setValue(item, no);
765 break;
766 case Qt::Key_M:
767 setValue(item, mod);
768 break;
769 case Qt::Key_Y:
770 setValue(item, yes);
771 break;
772 default:
773 Parent::keyPressEvent(ev);
774 return;
775 }
776 ev->accept();
777 }
778
mousePressEvent(QMouseEvent * e)779 void ConfigList::mousePressEvent(QMouseEvent* e)
780 {
781 //QPoint p(contentsToViewport(e->pos()));
782 //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
783 Parent::mousePressEvent(e);
784 }
785
mouseReleaseEvent(QMouseEvent * e)786 void ConfigList::mouseReleaseEvent(QMouseEvent* e)
787 {
788 QPoint p = e->pos();
789 ConfigItem* item = (ConfigItem*)itemAt(p);
790 struct menu *menu;
791 enum prop_type ptype;
792 QIcon icon;
793 int idx, x;
794
795 if (!item)
796 goto skip;
797
798 menu = item->menu;
799 x = header()->offset() + p.x();
800 idx = header()->logicalIndexAt(x);
801 switch (idx) {
802 case promptColIdx:
803 icon = item->icon(promptColIdx);
804 if (!icon.isNull()) {
805 int off = header()->sectionPosition(0) + visualRect(indexAt(p)).x() + 4; // 4 is Hardcoded image offset. There might be a way to do it properly.
806 if (x >= off && x < off + icon.availableSizes().first().width()) {
807 if (item->goParent) {
808 emit parentSelected();
809 break;
810 } else if (!menu)
811 break;
812 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
813 if (ptype == P_MENU && rootEntry != menu &&
814 mode != fullMode && mode != menuMode &&
815 mode != listMode)
816 emit menuSelected(menu);
817 else
818 changeValue(item);
819 }
820 }
821 break;
822 case dataColIdx:
823 changeValue(item);
824 break;
825 }
826
827 skip:
828 //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
829 Parent::mouseReleaseEvent(e);
830 }
831
mouseMoveEvent(QMouseEvent * e)832 void ConfigList::mouseMoveEvent(QMouseEvent* e)
833 {
834 //QPoint p(contentsToViewport(e->pos()));
835 //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
836 Parent::mouseMoveEvent(e);
837 }
838
mouseDoubleClickEvent(QMouseEvent * e)839 void ConfigList::mouseDoubleClickEvent(QMouseEvent* e)
840 {
841 QPoint p = e->pos();
842 ConfigItem* item = (ConfigItem*)itemAt(p);
843 struct menu *menu;
844 enum prop_type ptype;
845
846 if (!item)
847 goto skip;
848 if (item->goParent) {
849 emit parentSelected();
850 goto skip;
851 }
852 menu = item->menu;
853 if (!menu)
854 goto skip;
855 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
856 if (ptype == P_MENU && mode != listMode) {
857 if (mode == singleMode)
858 emit itemSelected(menu);
859 else if (mode == symbolMode)
860 emit menuSelected(menu);
861 } else if (menu->sym)
862 changeValue(item);
863
864 skip:
865 //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
866 Parent::mouseDoubleClickEvent(e);
867 }
868
focusInEvent(QFocusEvent * e)869 void ConfigList::focusInEvent(QFocusEvent *e)
870 {
871 struct menu *menu = NULL;
872
873 Parent::focusInEvent(e);
874
875 ConfigItem* item = (ConfigItem *)currentItem();
876 if (item) {
877 setSelected(item, true);
878 menu = item->menu;
879 }
880 emit gotFocus(menu);
881 }
882
contextMenuEvent(QContextMenuEvent * e)883 void ConfigList::contextMenuEvent(QContextMenuEvent *e)
884 {
885 if (!headerPopup) {
886 QAction *action;
887
888 headerPopup = new QMenu(this);
889 action = new QAction("Show Name", this);
890 action->setCheckable(true);
891 connect(action, SIGNAL(toggled(bool)),
892 SLOT(setShowName(bool)));
893 connect(this, SIGNAL(showNameChanged(bool)),
894 action, SLOT(setChecked(bool)));
895 action->setChecked(showName);
896 headerPopup->addAction(action);
897 }
898
899 headerPopup->exec(e->globalPos());
900 e->accept();
901 }
902
setShowName(bool on)903 void ConfigList::setShowName(bool on)
904 {
905 if (showName == on)
906 return;
907
908 showName = on;
909 reinit();
910 emit showNameChanged(on);
911 }
912
913 QList<ConfigList *> ConfigList::allLists;
914 QAction *ConfigList::showNormalAction;
915 QAction *ConfigList::showAllAction;
916 QAction *ConfigList::showPromptAction;
917
setAllOpen(bool open)918 void ConfigList::setAllOpen(bool open)
919 {
920 QTreeWidgetItemIterator it(this);
921
922 while (*it) {
923 (*it)->setExpanded(open);
924
925 ++it;
926 }
927 }
928
ConfigInfoView(QWidget * parent,const char * name)929 ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
930 : Parent(parent), sym(0), _menu(0)
931 {
932 setObjectName(name);
933 setOpenLinks(false);
934
935 if (!objectName().isEmpty()) {
936 configSettings->beginGroup(objectName());
937 setShowDebug(configSettings->value("/showDebug", false).toBool());
938 configSettings->endGroup();
939 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
940 }
941
942 contextMenu = createStandardContextMenu();
943 QAction *action = new QAction("Show Debug Info", contextMenu);
944
945 action->setCheckable(true);
946 connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
947 connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setChecked(bool)));
948 action->setChecked(showDebug());
949 contextMenu->addSeparator();
950 contextMenu->addAction(action);
951 }
952
saveSettings(void)953 void ConfigInfoView::saveSettings(void)
954 {
955 if (!objectName().isEmpty()) {
956 configSettings->beginGroup(objectName());
957 configSettings->setValue("/showDebug", showDebug());
958 configSettings->endGroup();
959 }
960 }
961
setShowDebug(bool b)962 void ConfigInfoView::setShowDebug(bool b)
963 {
964 if (_showDebug != b) {
965 _showDebug = b;
966 if (_menu)
967 menuInfo();
968 else if (sym)
969 symbolInfo();
970 emit showDebugChanged(b);
971 }
972 }
973
setInfo(struct menu * m)974 void ConfigInfoView::setInfo(struct menu *m)
975 {
976 if (_menu == m)
977 return;
978 _menu = m;
979 sym = NULL;
980 if (!_menu)
981 clear();
982 else
983 menuInfo();
984 }
985
symbolInfo(void)986 void ConfigInfoView::symbolInfo(void)
987 {
988 QString str;
989
990 str += "<big>Symbol: <b>";
991 str += print_filter(sym->name);
992 str += "</b></big><br><br>value: ";
993 str += print_filter(sym_get_string_value(sym));
994 str += "<br>visibility: ";
995 str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n";
996 str += "<br>";
997 str += debug_info(sym);
998
999 setText(str);
1000 }
1001
menuInfo(void)1002 void ConfigInfoView::menuInfo(void)
1003 {
1004 struct symbol* sym;
1005 QString info;
1006 QTextStream stream(&info);
1007
1008 sym = _menu->sym;
1009 if (sym) {
1010 if (_menu->prompt) {
1011 stream << "<big><b>";
1012 stream << print_filter(_menu->prompt->text);
1013 stream << "</b></big>";
1014 if (sym->name) {
1015 stream << " (";
1016 if (showDebug())
1017 stream << "<a href=\"s" << sym->name << "\">";
1018 stream << print_filter(sym->name);
1019 if (showDebug())
1020 stream << "</a>";
1021 stream << ")";
1022 }
1023 } else if (sym->name) {
1024 stream << "<big><b>";
1025 if (showDebug())
1026 stream << "<a href=\"s" << sym->name << "\">";
1027 stream << print_filter(sym->name);
1028 if (showDebug())
1029 stream << "</a>";
1030 stream << "</b></big>";
1031 }
1032 stream << "<br><br>";
1033
1034 if (showDebug())
1035 stream << debug_info(sym);
1036
1037 struct gstr help_gstr = str_new();
1038
1039 menu_get_ext_help(_menu, &help_gstr);
1040 stream << print_filter(str_get(&help_gstr));
1041 str_free(&help_gstr);
1042 } else if (_menu->prompt) {
1043 stream << "<big><b>";
1044 stream << print_filter(_menu->prompt->text);
1045 stream << "</b></big><br><br>";
1046 if (showDebug()) {
1047 if (_menu->prompt->visible.expr) {
1048 stream << " dep: ";
1049 expr_print(_menu->prompt->visible.expr,
1050 expr_print_help, &stream, E_NONE);
1051 stream << "<br><br>";
1052 }
1053
1054 stream << "defined at " << _menu->file->name << ":"
1055 << _menu->lineno << "<br><br>";
1056 }
1057 }
1058
1059 setText(info);
1060 }
1061
debug_info(struct symbol * sym)1062 QString ConfigInfoView::debug_info(struct symbol *sym)
1063 {
1064 QString debug;
1065 QTextStream stream(&debug);
1066
1067 stream << "type: ";
1068 stream << print_filter(sym_type_name(sym->type));
1069 if (sym_is_choice(sym))
1070 stream << " (choice)";
1071 debug += "<br>";
1072 if (sym->rev_dep.expr) {
1073 stream << "reverse dep: ";
1074 expr_print(sym->rev_dep.expr, expr_print_help, &stream, E_NONE);
1075 stream << "<br>";
1076 }
1077 for (struct property *prop = sym->prop; prop; prop = prop->next) {
1078 switch (prop->type) {
1079 case P_PROMPT:
1080 case P_MENU:
1081 stream << "prompt: <a href=\"m" << sym->name << "\">";
1082 stream << print_filter(prop->text);
1083 stream << "</a><br>";
1084 break;
1085 case P_DEFAULT:
1086 case P_SELECT:
1087 case P_RANGE:
1088 case P_COMMENT:
1089 case P_IMPLY:
1090 case P_SYMBOL:
1091 stream << prop_get_type_name(prop->type);
1092 stream << ": ";
1093 expr_print(prop->expr, expr_print_help,
1094 &stream, E_NONE);
1095 stream << "<br>";
1096 break;
1097 case P_CHOICE:
1098 if (sym_is_choice(sym)) {
1099 stream << "choice: ";
1100 expr_print(prop->expr, expr_print_help,
1101 &stream, E_NONE);
1102 stream << "<br>";
1103 }
1104 break;
1105 default:
1106 stream << "unknown property: ";
1107 stream << prop_get_type_name(prop->type);
1108 stream << "<br>";
1109 }
1110 if (prop->visible.expr) {
1111 stream << " dep: ";
1112 expr_print(prop->visible.expr, expr_print_help,
1113 &stream, E_NONE);
1114 stream << "<br>";
1115 }
1116 }
1117 stream << "<br>";
1118
1119 return debug;
1120 }
1121
print_filter(const QString & str)1122 QString ConfigInfoView::print_filter(const QString &str)
1123 {
1124 QRegExp re("[<>&\"\\n]");
1125 QString res = str;
1126 for (int i = 0; (i = res.indexOf(re, i)) >= 0;) {
1127 switch (res[i].toLatin1()) {
1128 case '<':
1129 res.replace(i, 1, "<");
1130 i += 4;
1131 break;
1132 case '>':
1133 res.replace(i, 1, ">");
1134 i += 4;
1135 break;
1136 case '&':
1137 res.replace(i, 1, "&");
1138 i += 5;
1139 break;
1140 case '"':
1141 res.replace(i, 1, """);
1142 i += 6;
1143 break;
1144 case '\n':
1145 res.replace(i, 1, "<br>");
1146 i += 4;
1147 break;
1148 }
1149 }
1150 return res;
1151 }
1152
expr_print_help(void * data,struct symbol * sym,const char * str)1153 void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str)
1154 {
1155 QTextStream *stream = reinterpret_cast<QTextStream *>(data);
1156
1157 if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
1158 *stream << "<a href=\"s" << sym->name << "\">";
1159 *stream << print_filter(str);
1160 *stream << "</a>";
1161 } else {
1162 *stream << print_filter(str);
1163 }
1164 }
1165
clicked(const QUrl & url)1166 void ConfigInfoView::clicked(const QUrl &url)
1167 {
1168 QByteArray str = url.toEncoded();
1169 const std::size_t count = str.size();
1170 char *data = new char[count + 1];
1171 struct symbol **result;
1172 struct menu *m = NULL;
1173
1174 if (count < 1) {
1175 delete[] data;
1176 return;
1177 }
1178
1179 memcpy(data, str.constData(), count);
1180 data[count] = '\0';
1181
1182 /* Seek for exact match */
1183 data[0] = '^';
1184 strcat(data, "$");
1185 result = sym_re_search(data);
1186 if (!result) {
1187 delete[] data;
1188 return;
1189 }
1190
1191 sym = *result;
1192
1193 /* Seek for the menu which holds the symbol */
1194 for (struct property *prop = sym->prop; prop; prop = prop->next) {
1195 if (prop->type != P_PROMPT && prop->type != P_MENU)
1196 continue;
1197 m = prop->menu;
1198 break;
1199 }
1200
1201 if (!m) {
1202 /* Symbol is not visible as a menu */
1203 symbolInfo();
1204 emit showDebugChanged(true);
1205 } else {
1206 emit menuSelected(m);
1207 }
1208
1209 free(result);
1210 delete[] data;
1211 }
1212
contextMenuEvent(QContextMenuEvent * event)1213 void ConfigInfoView::contextMenuEvent(QContextMenuEvent *event)
1214 {
1215 contextMenu->popup(event->globalPos());
1216 event->accept();
1217 }
1218
ConfigSearchWindow(ConfigMainWindow * parent)1219 ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow *parent)
1220 : Parent(parent), result(NULL)
1221 {
1222 setObjectName("search");
1223 setWindowTitle("Search Config");
1224
1225 QVBoxLayout* layout1 = new QVBoxLayout(this);
1226 layout1->setContentsMargins(11, 11, 11, 11);
1227 layout1->setSpacing(6);
1228
1229 QHBoxLayout* layout2 = new QHBoxLayout();
1230 layout2->setContentsMargins(0, 0, 0, 0);
1231 layout2->setSpacing(6);
1232 layout2->addWidget(new QLabel("Find:", this));
1233 editField = new QLineEdit(this);
1234 connect(editField, SIGNAL(returnPressed()), SLOT(search()));
1235 layout2->addWidget(editField);
1236 searchButton = new QPushButton("Search", this);
1237 searchButton->setAutoDefault(false);
1238 connect(searchButton, SIGNAL(clicked()), SLOT(search()));
1239 layout2->addWidget(searchButton);
1240 layout1->addLayout(layout2);
1241
1242 split = new QSplitter(this);
1243 split->setOrientation(Qt::Vertical);
1244 list = new ConfigList(split, "search");
1245 list->mode = listMode;
1246 info = new ConfigInfoView(split, "search");
1247 connect(list, SIGNAL(menuChanged(struct menu *)),
1248 info, SLOT(setInfo(struct menu *)));
1249 connect(list, SIGNAL(menuChanged(struct menu *)),
1250 parent, SLOT(setMenuLink(struct menu *)));
1251
1252 layout1->addWidget(split);
1253
1254 QVariant x, y;
1255 int width, height;
1256 bool ok;
1257
1258 configSettings->beginGroup("search");
1259 width = configSettings->value("/window width", parent->width() / 2).toInt();
1260 height = configSettings->value("/window height", parent->height() / 2).toInt();
1261 resize(width, height);
1262 x = configSettings->value("/window x");
1263 y = configSettings->value("/window y");
1264 if (x.isValid() && y.isValid())
1265 move(x.toInt(), y.toInt());
1266 QList<int> sizes = configSettings->readSizes("/split", &ok);
1267 if (ok)
1268 split->setSizes(sizes);
1269 configSettings->endGroup();
1270 connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
1271 }
1272
saveSettings(void)1273 void ConfigSearchWindow::saveSettings(void)
1274 {
1275 if (!objectName().isEmpty()) {
1276 configSettings->beginGroup(objectName());
1277 configSettings->setValue("/window x", pos().x());
1278 configSettings->setValue("/window y", pos().y());
1279 configSettings->setValue("/window width", size().width());
1280 configSettings->setValue("/window height", size().height());
1281 configSettings->writeSizes("/split", split->sizes());
1282 configSettings->endGroup();
1283 }
1284 }
1285
search(void)1286 void ConfigSearchWindow::search(void)
1287 {
1288 struct symbol **p;
1289 struct property *prop;
1290 ConfigItem *lastItem = NULL;
1291
1292 free(result);
1293 list->clear();
1294 info->clear();
1295
1296 result = sym_re_search(editField->text().toLatin1());
1297 if (!result)
1298 return;
1299 for (p = result; *p; p++) {
1300 for_all_prompts((*p), prop)
1301 lastItem = new ConfigItem(list, lastItem, prop->menu,
1302 menu_is_visible(prop->menu));
1303 }
1304 }
1305
1306 /*
1307 * Construct the complete config widget
1308 */
ConfigMainWindow(void)1309 ConfigMainWindow::ConfigMainWindow(void)
1310 : searchWindow(0)
1311 {
1312 bool ok = true;
1313 QVariant x, y;
1314 int width, height;
1315 char title[256];
1316
1317 QDesktopWidget *d = configApp->desktop();
1318 snprintf(title, sizeof(title), "%s%s",
1319 rootmenu.prompt->text,
1320 ""
1321 );
1322 setWindowTitle(title);
1323
1324 width = configSettings->value("/window width", d->width() - 64).toInt();
1325 height = configSettings->value("/window height", d->height() - 64).toInt();
1326 resize(width, height);
1327 x = configSettings->value("/window x");
1328 y = configSettings->value("/window y");
1329 if ((x.isValid())&&(y.isValid()))
1330 move(x.toInt(), y.toInt());
1331
1332 // set up icons
1333 ConfigItem::symbolYesIcon = QIcon(QPixmap(xpm_symbol_yes));
1334 ConfigItem::symbolModIcon = QIcon(QPixmap(xpm_symbol_mod));
1335 ConfigItem::symbolNoIcon = QIcon(QPixmap(xpm_symbol_no));
1336 ConfigItem::choiceYesIcon = QIcon(QPixmap(xpm_choice_yes));
1337 ConfigItem::choiceNoIcon = QIcon(QPixmap(xpm_choice_no));
1338 ConfigItem::menuIcon = QIcon(QPixmap(xpm_menu));
1339 ConfigItem::menubackIcon = QIcon(QPixmap(xpm_menuback));
1340
1341 QWidget *widget = new QWidget(this);
1342 QVBoxLayout *layout = new QVBoxLayout(widget);
1343 setCentralWidget(widget);
1344
1345 split1 = new QSplitter(widget);
1346 split1->setOrientation(Qt::Horizontal);
1347 split1->setChildrenCollapsible(false);
1348
1349 menuList = new ConfigList(widget, "menu");
1350
1351 split2 = new QSplitter(widget);
1352 split2->setChildrenCollapsible(false);
1353 split2->setOrientation(Qt::Vertical);
1354
1355 // create config tree
1356 configList = new ConfigList(widget, "config");
1357
1358 helpText = new ConfigInfoView(widget, "help");
1359
1360 layout->addWidget(split2);
1361 split2->addWidget(split1);
1362 split1->addWidget(configList);
1363 split1->addWidget(menuList);
1364 split2->addWidget(helpText);
1365
1366 setTabOrder(configList, helpText);
1367 configList->setFocus();
1368
1369 backAction = new QAction(QPixmap(xpm_back), "Back", this);
1370 connect(backAction, SIGNAL(triggered(bool)), SLOT(goBack()));
1371
1372 QAction *quitAction = new QAction("&Quit", this);
1373 quitAction->setShortcut(Qt::CTRL + Qt::Key_Q);
1374 connect(quitAction, SIGNAL(triggered(bool)), SLOT(close()));
1375
1376 QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this);
1377 loadAction->setShortcut(Qt::CTRL + Qt::Key_L);
1378 connect(loadAction, SIGNAL(triggered(bool)), SLOT(loadConfig()));
1379
1380 saveAction = new QAction(QPixmap(xpm_save), "&Save", this);
1381 saveAction->setShortcut(Qt::CTRL + Qt::Key_S);
1382 connect(saveAction, SIGNAL(triggered(bool)), SLOT(saveConfig()));
1383
1384 conf_set_changed_callback(conf_changed);
1385
1386 // Set saveAction's initial state
1387 conf_changed();
1388 configname = xstrdup(conf_get_configname());
1389
1390 QAction *saveAsAction = new QAction("Save &As...", this);
1391 connect(saveAsAction, SIGNAL(triggered(bool)), SLOT(saveConfigAs()));
1392 QAction *searchAction = new QAction("&Find", this);
1393 searchAction->setShortcut(Qt::CTRL + Qt::Key_F);
1394 connect(searchAction, SIGNAL(triggered(bool)), SLOT(searchConfig()));
1395 singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this);
1396 singleViewAction->setCheckable(true);
1397 connect(singleViewAction, SIGNAL(triggered(bool)), SLOT(showSingleView()));
1398 splitViewAction = new QAction(QPixmap(xpm_split_view), "Split View", this);
1399 splitViewAction->setCheckable(true);
1400 connect(splitViewAction, SIGNAL(triggered(bool)), SLOT(showSplitView()));
1401 fullViewAction = new QAction(QPixmap(xpm_tree_view), "Full View", this);
1402 fullViewAction->setCheckable(true);
1403 connect(fullViewAction, SIGNAL(triggered(bool)), SLOT(showFullView()));
1404
1405 QAction *showNameAction = new QAction("Show Name", this);
1406 showNameAction->setCheckable(true);
1407 connect(showNameAction, SIGNAL(toggled(bool)), configList, SLOT(setShowName(bool)));
1408 showNameAction->setChecked(configList->showName);
1409
1410 QActionGroup *optGroup = new QActionGroup(this);
1411 optGroup->setExclusive(true);
1412 connect(optGroup, SIGNAL(triggered(QAction*)), configList,
1413 SLOT(setOptionMode(QAction *)));
1414 connect(optGroup, SIGNAL(triggered(QAction *)), menuList,
1415 SLOT(setOptionMode(QAction *)));
1416
1417 ConfigList::showNormalAction = new QAction("Show Normal Options", optGroup);
1418 ConfigList::showNormalAction->setCheckable(true);
1419 ConfigList::showAllAction = new QAction("Show All Options", optGroup);
1420 ConfigList::showAllAction->setCheckable(true);
1421 ConfigList::showPromptAction = new QAction("Show Prompt Options", optGroup);
1422 ConfigList::showPromptAction->setCheckable(true);
1423
1424 QAction *showDebugAction = new QAction("Show Debug Info", this);
1425 showDebugAction->setCheckable(true);
1426 connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
1427 showDebugAction->setChecked(helpText->showDebug());
1428
1429 QAction *showIntroAction = new QAction("Introduction", this);
1430 connect(showIntroAction, SIGNAL(triggered(bool)), SLOT(showIntro()));
1431 QAction *showAboutAction = new QAction("About", this);
1432 connect(showAboutAction, SIGNAL(triggered(bool)), SLOT(showAbout()));
1433
1434 // init tool bar
1435 QToolBar *toolBar = addToolBar("Tools");
1436 toolBar->addAction(backAction);
1437 toolBar->addSeparator();
1438 toolBar->addAction(loadAction);
1439 toolBar->addAction(saveAction);
1440 toolBar->addSeparator();
1441 toolBar->addAction(singleViewAction);
1442 toolBar->addAction(splitViewAction);
1443 toolBar->addAction(fullViewAction);
1444
1445 // create file menu
1446 QMenu *menu = menuBar()->addMenu("&File");
1447 menu->addAction(loadAction);
1448 menu->addAction(saveAction);
1449 menu->addAction(saveAsAction);
1450 menu->addSeparator();
1451 menu->addAction(quitAction);
1452
1453 // create edit menu
1454 menu = menuBar()->addMenu("&Edit");
1455 menu->addAction(searchAction);
1456
1457 // create options menu
1458 menu = menuBar()->addMenu("&Option");
1459 menu->addAction(showNameAction);
1460 menu->addSeparator();
1461 menu->addActions(optGroup->actions());
1462 menu->addSeparator();
1463 menu->addAction(showDebugAction);
1464
1465 // create help menu
1466 menu = menuBar()->addMenu("&Help");
1467 menu->addAction(showIntroAction);
1468 menu->addAction(showAboutAction);
1469
1470 connect (helpText, SIGNAL (anchorClicked (const QUrl &)),
1471 helpText, SLOT (clicked (const QUrl &)) );
1472
1473 connect(configList, SIGNAL(menuChanged(struct menu *)),
1474 helpText, SLOT(setInfo(struct menu *)));
1475 connect(configList, SIGNAL(menuSelected(struct menu *)),
1476 SLOT(changeMenu(struct menu *)));
1477 connect(configList, SIGNAL(itemSelected(struct menu *)),
1478 SLOT(changeItens(struct menu *)));
1479 connect(configList, SIGNAL(parentSelected()),
1480 SLOT(goBack()));
1481 connect(menuList, SIGNAL(menuChanged(struct menu *)),
1482 helpText, SLOT(setInfo(struct menu *)));
1483 connect(menuList, SIGNAL(menuSelected(struct menu *)),
1484 SLOT(changeMenu(struct menu *)));
1485
1486 connect(configList, SIGNAL(gotFocus(struct menu *)),
1487 helpText, SLOT(setInfo(struct menu *)));
1488 connect(menuList, SIGNAL(gotFocus(struct menu *)),
1489 helpText, SLOT(setInfo(struct menu *)));
1490 connect(menuList, SIGNAL(gotFocus(struct menu *)),
1491 SLOT(listFocusChanged(void)));
1492 connect(helpText, SIGNAL(menuSelected(struct menu *)),
1493 SLOT(setMenuLink(struct menu *)));
1494
1495 QString listMode = configSettings->value("/listMode", "symbol").toString();
1496 if (listMode == "single")
1497 showSingleView();
1498 else if (listMode == "full")
1499 showFullView();
1500 else /*if (listMode == "split")*/
1501 showSplitView();
1502
1503 // UI setup done, restore splitter positions
1504 QList<int> sizes = configSettings->readSizes("/split1", &ok);
1505 if (ok)
1506 split1->setSizes(sizes);
1507
1508 sizes = configSettings->readSizes("/split2", &ok);
1509 if (ok)
1510 split2->setSizes(sizes);
1511 }
1512
loadConfig(void)1513 void ConfigMainWindow::loadConfig(void)
1514 {
1515 QString str;
1516 QByteArray ba;
1517 const char *name;
1518
1519 str = QFileDialog::getOpenFileName(this, "", configname);
1520 if (str.isNull())
1521 return;
1522
1523 ba = str.toLocal8Bit();
1524 name = ba.data();
1525
1526 if (conf_read(name))
1527 QMessageBox::information(this, "qconf", "Unable to load configuration!");
1528
1529 free(configname);
1530 configname = xstrdup(name);
1531
1532 ConfigList::updateListAllForAll();
1533 }
1534
saveConfig(void)1535 bool ConfigMainWindow::saveConfig(void)
1536 {
1537 if (conf_write(configname)) {
1538 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1539 return false;
1540 }
1541 conf_write_autoconf(0);
1542
1543 return true;
1544 }
1545
saveConfigAs(void)1546 void ConfigMainWindow::saveConfigAs(void)
1547 {
1548 QString str;
1549 QByteArray ba;
1550 const char *name;
1551
1552 str = QFileDialog::getSaveFileName(this, "", configname);
1553 if (str.isNull())
1554 return;
1555
1556 ba = str.toLocal8Bit();
1557 name = ba.data();
1558
1559 if (conf_write(name)) {
1560 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1561 }
1562 conf_write_autoconf(0);
1563
1564 free(configname);
1565 configname = xstrdup(name);
1566 }
1567
searchConfig(void)1568 void ConfigMainWindow::searchConfig(void)
1569 {
1570 if (!searchWindow)
1571 searchWindow = new ConfigSearchWindow(this);
1572 searchWindow->show();
1573 }
1574
changeItens(struct menu * menu)1575 void ConfigMainWindow::changeItens(struct menu *menu)
1576 {
1577 configList->setRootMenu(menu);
1578 }
1579
changeMenu(struct menu * menu)1580 void ConfigMainWindow::changeMenu(struct menu *menu)
1581 {
1582 menuList->setRootMenu(menu);
1583 }
1584
setMenuLink(struct menu * menu)1585 void ConfigMainWindow::setMenuLink(struct menu *menu)
1586 {
1587 struct menu *parent;
1588 ConfigList* list = NULL;
1589 ConfigItem* item;
1590
1591 if (configList->menuSkip(menu))
1592 return;
1593
1594 switch (configList->mode) {
1595 case singleMode:
1596 list = configList;
1597 parent = menu_get_parent_menu(menu);
1598 if (!parent)
1599 return;
1600 list->setRootMenu(parent);
1601 break;
1602 case menuMode:
1603 if (menu->flags & MENU_ROOT) {
1604 menuList->setRootMenu(menu);
1605 configList->clearSelection();
1606 list = configList;
1607 } else {
1608 parent = menu_get_parent_menu(menu->parent);
1609 if (!parent)
1610 return;
1611
1612 /* Select the config view */
1613 item = configList->findConfigItem(parent);
1614 if (item) {
1615 configList->setSelected(item, true);
1616 configList->scrollToItem(item);
1617 }
1618
1619 menuList->setRootMenu(parent);
1620 menuList->clearSelection();
1621 list = menuList;
1622 }
1623 break;
1624 case fullMode:
1625 list = configList;
1626 break;
1627 default:
1628 break;
1629 }
1630
1631 if (list) {
1632 item = list->findConfigItem(menu);
1633 if (item) {
1634 list->setSelected(item, true);
1635 list->scrollToItem(item);
1636 list->setFocus();
1637 helpText->setInfo(menu);
1638 }
1639 }
1640 }
1641
listFocusChanged(void)1642 void ConfigMainWindow::listFocusChanged(void)
1643 {
1644 if (menuList->mode == menuMode)
1645 configList->clearSelection();
1646 }
1647
goBack(void)1648 void ConfigMainWindow::goBack(void)
1649 {
1650 if (configList->rootEntry == &rootmenu)
1651 return;
1652
1653 configList->setParentMenu();
1654 }
1655
showSingleView(void)1656 void ConfigMainWindow::showSingleView(void)
1657 {
1658 singleViewAction->setEnabled(false);
1659 singleViewAction->setChecked(true);
1660 splitViewAction->setEnabled(true);
1661 splitViewAction->setChecked(false);
1662 fullViewAction->setEnabled(true);
1663 fullViewAction->setChecked(false);
1664
1665 backAction->setEnabled(true);
1666
1667 menuList->hide();
1668 menuList->setRootMenu(0);
1669 configList->mode = singleMode;
1670 if (configList->rootEntry == &rootmenu)
1671 configList->updateListAll();
1672 else
1673 configList->setRootMenu(&rootmenu);
1674 configList->setFocus();
1675 }
1676
showSplitView(void)1677 void ConfigMainWindow::showSplitView(void)
1678 {
1679 singleViewAction->setEnabled(true);
1680 singleViewAction->setChecked(false);
1681 splitViewAction->setEnabled(false);
1682 splitViewAction->setChecked(true);
1683 fullViewAction->setEnabled(true);
1684 fullViewAction->setChecked(false);
1685
1686 backAction->setEnabled(false);
1687
1688 configList->mode = menuMode;
1689 if (configList->rootEntry == &rootmenu)
1690 configList->updateListAll();
1691 else
1692 configList->setRootMenu(&rootmenu);
1693 configList->setAllOpen(true);
1694 configApp->processEvents();
1695 menuList->mode = symbolMode;
1696 menuList->setRootMenu(&rootmenu);
1697 menuList->setAllOpen(true);
1698 menuList->show();
1699 menuList->setFocus();
1700 }
1701
showFullView(void)1702 void ConfigMainWindow::showFullView(void)
1703 {
1704 singleViewAction->setEnabled(true);
1705 singleViewAction->setChecked(false);
1706 splitViewAction->setEnabled(true);
1707 splitViewAction->setChecked(false);
1708 fullViewAction->setEnabled(false);
1709 fullViewAction->setChecked(true);
1710
1711 backAction->setEnabled(false);
1712
1713 menuList->hide();
1714 menuList->setRootMenu(0);
1715 configList->mode = fullMode;
1716 if (configList->rootEntry == &rootmenu)
1717 configList->updateListAll();
1718 else
1719 configList->setRootMenu(&rootmenu);
1720 configList->setFocus();
1721 }
1722
1723 /*
1724 * ask for saving configuration before quitting
1725 */
closeEvent(QCloseEvent * e)1726 void ConfigMainWindow::closeEvent(QCloseEvent* e)
1727 {
1728 if (!conf_get_changed()) {
1729 e->accept();
1730 return;
1731 }
1732 QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning,
1733 QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
1734 mb.setButtonText(QMessageBox::Yes, "&Save Changes");
1735 mb.setButtonText(QMessageBox::No, "&Discard Changes");
1736 mb.setButtonText(QMessageBox::Cancel, "Cancel Exit");
1737 switch (mb.exec()) {
1738 case QMessageBox::Yes:
1739 if (saveConfig())
1740 e->accept();
1741 else
1742 e->ignore();
1743 break;
1744 case QMessageBox::No:
1745 e->accept();
1746 break;
1747 case QMessageBox::Cancel:
1748 e->ignore();
1749 break;
1750 }
1751 }
1752
showIntro(void)1753 void ConfigMainWindow::showIntro(void)
1754 {
1755 static const QString str =
1756 "Welcome to the qconf graphical configuration tool.\n"
1757 "\n"
1758 "For bool and tristate options, a blank box indicates the "
1759 "feature is disabled, a check indicates it is enabled, and a "
1760 "dot indicates that it is to be compiled as a module. Clicking "
1761 "on the box will cycle through the three states. For int, hex, "
1762 "and string options, double-clicking or pressing F2 on the "
1763 "Value cell will allow you to edit the value.\n"
1764 "\n"
1765 "If you do not see an option (e.g., a device driver) that you "
1766 "believe should be present, try turning on Show All Options "
1767 "under the Options menu. Enabling Show Debug Info will help you"
1768 "figure out what other options must be enabled to support the "
1769 "option you are interested in, and hyperlinks will navigate to "
1770 "them.\n"
1771 "\n"
1772 "Toggling Show Debug Info under the Options menu will show the "
1773 "dependencies, which you can then match by examining other "
1774 "options.\n";
1775
1776 QMessageBox::information(this, "qconf", str);
1777 }
1778
showAbout(void)1779 void ConfigMainWindow::showAbout(void)
1780 {
1781 static const QString str = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n"
1782 "Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>.\n\n"
1783 "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n";
1784
1785 QMessageBox::information(this, "qconf", str);
1786 }
1787
saveSettings(void)1788 void ConfigMainWindow::saveSettings(void)
1789 {
1790 configSettings->setValue("/window x", pos().x());
1791 configSettings->setValue("/window y", pos().y());
1792 configSettings->setValue("/window width", size().width());
1793 configSettings->setValue("/window height", size().height());
1794
1795 QString entry;
1796 switch(configList->mode) {
1797 case singleMode :
1798 entry = "single";
1799 break;
1800
1801 case symbolMode :
1802 entry = "split";
1803 break;
1804
1805 case fullMode :
1806 entry = "full";
1807 break;
1808
1809 default:
1810 break;
1811 }
1812 configSettings->setValue("/listMode", entry);
1813
1814 configSettings->writeSizes("/split1", split1->sizes());
1815 configSettings->writeSizes("/split2", split2->sizes());
1816 }
1817
conf_changed(void)1818 void ConfigMainWindow::conf_changed(void)
1819 {
1820 if (saveAction)
1821 saveAction->setEnabled(conf_get_changed());
1822 }
1823
fixup_rootmenu(struct menu * menu)1824 void fixup_rootmenu(struct menu *menu)
1825 {
1826 struct menu *child;
1827 static int menu_cnt = 0;
1828
1829 menu->flags |= MENU_ROOT;
1830 for (child = menu->list; child; child = child->next) {
1831 if (child->prompt && child->prompt->type == P_MENU) {
1832 menu_cnt++;
1833 fixup_rootmenu(child);
1834 menu_cnt--;
1835 } else if (!menu_cnt)
1836 fixup_rootmenu(child);
1837 }
1838 }
1839
1840 static const char *progname;
1841
usage(void)1842 static void usage(void)
1843 {
1844 printf("%s [-s] <config>\n", progname);
1845 exit(0);
1846 }
1847
main(int ac,char ** av)1848 int main(int ac, char** av)
1849 {
1850 ConfigMainWindow* v;
1851 const char *name;
1852
1853 progname = av[0];
1854 if (ac > 1 && av[1][0] == '-') {
1855 switch (av[1][1]) {
1856 case 's':
1857 conf_set_message_callback(NULL);
1858 break;
1859 case 'h':
1860 case '?':
1861 usage();
1862 }
1863 name = av[2];
1864 } else
1865 name = av[1];
1866 if (!name)
1867 usage();
1868
1869 conf_parse(name);
1870 fixup_rootmenu(&rootmenu);
1871 conf_read(NULL);
1872 //zconfdump(stdout);
1873
1874 configApp = new QApplication(ac, av);
1875
1876 configSettings = new ConfigSettings();
1877 configSettings->beginGroup("/kconfig/qconf");
1878 v = new ConfigMainWindow();
1879
1880 //zconfdump(stdout);
1881 configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
1882 configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1883 v->show();
1884 configApp->exec();
1885
1886 configSettings->endGroup();
1887 delete configSettings;
1888 delete v;
1889 delete configApp;
1890
1891 return 0;
1892 }
1893