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