blob: 0cdbf9dbbd510b27d419a25ab29589515489c794 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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 <qapplication.h>
7#include <qmainwindow.h>
8#include <qtoolbar.h>
9#include <qvbox.h>
10#include <qsplitter.h>
11#include <qlistview.h>
12#include <qtextview.h>
13#include <qlineedit.h>
14#include <qmenubar.h>
15#include <qmessagebox.h>
16#include <qaction.h>
17#include <qheader.h>
18#include <qfiledialog.h>
19#include <qregexp.h>
20
21#include <stdlib.h>
22
23#include "lkc.h"
24#include "qconf.h"
25
26#include "qconf.moc"
27#include "images.c"
28
29static QApplication *configApp;
30
31ConfigSettings::ConfigSettings()
32 : showAll(false), showName(false), showRange(false), showData(false)
33{
34}
35
36#if QT_VERSION >= 300
37/**
38 * Reads the list column settings from the application settings.
39 */
40void ConfigSettings::readListSettings()
41{
42 showAll = readBoolEntry("/kconfig/qconf/showAll", false);
43 showName = readBoolEntry("/kconfig/qconf/showName", false);
44 showRange = readBoolEntry("/kconfig/qconf/showRange", false);
45 showData = readBoolEntry("/kconfig/qconf/showData", false);
46}
47
48/**
49 * Reads a list of integer values from the application settings.
50 */
51QValueList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
52{
53 QValueList<int> result;
54 QStringList entryList = readListEntry(key, ok);
55 if (ok) {
56 QStringList::Iterator it;
57 for (it = entryList.begin(); it != entryList.end(); ++it)
58 result.push_back((*it).toInt());
59 }
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 QValueList<int>& value)
68{
69 QStringList stringList;
70 QValueList<int>::ConstIterator it;
71
72 for (it = value.begin(); it != value.end(); ++it)
73 stringList.push_back(QString::number(*it));
74 return writeEntry(key, stringList);
75}
76#endif
77
78
79/*
80 * update all the children of a menu entry
81 * removes/adds the entries from the parent widget as necessary
82 *
83 * parent: either the menu list widget or a menu entry widget
84 * menu: entry to be updated
85 */
86template <class P>
87void ConfigList::updateMenuList(P* parent, struct menu* menu)
88{
89 struct menu* child;
90 ConfigItem* item;
91 ConfigItem* last;
92 bool visible;
93 enum prop_type type;
94
95 if (!menu) {
96 while ((item = parent->firstChild()))
97 delete item;
98 return;
99 }
100
101 last = parent->firstChild();
102 if (last && !last->goParent)
103 last = 0;
104 for (child = menu->list; child; child = child->next) {
105 item = last ? last->nextSibling() : parent->firstChild();
106 type = child->prompt ? child->prompt->type : P_UNKNOWN;
107
108 switch (mode) {
109 case menuMode:
110 if (!(child->flags & MENU_ROOT))
111 goto hide;
112 break;
113 case symbolMode:
114 if (child->flags & MENU_ROOT)
115 goto hide;
116 break;
117 default:
118 break;
119 }
120
121 visible = menu_is_visible(child);
122 if (showAll || visible) {
123 if (!item || item->menu != child)
124 item = new ConfigItem(parent, last, child, visible);
125 else
126 item->testUpdateMenu(visible);
127
128 if (mode == fullMode || mode == menuMode || type != P_MENU)
129 updateMenuList(item, child);
130 else
131 updateMenuList(item, 0);
132 last = item;
133 continue;
134 }
135 hide:
136 if (item && item->menu == child) {
137 last = parent->firstChild();
138 if (last == item)
139 last = 0;
140 else while (last->nextSibling() != item)
141 last = last->nextSibling();
142 delete item;
143 }
144 }
145}
146
147#if QT_VERSION >= 300
148/*
149 * set the new data
150 * TODO check the value
151 */
152void ConfigItem::okRename(int col)
153{
154 Parent::okRename(col);
155 sym_set_string_value(menu->sym, text(dataColIdx).latin1());
156}
157#endif
158
159/*
160 * update the displayed of a menu entry
161 */
162void ConfigItem::updateMenu(void)
163{
164 ConfigList* list;
165 struct symbol* sym;
166 struct property *prop;
167 QString prompt;
168 int type;
169 tristate expr;
170
171 list = listView();
172 if (goParent) {
173 setPixmap(promptColIdx, list->menuBackPix);
174 prompt = "..";
175 goto set_prompt;
176 }
177
178 sym = menu->sym;
179 prop = menu->prompt;
180 prompt = menu_get_prompt(menu);
181
182 if (prop) switch (prop->type) {
183 case P_MENU:
184 if (list->mode == singleMode || list->mode == symbolMode) {
185 /* a menuconfig entry is displayed differently
186 * depending whether it's at the view root or a child.
187 */
188 if (sym && list->rootEntry == menu)
189 break;
190 setPixmap(promptColIdx, list->menuPix);
191 } else {
192 if (sym)
193 break;
194 setPixmap(promptColIdx, 0);
195 }
196 goto set_prompt;
197 case P_COMMENT:
198 setPixmap(promptColIdx, 0);
199 goto set_prompt;
200 default:
201 ;
202 }
203 if (!sym)
204 goto set_prompt;
205
206 setText(nameColIdx, sym->name);
207
208 type = sym_get_type(sym);
209 switch (type) {
210 case S_BOOLEAN:
211 case S_TRISTATE:
212 char ch;
213
214 if (!sym_is_changable(sym) && !list->showAll) {
215 setPixmap(promptColIdx, 0);
216 setText(noColIdx, 0);
217 setText(modColIdx, 0);
218 setText(yesColIdx, 0);
219 break;
220 }
221 expr = sym_get_tristate_value(sym);
222 switch (expr) {
223 case yes:
224 if (sym_is_choice_value(sym) && type == S_BOOLEAN)
225 setPixmap(promptColIdx, list->choiceYesPix);
226 else
227 setPixmap(promptColIdx, list->symbolYesPix);
228 setText(yesColIdx, "Y");
229 ch = 'Y';
230 break;
231 case mod:
232 setPixmap(promptColIdx, list->symbolModPix);
233 setText(modColIdx, "M");
234 ch = 'M';
235 break;
236 default:
237 if (sym_is_choice_value(sym) && type == S_BOOLEAN)
238 setPixmap(promptColIdx, list->choiceNoPix);
239 else
240 setPixmap(promptColIdx, list->symbolNoPix);
241 setText(noColIdx, "N");
242 ch = 'N';
243 break;
244 }
245 if (expr != no)
246 setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0);
247 if (expr != mod)
248 setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0);
249 if (expr != yes)
250 setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0);
251
252 setText(dataColIdx, QChar(ch));
253 break;
254 case S_INT:
255 case S_HEX:
256 case S_STRING:
257 const char* data;
258
259 data = sym_get_string_value(sym);
260#if QT_VERSION >= 300
261 int i = list->mapIdx(dataColIdx);
262 if (i >= 0)
263 setRenameEnabled(i, TRUE);
264#endif
265 setText(dataColIdx, data);
266 if (type == S_STRING)
267 prompt.sprintf("%s: %s", prompt.latin1(), data);
268 else
269 prompt.sprintf("(%s) %s", data, prompt.latin1());
270 break;
271 }
272 if (!sym_has_value(sym) && visible)
273 prompt += " (NEW)";
274set_prompt:
275 setText(promptColIdx, prompt);
276}
277
278void ConfigItem::testUpdateMenu(bool v)
279{
280 ConfigItem* i;
281
282 visible = v;
283 if (!menu)
284 return;
285
286 sym_calc_value(menu->sym);
287 if (menu->flags & MENU_CHANGED) {
288 /* the menu entry changed, so update all list items */
289 menu->flags &= ~MENU_CHANGED;
290 for (i = (ConfigItem*)menu->data; i; i = i->nextItem)
291 i->updateMenu();
292 } else if (listView()->updateAll)
293 updateMenu();
294}
295
296void ConfigItem::paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align)
297{
298 ConfigList* list = listView();
299
300 if (visible) {
301 if (isSelected() && !list->hasFocus() && list->mode == menuMode)
302 Parent::paintCell(p, list->inactivedColorGroup, column, width, align);
303 else
304 Parent::paintCell(p, cg, column, width, align);
305 } else
306 Parent::paintCell(p, list->disabledColorGroup, column, width, align);
307}
308
309/*
310 * construct a menu entry
311 */
312void ConfigItem::init(void)
313{
314 if (menu) {
315 ConfigList* list = listView();
316 nextItem = (ConfigItem*)menu->data;
317 menu->data = this;
318
319 if (list->mode != fullMode)
320 setOpen(TRUE);
321 sym_calc_value(menu->sym);
322 }
323 updateMenu();
324}
325
326/*
327 * destruct a menu entry
328 */
329ConfigItem::~ConfigItem(void)
330{
331 if (menu) {
332 ConfigItem** ip = (ConfigItem**)&menu->data;
333 for (; *ip; ip = &(*ip)->nextItem) {
334 if (*ip == this) {
335 *ip = nextItem;
336 break;
337 }
338 }
339 }
340}
341
342void ConfigLineEdit::show(ConfigItem* i)
343{
344 item = i;
345 if (sym_get_string_value(item->menu->sym))
346 setText(sym_get_string_value(item->menu->sym));
347 else
348 setText(0);
349 Parent::show();
350 setFocus();
351}
352
353void ConfigLineEdit::keyPressEvent(QKeyEvent* e)
354{
355 switch (e->key()) {
356 case Key_Escape:
357 break;
358 case Key_Return:
359 case Key_Enter:
360 sym_set_string_value(item->menu->sym, text().latin1());
361 parent()->updateList(item);
362 break;
363 default:
364 Parent::keyPressEvent(e);
365 return;
366 }
367 e->accept();
368 parent()->list->setFocus();
369 hide();
370}
371
372ConfigList::ConfigList(ConfigView* p, ConfigMainWindow* cv, ConfigSettings* configSettings)
373 : Parent(p), cview(cv),
374 updateAll(false),
375 symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no),
376 choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no),
377 menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void),
378 showAll(false), showName(false), showRange(false), showData(false),
379 rootEntry(0)
380{
381 int i;
382
383 setSorting(-1);
384 setRootIsDecorated(TRUE);
385 disabledColorGroup = palette().active();
386 disabledColorGroup.setColor(QColorGroup::Text, palette().disabled().text());
387 inactivedColorGroup = palette().active();
388 inactivedColorGroup.setColor(QColorGroup::Highlight, palette().disabled().highlight());
389
390 connect(this, SIGNAL(selectionChanged(void)),
391 SLOT(updateSelection(void)));
392
393 if (configSettings) {
394 showAll = configSettings->showAll;
395 showName = configSettings->showName;
396 showRange = configSettings->showRange;
397 showData = configSettings->showData;
398 }
399
400 for (i = 0; i < colNr; i++)
401 colMap[i] = colRevMap[i] = -1;
402 addColumn(promptColIdx, "Option");
403
404 reinit();
405}
406
407void ConfigList::reinit(void)
408{
409 removeColumn(dataColIdx);
410 removeColumn(yesColIdx);
411 removeColumn(modColIdx);
412 removeColumn(noColIdx);
413 removeColumn(nameColIdx);
414
415 if (showName)
416 addColumn(nameColIdx, "Name");
417 if (showRange) {
418 addColumn(noColIdx, "N");
419 addColumn(modColIdx, "M");
420 addColumn(yesColIdx, "Y");
421 }
422 if (showData)
423 addColumn(dataColIdx, "Value");
424
425 updateListAll();
426}
427
428void ConfigList::updateSelection(void)
429{
430 struct menu *menu;
431 enum prop_type type;
432
433 ConfigItem* item = (ConfigItem*)selectedItem();
434 if (!item)
435 return;
436
437 cview->setHelp(item);
438
439 menu = item->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 goto update;
453
454 if (rootEntry != &rootmenu && (mode == singleMode ||
455 (mode == symbolMode && rootEntry->parent != &rootmenu))) {
456 item = firstChild();
457 if (!item)
458 item = new ConfigItem(this, 0, true);
459 last = item;
460 }
461 if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) &&
462 rootEntry->sym && rootEntry->prompt) {
463 item = last ? last->nextSibling() : firstChild();
464 if (!item)
465 item = new ConfigItem(this, last, rootEntry, true);
466 else
467 item->testUpdateMenu(true);
468
469 updateMenuList(item, rootEntry);
470 triggerUpdate();
471 return;
472 }
473update:
474 updateMenuList(this, rootEntry);
475 triggerUpdate();
476}
477
478void ConfigList::setAllOpen(bool open)
479{
480 QListViewItemIterator it(this);
481
482 for (; it.current(); it++)
483 it.current()->setOpen(open);
484}
485
486void ConfigList::setValue(ConfigItem* item, tristate val)
487{
488 struct symbol* sym;
489 int type;
490 tristate oldval;
491
492 sym = item->menu ? item->menu->sym : 0;
493 if (!sym)
494 return;
495
496 type = sym_get_type(sym);
497 switch (type) {
498 case S_BOOLEAN:
499 case S_TRISTATE:
500 oldval = sym_get_tristate_value(sym);
501
502 if (!sym_set_tristate_value(sym, val))
503 return;
504 if (oldval == no && item->menu->list)
505 item->setOpen(TRUE);
506 parent()->updateList(item);
507 break;
508 }
509}
510
511void ConfigList::changeValue(ConfigItem* item)
512{
513 struct symbol* sym;
514 struct menu* menu;
515 int type, oldexpr, newexpr;
516
517 menu = item->menu;
518 if (!menu)
519 return;
520 sym = menu->sym;
521 if (!sym) {
522 if (item->menu->list)
523 item->setOpen(!item->isOpen());
524 return;
525 }
526
527 type = sym_get_type(sym);
528 switch (type) {
529 case S_BOOLEAN:
530 case S_TRISTATE:
531 oldexpr = sym_get_tristate_value(sym);
532 newexpr = sym_toggle_tristate_value(sym);
533 if (item->menu->list) {
534 if (oldexpr == newexpr)
535 item->setOpen(!item->isOpen());
536 else if (oldexpr == no)
537 item->setOpen(TRUE);
538 }
539 if (oldexpr != newexpr)
540 parent()->updateList(item);
541 break;
542 case S_INT:
543 case S_HEX:
544 case S_STRING:
545#if QT_VERSION >= 300
546 if (colMap[dataColIdx] >= 0)
547 item->startRename(colMap[dataColIdx]);
548 else
549#endif
550 parent()->lineEdit->show(item);
551 break;
552 }
553}
554
555void ConfigList::setRootMenu(struct menu *menu)
556{
557 enum prop_type type;
558
559 if (rootEntry == menu)
560 return;
561 type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
562 if (type != P_MENU)
563 return;
564 updateMenuList(this, 0);
565 rootEntry = menu;
566 updateListAll();
567 setSelected(currentItem(), hasFocus());
568}
569
570void ConfigList::setParentMenu(void)
571{
572 ConfigItem* item;
573 struct menu *oldroot;
574
575 oldroot = rootEntry;
576 if (rootEntry == &rootmenu)
577 return;
578 setRootMenu(menu_get_parent_menu(rootEntry->parent));
579
580 QListViewItemIterator it(this);
581 for (; (item = (ConfigItem*)it.current()); it++) {
582 if (item->menu == oldroot) {
583 setCurrentItem(item);
584 ensureItemVisible(item);
585 break;
586 }
587 }
588}
589
590void ConfigList::keyPressEvent(QKeyEvent* ev)
591{
592 QListViewItem* i = currentItem();
593 ConfigItem* item;
594 struct menu *menu;
595 enum prop_type type;
596
597 if (ev->key() == Key_Escape && mode != fullMode) {
598 emit parentSelected();
599 ev->accept();
600 return;
601 }
602
603 if (!i) {
604 Parent::keyPressEvent(ev);
605 return;
606 }
607 item = (ConfigItem*)i;
608
609 switch (ev->key()) {
610 case Key_Return:
611 case Key_Enter:
612 if (item->goParent) {
613 emit parentSelected();
614 break;
615 }
616 menu = item->menu;
617 if (!menu)
618 break;
619 type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
620 if (type == P_MENU && rootEntry != menu &&
621 mode != fullMode && mode != menuMode) {
622 emit menuSelected(menu);
623 break;
624 }
625 case Key_Space:
626 changeValue(item);
627 break;
628 case Key_N:
629 setValue(item, no);
630 break;
631 case Key_M:
632 setValue(item, mod);
633 break;
634 case Key_Y:
635 setValue(item, yes);
636 break;
637 default:
638 Parent::keyPressEvent(ev);
639 return;
640 }
641 ev->accept();
642}
643
644void ConfigList::contentsMousePressEvent(QMouseEvent* e)
645{
646 //QPoint p(contentsToViewport(e->pos()));
647 //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
648 Parent::contentsMousePressEvent(e);
649}
650
651void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e)
652{
653 QPoint p(contentsToViewport(e->pos()));
654 ConfigItem* item = (ConfigItem*)itemAt(p);
655 struct menu *menu;
656 enum prop_type ptype;
657 const QPixmap* pm;
658 int idx, x;
659
660 if (!item)
661 goto skip;
662
663 menu = item->menu;
664 x = header()->offset() + p.x();
665 idx = colRevMap[header()->sectionAt(x)];
666 switch (idx) {
667 case promptColIdx:
668 pm = item->pixmap(promptColIdx);
669 if (pm) {
670 int off = header()->sectionPos(0) + itemMargin() +
671 treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0));
672 if (x >= off && x < off + pm->width()) {
673 if (item->goParent) {
674 emit parentSelected();
675 break;
676 } else if (!menu)
677 break;
678 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
679 if (ptype == P_MENU && rootEntry != menu &&
680 mode != fullMode && mode != menuMode)
681 emit menuSelected(menu);
682 else
683 changeValue(item);
684 }
685 }
686 break;
687 case noColIdx:
688 setValue(item, no);
689 break;
690 case modColIdx:
691 setValue(item, mod);
692 break;
693 case yesColIdx:
694 setValue(item, yes);
695 break;
696 case dataColIdx:
697 changeValue(item);
698 break;
699 }
700
701skip:
702 //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
703 Parent::contentsMouseReleaseEvent(e);
704}
705
706void ConfigList::contentsMouseMoveEvent(QMouseEvent* e)
707{
708 //QPoint p(contentsToViewport(e->pos()));
709 //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
710 Parent::contentsMouseMoveEvent(e);
711}
712
713void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e)
714{
715 QPoint p(contentsToViewport(e->pos()));
716 ConfigItem* item = (ConfigItem*)itemAt(p);
717 struct menu *menu;
718 enum prop_type ptype;
719
720 if (!item)
721 goto skip;
722 if (item->goParent) {
723 emit parentSelected();
724 goto skip;
725 }
726 menu = item->menu;
727 if (!menu)
728 goto skip;
729 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
730 if (ptype == P_MENU && (mode == singleMode || mode == symbolMode))
731 emit menuSelected(menu);
732 else if (menu->sym)
733 changeValue(item);
734
735skip:
736 //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
737 Parent::contentsMouseDoubleClickEvent(e);
738}
739
740void ConfigList::focusInEvent(QFocusEvent *e)
741{
742 Parent::focusInEvent(e);
743
744 QListViewItem* item = currentItem();
745 if (!item)
746 return;
747
748 setSelected(item, TRUE);
749 emit gotFocus();
750}
751
752ConfigView* ConfigView::viewList;
753
754ConfigView::ConfigView(QWidget* parent, ConfigMainWindow* cview,
755 ConfigSettings *configSettings)
756 : Parent(parent)
757{
758 list = new ConfigList(this, cview, configSettings);
759 lineEdit = new ConfigLineEdit(this);
760 lineEdit->hide();
761
762 this->nextView = viewList;
763 viewList = this;
764}
765
766ConfigView::~ConfigView(void)
767{
768 ConfigView** vp;
769
770 for (vp = &viewList; *vp; vp = &(*vp)->nextView) {
771 if (*vp == this) {
772 *vp = nextView;
773 break;
774 }
775 }
776}
777
778void ConfigView::updateList(ConfigItem* item)
779{
780 ConfigView* v;
781
782 for (v = viewList; v; v = v->nextView)
783 v->list->updateList(item);
784}
785
786void ConfigView::updateListAll(void)
787{
788 ConfigView* v;
789
790 for (v = viewList; v; v = v->nextView)
791 v->list->updateListAll();
792}
793
794/*
795 * Construct the complete config widget
796 */
797ConfigMainWindow::ConfigMainWindow(void)
798{
799 QMenuBar* menu;
800 bool ok;
801 int x, y, width, height;
802
803 QWidget *d = configApp->desktop();
804
805 ConfigSettings* configSettings = new ConfigSettings();
806#if QT_VERSION >= 300
807 width = configSettings->readNumEntry("/kconfig/qconf/window width", d->width() - 64);
808 height = configSettings->readNumEntry("/kconfig/qconf/window height", d->height() - 64);
809 resize(width, height);
810 x = configSettings->readNumEntry("/kconfig/qconf/window x", 0, &ok);
811 if (ok)
812 y = configSettings->readNumEntry("/kconfig/qconf/window y", 0, &ok);
813 if (ok)
814 move(x, y);
815 showDebug = configSettings->readBoolEntry("/kconfig/qconf/showDebug", false);
816
817 // read list settings into configSettings, will be used later for ConfigList setup
818 configSettings->readListSettings();
819#else
820 width = d->width() - 64;
821 height = d->height() - 64;
822 resize(width, height);
823 showDebug = false;
824#endif
825
826 split1 = new QSplitter(this);
827 split1->setOrientation(QSplitter::Horizontal);
828 setCentralWidget(split1);
829
830 menuView = new ConfigView(split1, this, configSettings);
831 menuList = menuView->list;
832
833 split2 = new QSplitter(split1);
834 split2->setOrientation(QSplitter::Vertical);
835
836 // create config tree
837 configView = new ConfigView(split2, this, configSettings);
838 configList = configView->list;
839
840 helpText = new QTextView(split2);
841 helpText->setTextFormat(Qt::RichText);
842
843 setTabOrder(configList, helpText);
844 configList->setFocus();
845
846 menu = menuBar();
847 toolBar = new QToolBar("Tools", this);
848
849 backAction = new QAction("Back", QPixmap(xpm_back), "Back", 0, this);
850 connect(backAction, SIGNAL(activated()), SLOT(goBack()));
851 backAction->setEnabled(FALSE);
852 QAction *quitAction = new QAction("Quit", "&Quit", CTRL+Key_Q, this);
853 connect(quitAction, SIGNAL(activated()), SLOT(close()));
854 QAction *loadAction = new QAction("Load", QPixmap(xpm_load), "&Load", CTRL+Key_L, this);
855 connect(loadAction, SIGNAL(activated()), SLOT(loadConfig()));
856 QAction *saveAction = new QAction("Save", QPixmap(xpm_save), "&Save", CTRL+Key_S, this);
857 connect(saveAction, SIGNAL(activated()), SLOT(saveConfig()));
858 QAction *saveAsAction = new QAction("Save As...", "Save &As...", 0, this);
859 connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs()));
860 QAction *singleViewAction = new QAction("Single View", QPixmap(xpm_single_view), "Split View", 0, this);
861 connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView()));
862 QAction *splitViewAction = new QAction("Split View", QPixmap(xpm_split_view), "Split View", 0, this);
863 connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView()));
864 QAction *fullViewAction = new QAction("Full View", QPixmap(xpm_tree_view), "Full View", 0, this);
865 connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView()));
866
867 QAction *showNameAction = new QAction(NULL, "Show Name", 0, this);
868 showNameAction->setToggleAction(TRUE);
869 showNameAction->setOn(configList->showName);
870 connect(showNameAction, SIGNAL(toggled(bool)), SLOT(setShowName(bool)));
871 QAction *showRangeAction = new QAction(NULL, "Show Range", 0, this);
872 showRangeAction->setToggleAction(TRUE);
873 showRangeAction->setOn(configList->showRange);
874 connect(showRangeAction, SIGNAL(toggled(bool)), SLOT(setShowRange(bool)));
875 QAction *showDataAction = new QAction(NULL, "Show Data", 0, this);
876 showDataAction->setToggleAction(TRUE);
877 showDataAction->setOn(configList->showData);
878 connect(showDataAction, SIGNAL(toggled(bool)), SLOT(setShowData(bool)));
879 QAction *showAllAction = new QAction(NULL, "Show All Options", 0, this);
880 showAllAction->setToggleAction(TRUE);
881 showAllAction->setOn(configList->showAll);
882 connect(showAllAction, SIGNAL(toggled(bool)), SLOT(setShowAll(bool)));
883 QAction *showDebugAction = new QAction(NULL, "Show Debug Info", 0, this);
884 showDebugAction->setToggleAction(TRUE);
885 showDebugAction->setOn(showDebug);
886 connect(showDebugAction, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
887
888 QAction *showIntroAction = new QAction(NULL, "Introduction", 0, this);
889 connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro()));
890 QAction *showAboutAction = new QAction(NULL, "About", 0, this);
891 connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout()));
892
893 // init tool bar
894 backAction->addTo(toolBar);
895 toolBar->addSeparator();
896 loadAction->addTo(toolBar);
897 saveAction->addTo(toolBar);
898 toolBar->addSeparator();
899 singleViewAction->addTo(toolBar);
900 splitViewAction->addTo(toolBar);
901 fullViewAction->addTo(toolBar);
902
903 // create config menu
904 QPopupMenu* config = new QPopupMenu(this);
905 menu->insertItem("&File", config);
906 loadAction->addTo(config);
907 saveAction->addTo(config);
908 saveAsAction->addTo(config);
909 config->insertSeparator();
910 quitAction->addTo(config);
911
912 // create options menu
913 QPopupMenu* optionMenu = new QPopupMenu(this);
914 menu->insertItem("&Option", optionMenu);
915 showNameAction->addTo(optionMenu);
916 showRangeAction->addTo(optionMenu);
917 showDataAction->addTo(optionMenu);
918 optionMenu->insertSeparator();
919 showAllAction->addTo(optionMenu);
920 showDebugAction->addTo(optionMenu);
921
922 // create help menu
923 QPopupMenu* helpMenu = new QPopupMenu(this);
924 menu->insertSeparator();
925 menu->insertItem("&Help", helpMenu);
926 showIntroAction->addTo(helpMenu);
927 showAboutAction->addTo(helpMenu);
928
929 connect(configList, SIGNAL(menuSelected(struct menu *)),
930 SLOT(changeMenu(struct menu *)));
931 connect(configList, SIGNAL(parentSelected()),
932 SLOT(goBack()));
933 connect(menuList, SIGNAL(menuSelected(struct menu *)),
934 SLOT(changeMenu(struct menu *)));
935
936 connect(configList, SIGNAL(gotFocus(void)),
937 SLOT(listFocusChanged(void)));
938 connect(menuList, SIGNAL(gotFocus(void)),
939 SLOT(listFocusChanged(void)));
940
941#if QT_VERSION >= 300
942 QString listMode = configSettings->readEntry("/kconfig/qconf/listMode", "symbol");
943 if (listMode == "single")
944 showSingleView();
945 else if (listMode == "full")
946 showFullView();
947 else /*if (listMode == "split")*/
948 showSplitView();
949
950 // UI setup done, restore splitter positions
951 QValueList<int> sizes = configSettings->readSizes("/kconfig/qconf/split1", &ok);
952 if (ok)
953 split1->setSizes(sizes);
954
955 sizes = configSettings->readSizes("/kconfig/qconf/split2", &ok);
956 if (ok)
957 split2->setSizes(sizes);
958#else
959 showSplitView();
960#endif
961 delete configSettings;
962}
963
964static QString print_filter(const char *str)
965{
966 QRegExp re("[<>&\"\\n]");
967 QString res = str;
968 for (int i = 0; (i = res.find(re, i)) >= 0;) {
969 switch (res[i].latin1()) {
970 case '<':
971 res.replace(i, 1, "&lt;");
972 i += 4;
973 break;
974 case '>':
975 res.replace(i, 1, "&gt;");
976 i += 4;
977 break;
978 case '&':
979 res.replace(i, 1, "&amp;");
980 i += 5;
981 break;
982 case '"':
983 res.replace(i, 1, "&quot;");
984 i += 6;
985 break;
986 case '\n':
987 res.replace(i, 1, "<br>");
988 i += 4;
989 break;
990 }
991 }
992 return res;
993}
994
995static void expr_print_help(void *data, const char *str)
996{
997 ((QString*)data)->append(print_filter(str));
998}
999
1000/*
1001 * display a new help entry as soon as a new menu entry is selected
1002 */
1003void ConfigMainWindow::setHelp(QListViewItem* item)
1004{
1005 struct symbol* sym;
1006 struct menu* menu = 0;
1007
1008 configList->parent()->lineEdit->hide();
1009 if (item)
1010 menu = ((ConfigItem*)item)->menu;
1011 if (!menu) {
1012 helpText->setText(NULL);
1013 return;
1014 }
1015
1016 QString head, debug, help;
1017 menu = ((ConfigItem*)item)->menu;
1018 sym = menu->sym;
1019 if (sym) {
1020 if (menu->prompt) {
1021 head += "<big><b>";
1022 head += print_filter(menu->prompt->text);
1023 head += "</b></big>";
1024 if (sym->name) {
1025 head += " (";
1026 head += print_filter(sym->name);
1027 head += ")";
1028 }
1029 } else if (sym->name) {
1030 head += "<big><b>";
1031 head += print_filter(sym->name);
1032 head += "</b></big>";
1033 }
1034 head += "<br><br>";
1035
1036 if (showDebug) {
1037 debug += "type: ";
1038 debug += print_filter(sym_type_name(sym->type));
1039 if (sym_is_choice(sym))
1040 debug += " (choice)";
1041 debug += "<br>";
1042 if (sym->rev_dep.expr) {
1043 debug += "reverse dep: ";
1044 expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
1045 debug += "<br>";
1046 }
1047 for (struct property *prop = sym->prop; prop; prop = prop->next) {
1048 switch (prop->type) {
1049 case P_PROMPT:
1050 case P_MENU:
1051 debug += "prompt: ";
1052 debug += print_filter(prop->text);
1053 debug += "<br>";
1054 break;
1055 case P_DEFAULT:
1056 debug += "default: ";
1057 expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1058 debug += "<br>";
1059 break;
1060 case P_CHOICE:
1061 if (sym_is_choice(sym)) {
1062 debug += "choice: ";
1063 expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1064 debug += "<br>";
1065 }
1066 break;
1067 case P_SELECT:
1068 debug += "select: ";
1069 expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1070 debug += "<br>";
1071 break;
1072 case P_RANGE:
1073 debug += "range: ";
1074 expr_print(prop->expr, expr_print_help, &debug, E_NONE);
1075 debug += "<br>";
1076 break;
1077 default:
1078 debug += "unknown property: ";
1079 debug += prop_get_type_name(prop->type);
1080 debug += "<br>";
1081 }
1082 if (prop->visible.expr) {
1083 debug += "&nbsp;&nbsp;&nbsp;&nbsp;dep: ";
1084 expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
1085 debug += "<br>";
1086 }
1087 }
1088 debug += "<br>";
1089 }
1090
1091 help = print_filter(sym->help);
1092 } else if (menu->prompt) {
1093 head += "<big><b>";
1094 head += print_filter(menu->prompt->text);
1095 head += "</b></big><br><br>";
1096 if (showDebug) {
1097 if (menu->prompt->visible.expr) {
1098 debug += "&nbsp;&nbsp;dep: ";
1099 expr_print(menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
1100 debug += "<br><br>";
1101 }
1102 }
1103 }
1104 if (showDebug)
1105 debug += QString().sprintf("defined at %s:%d<br><br>", menu->file->name, menu->lineno);
1106 helpText->setText(head + debug + help);
1107}
1108
1109void ConfigMainWindow::loadConfig(void)
1110{
1111 QString s = QFileDialog::getOpenFileName(".config", NULL, this);
1112 if (s.isNull())
1113 return;
1114 if (conf_read(s.latin1()))
1115 QMessageBox::information(this, "qconf", "Unable to load configuration!");
1116 ConfigView::updateListAll();
1117}
1118
1119void ConfigMainWindow::saveConfig(void)
1120{
1121 if (conf_write(NULL))
1122 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1123}
1124
1125void ConfigMainWindow::saveConfigAs(void)
1126{
1127 QString s = QFileDialog::getSaveFileName(".config", NULL, this);
1128 if (s.isNull())
1129 return;
1130 if (conf_write(s.latin1()))
1131 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1132}
1133
1134void ConfigMainWindow::changeMenu(struct menu *menu)
1135{
1136 configList->setRootMenu(menu);
1137 backAction->setEnabled(TRUE);
1138}
1139
1140void ConfigMainWindow::listFocusChanged(void)
1141{
1142 if (menuList->hasFocus()) {
1143 if (menuList->mode == menuMode)
1144 configList->clearSelection();
1145 setHelp(menuList->selectedItem());
1146 } else if (configList->hasFocus()) {
1147 setHelp(configList->selectedItem());
1148 }
1149}
1150
1151void ConfigMainWindow::goBack(void)
1152{
1153 ConfigItem* item;
1154
1155 configList->setParentMenu();
1156 if (configList->rootEntry == &rootmenu)
1157 backAction->setEnabled(FALSE);
1158 item = (ConfigItem*)menuList->selectedItem();
1159 while (item) {
1160 if (item->menu == configList->rootEntry) {
1161 menuList->setSelected(item, TRUE);
1162 break;
1163 }
1164 item = (ConfigItem*)item->parent();
1165 }
1166}
1167
1168void ConfigMainWindow::showSingleView(void)
1169{
1170 menuView->hide();
1171 menuList->setRootMenu(0);
1172 configList->mode = singleMode;
1173 if (configList->rootEntry == &rootmenu)
1174 configList->updateListAll();
1175 else
1176 configList->setRootMenu(&rootmenu);
1177 configList->setAllOpen(TRUE);
1178 configList->setFocus();
1179}
1180
1181void ConfigMainWindow::showSplitView(void)
1182{
1183 configList->mode = symbolMode;
1184 if (configList->rootEntry == &rootmenu)
1185 configList->updateListAll();
1186 else
1187 configList->setRootMenu(&rootmenu);
1188 configList->setAllOpen(TRUE);
1189 configApp->processEvents();
1190 menuList->mode = menuMode;
1191 menuList->setRootMenu(&rootmenu);
1192 menuList->setAllOpen(TRUE);
1193 menuView->show();
1194 menuList->setFocus();
1195}
1196
1197void ConfigMainWindow::showFullView(void)
1198{
1199 menuView->hide();
1200 menuList->setRootMenu(0);
1201 configList->mode = fullMode;
1202 if (configList->rootEntry == &rootmenu)
1203 configList->updateListAll();
1204 else
1205 configList->setRootMenu(&rootmenu);
1206 configList->setAllOpen(FALSE);
1207 configList->setFocus();
1208}
1209
1210void ConfigMainWindow::setShowAll(bool b)
1211{
1212 if (configList->showAll == b)
1213 return;
1214 configList->showAll = b;
1215 configList->updateListAll();
1216 menuList->showAll = b;
1217 menuList->updateListAll();
1218}
1219
1220void ConfigMainWindow::setShowDebug(bool b)
1221{
1222 if (showDebug == b)
1223 return;
1224 showDebug = b;
1225}
1226
1227void ConfigMainWindow::setShowName(bool b)
1228{
1229 if (configList->showName == b)
1230 return;
1231 configList->showName = b;
1232 configList->reinit();
1233 menuList->showName = b;
1234 menuList->reinit();
1235}
1236
1237void ConfigMainWindow::setShowRange(bool b)
1238{
1239 if (configList->showRange == b)
1240 return;
1241 configList->showRange = b;
1242 configList->reinit();
1243 menuList->showRange = b;
1244 menuList->reinit();
1245}
1246
1247void ConfigMainWindow::setShowData(bool b)
1248{
1249 if (configList->showData == b)
1250 return;
1251 configList->showData = b;
1252 configList->reinit();
1253 menuList->showData = b;
1254 menuList->reinit();
1255}
1256
1257/*
1258 * ask for saving configuration before quitting
1259 * TODO ask only when something changed
1260 */
1261void ConfigMainWindow::closeEvent(QCloseEvent* e)
1262{
1263 if (!sym_change_count) {
1264 e->accept();
1265 return;
1266 }
1267 QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning,
1268 QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
1269 mb.setButtonText(QMessageBox::Yes, "&Save Changes");
1270 mb.setButtonText(QMessageBox::No, "&Discard Changes");
1271 mb.setButtonText(QMessageBox::Cancel, "Cancel Exit");
1272 switch (mb.exec()) {
1273 case QMessageBox::Yes:
1274 conf_write(NULL);
1275 case QMessageBox::No:
1276 e->accept();
1277 break;
1278 case QMessageBox::Cancel:
1279 e->ignore();
1280 break;
1281 }
1282}
1283
1284void ConfigMainWindow::showIntro(void)
1285{
1286 static char str[] = "Welcome to the qconf graphical kernel configuration tool for Linux.\n\n"
1287 "For each option, a blank box indicates the feature is disabled, a check\n"
1288 "indicates it is enabled, and a dot indicates that it is to be compiled\n"
1289 "as a module. Clicking on the box will cycle through the three states.\n\n"
1290 "If you do not see an option (e.g., a device driver) that you believe\n"
1291 "should be present, try turning on Show All Options under the Options menu.\n"
1292 "Although there is no cross reference yet to help you figure out what other\n"
1293 "options must be enabled to support the option you are interested in, you can\n"
1294 "still view the help of a grayed-out option.\n\n"
1295 "Toggling Show Debug Info under the Options menu will show the dependencies,\n"
1296 "which you can then match by examining other options.\n\n";
1297
1298 QMessageBox::information(this, "qconf", str);
1299}
1300
1301void ConfigMainWindow::showAbout(void)
1302{
1303 static char str[] = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n\n"
1304 "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n";
1305
1306 QMessageBox::information(this, "qconf", str);
1307}
1308
1309void ConfigMainWindow::saveSettings(void)
1310{
1311#if QT_VERSION >= 300
1312 ConfigSettings *configSettings = new ConfigSettings;
1313 configSettings->writeEntry("/kconfig/qconf/window x", pos().x());
1314 configSettings->writeEntry("/kconfig/qconf/window y", pos().y());
1315 configSettings->writeEntry("/kconfig/qconf/window width", size().width());
1316 configSettings->writeEntry("/kconfig/qconf/window height", size().height());
1317 configSettings->writeEntry("/kconfig/qconf/showName", configList->showName);
1318 configSettings->writeEntry("/kconfig/qconf/showRange", configList->showRange);
1319 configSettings->writeEntry("/kconfig/qconf/showData", configList->showData);
1320 configSettings->writeEntry("/kconfig/qconf/showAll", configList->showAll);
1321 configSettings->writeEntry("/kconfig/qconf/showDebug", showDebug);
1322
1323 QString entry;
1324 switch(configList->mode) {
1325 case singleMode :
1326 entry = "single";
1327 break;
1328
1329 case symbolMode :
1330 entry = "split";
1331 break;
1332
1333 case fullMode :
1334 entry = "full";
1335 break;
1336 }
1337 configSettings->writeEntry("/kconfig/qconf/listMode", entry);
1338
1339 configSettings->writeSizes("/kconfig/qconf/split1", split1->sizes());
1340 configSettings->writeSizes("/kconfig/qconf/split2", split2->sizes());
1341
1342 delete configSettings;
1343#endif
1344}
1345
1346void fixup_rootmenu(struct menu *menu)
1347{
1348 struct menu *child;
1349 static int menu_cnt = 0;
1350
1351 menu->flags |= MENU_ROOT;
1352 for (child = menu->list; child; child = child->next) {
1353 if (child->prompt && child->prompt->type == P_MENU) {
1354 menu_cnt++;
1355 fixup_rootmenu(child);
1356 menu_cnt--;
1357 } else if (!menu_cnt)
1358 fixup_rootmenu(child);
1359 }
1360}
1361
1362static const char *progname;
1363
1364static void usage(void)
1365{
1366 printf("%s <config>\n", progname);
1367 exit(0);
1368}
1369
1370int main(int ac, char** av)
1371{
1372 ConfigMainWindow* v;
1373 const char *name;
1374
1375#ifndef LKC_DIRECT_LINK
1376 kconfig_load();
1377#endif
1378
1379 progname = av[0];
1380 configApp = new QApplication(ac, av);
1381 if (ac > 1 && av[1][0] == '-') {
1382 switch (av[1][1]) {
1383 case 'h':
1384 case '?':
1385 usage();
1386 }
1387 name = av[2];
1388 } else
1389 name = av[1];
1390 if (!name)
1391 usage();
1392
1393 conf_parse(name);
1394 fixup_rootmenu(&rootmenu);
1395 conf_read(NULL);
1396 //zconfdump(stdout);
1397
1398 v = new ConfigMainWindow();
1399
1400 //zconfdump(stdout);
1401 v->show();
1402 configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
1403 configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1404 configApp->exec();
1405
1406 return 0;
1407}