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