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