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 <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
29 #ifdef _
30 # undef _
31 # define _ qgettext
32 #endif
33
34 static QApplication *configApp;
35
qgettext(const char * str)36 static inline QString qgettext(const char* str)
37 {
38 return QString::fromLocal8Bit(gettext(str));
39 }
40
qgettext(const QString & str)41 static inline QString qgettext(const QString& str)
42 {
43 return QString::fromLocal8Bit(gettext(str.latin1()));
44 }
45
ConfigSettings()46 ConfigSettings::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 */
readListSettings()55 void 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 */
readSizes(const QString & key,bool * ok)66 QValueList<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 */
writeSizes(const QString & key,const QValueList<int> & value)82 bool 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 */
101 template <class P>
updateMenuList(P * parent,struct menu * menu)102 void 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 */
okRename(int col)167 void 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 */
updateMenu(void)177 void 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;
195 prompt = QString::fromLocal8Bit(menu_get_prompt(menu));
196
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
221 setText(nameColIdx, QString::fromLocal8Bit(sym->name));
222
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);
231 setText(noColIdx, QString::null);
232 setText(modColIdx, QString::null);
233 setText(yesColIdx, QString::null);
234 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);
275
276 #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)
283 prompt = QString("%1: %2").arg(prompt).arg(data);
284 else
285 prompt = QString("(%2) %1").arg(prompt).arg(data);
286 break;
287 }
288 if (!sym_has_value(sym) && visible)
289 prompt += " (NEW)";
290 set_prompt:
291 setText(promptColIdx, prompt);
292 }
293
testUpdateMenu(bool v)294 void 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
paintCell(QPainter * p,const QColorGroup & cg,int column,int width,int align)312 void 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 */
init(void)328 void 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 */
~ConfigItem(void)345 ConfigItem::~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
show(ConfigItem * i)358 void ConfigLineEdit::show(ConfigItem* i)
359 {
360 item = i;
361 if (sym_get_string_value(item->menu->sym))
362 setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym)));
363 else
364 setText(QString::null);
365 Parent::show();
366 setFocus();
367 }
368
keyPressEvent(QKeyEvent * e)369 void 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
ConfigList(ConfigView * p,ConfigMainWindow * cv,ConfigSettings * configSettings)388 ConfigList::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
reinit(void)423 void 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
updateSelection(void)444 void 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
updateList(ConfigItem * item)463 void 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 }
489 update:
490 updateMenuList(this, rootEntry);
491 triggerUpdate();
492 }
493
setAllOpen(bool open)494 void ConfigList::setAllOpen(bool open)
495 {
496 QListViewItemIterator it(this);
497
498 for (; it.current(); it++)
499 it.current()->setOpen(open);
500 }
501
setValue(ConfigItem * item,tristate val)502 void 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
changeValue(ConfigItem * item)527 void 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
setRootMenu(struct menu * menu)571 void 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
setParentMenu(void)586 void 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
keyPressEvent(QKeyEvent * ev)606 void 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
contentsMousePressEvent(QMouseEvent * e)660 void 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
contentsMouseReleaseEvent(QMouseEvent * e)667 void 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
717 skip:
718 //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
719 Parent::contentsMouseReleaseEvent(e);
720 }
721
contentsMouseMoveEvent(QMouseEvent * e)722 void 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
contentsMouseDoubleClickEvent(QMouseEvent * e)729 void 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
751 skip:
752 //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
753 Parent::contentsMouseDoubleClickEvent(e);
754 }
755
focusInEvent(QFocusEvent * e)756 void 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
768 ConfigView* ConfigView::viewList;
769
ConfigView(QWidget * parent,ConfigMainWindow * cview,ConfigSettings * configSettings)770 ConfigView::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
~ConfigView(void)782 ConfigView::~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
updateList(ConfigItem * item)794 void ConfigView::updateList(ConfigItem* item)
795 {
796 ConfigView* v;
797
798 for (v = viewList; v; v = v->nextView)
799 v->list->updateList(item);
800 }
801
updateListAll(void)802 void 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 */
ConfigMainWindow(void)813 ConfigMainWindow::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
print_filter(const QString & str)980 static QString print_filter(const QString &str)
981 {
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, "<");
988 i += 4;
989 break;
990 case '>':
991 res.replace(i, 1, ">");
992 i += 4;
993 break;
994 case '&':
995 res.replace(i, 1, "&");
996 i += 5;
997 break;
998 case '"':
999 res.replace(i, 1, """);
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
expr_print_help(void * data,const char * str)1011 static void expr_print_help(void *data, const char *str)
1012 {
1013 reinterpret_cast<QString*>(data)->append(print_filter(str));
1014 }
1015
1016 /*
1017 * display a new help entry as soon as a new menu entry is selected
1018 */
setHelp(QListViewItem * item)1019 void 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) {
1028 helpText->setText(QString::null);
1029 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>";
1038 head += print_filter(_(menu->prompt->text));
1039 head += "</b></big>";
1040 if (sym->name) {
1041 head += " (";
1042 head += print_filter(_(sym->name));
1043 head += ")";
1044 }
1045 } else if (sym->name) {
1046 head += "<big><b>";
1047 head += print_filter(_(sym->name));
1048 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: ";
1068 debug += print_filter(_(prop->text));
1069 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 += " dep: ";
1100 expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
1101 debug += "<br>";
1102 }
1103 }
1104 debug += "<br>";
1105 }
1106
1107 help = print_filter(_(sym->help));
1108 } else if (menu->prompt) {
1109 head += "<big><b>";
1110 head += print_filter(_(menu->prompt->text));
1111 head += "</b></big><br><br>";
1112 if (showDebug) {
1113 if (menu->prompt->visible.expr) {
1114 debug += " 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
loadConfig(void)1125 void ConfigMainWindow::loadConfig(void)
1126 {
1127 QString s = QFileDialog::getOpenFileName(".config", NULL, this);
1128 if (s.isNull())
1129 return;
1130 if (conf_read(QFile::encodeName(s)))
1131 QMessageBox::information(this, "qconf", "Unable to load configuration!");
1132 ConfigView::updateListAll();
1133 }
1134
saveConfig(void)1135 void ConfigMainWindow::saveConfig(void)
1136 {
1137 if (conf_write(NULL))
1138 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1139 }
1140
saveConfigAs(void)1141 void ConfigMainWindow::saveConfigAs(void)
1142 {
1143 QString s = QFileDialog::getSaveFileName(".config", NULL, this);
1144 if (s.isNull())
1145 return;
1146 if (conf_write(QFile::encodeName(s)))
1147 QMessageBox::information(this, "qconf", "Unable to save configuration!");
1148 }
1149
changeMenu(struct menu * menu)1150 void ConfigMainWindow::changeMenu(struct menu *menu)
1151 {
1152 configList->setRootMenu(menu);
1153 backAction->setEnabled(TRUE);
1154 }
1155
listFocusChanged(void)1156 void 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
goBack(void)1167 void 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
showSingleView(void)1184 void 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
showSplitView(void)1197 void 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
showFullView(void)1213 void 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
setShowAll(bool b)1226 void 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
setShowDebug(bool b)1236 void ConfigMainWindow::setShowDebug(bool b)
1237 {
1238 if (showDebug == b)
1239 return;
1240 showDebug = b;
1241 }
1242
setShowName(bool b)1243 void 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
setShowRange(bool b)1253 void 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
setShowData(bool b)1263 void 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 */
closeEvent(QCloseEvent * e)1277 void 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
showIntro(void)1300 void ConfigMainWindow::showIntro(void)
1301 {
1302 static char str[] = "Welcome to the qconf graphical configuration tool.\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
showAbout(void)1317 void ConfigMainWindow::showAbout(void)
1318 {
1319 static char str[] = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n";
1320
1321 QMessageBox::information(this, "qconf", str);
1322 }
1323
saveSettings(void)1324 void ConfigMainWindow::saveSettings(void)
1325 {
1326 #if QT_VERSION >= 300
1327 ConfigSettings *configSettings = new ConfigSettings;
1328 configSettings->writeEntry("/kconfig/qconf/window x", pos().x());
1329 configSettings->writeEntry("/kconfig/qconf/window y", pos().y());
1330 configSettings->writeEntry("/kconfig/qconf/window width", size().width());
1331 configSettings->writeEntry("/kconfig/qconf/window height", size().height());
1332 configSettings->writeEntry("/kconfig/qconf/showName", configList->showName);
1333 configSettings->writeEntry("/kconfig/qconf/showRange", configList->showRange);
1334 configSettings->writeEntry("/kconfig/qconf/showData", configList->showData);
1335 configSettings->writeEntry("/kconfig/qconf/showAll", configList->showAll);
1336 configSettings->writeEntry("/kconfig/qconf/showDebug", showDebug);
1337
1338 QString entry;
1339 switch(configList->mode) {
1340 case singleMode :
1341 entry = "single";
1342 break;
1343
1344 case symbolMode :
1345 entry = "split";
1346 break;
1347
1348 case fullMode :
1349 entry = "full";
1350 break;
1351 }
1352 configSettings->writeEntry("/kconfig/qconf/listMode", entry);
1353
1354 configSettings->writeSizes("/kconfig/qconf/split1", split1->sizes());
1355 configSettings->writeSizes("/kconfig/qconf/split2", split2->sizes());
1356
1357 delete configSettings;
1358 #endif
1359 }
1360
fixup_rootmenu(struct menu * menu)1361 void fixup_rootmenu(struct menu *menu)
1362 {
1363 struct menu *child;
1364 static int menu_cnt = 0;
1365
1366 menu->flags |= MENU_ROOT;
1367 for (child = menu->list; child; child = child->next) {
1368 if (child->prompt && child->prompt->type == P_MENU) {
1369 menu_cnt++;
1370 fixup_rootmenu(child);
1371 menu_cnt--;
1372 } else if (!menu_cnt)
1373 fixup_rootmenu(child);
1374 }
1375 }
1376
1377 static const char *progname;
1378
usage(void)1379 static void usage(void)
1380 {
1381 printf("%s <config>\n", progname);
1382 exit(0);
1383 }
1384
main(int ac,char ** av)1385 int main(int ac, char** av)
1386 {
1387 ConfigMainWindow* v;
1388 const char *name;
1389
1390 bindtextdomain(PACKAGE, LOCALEDIR);
1391 textdomain(PACKAGE);
1392
1393 #ifndef LKC_DIRECT_LINK
1394 kconfig_load();
1395 #endif
1396
1397 progname = av[0];
1398 configApp = new QApplication(ac, av);
1399 if (ac > 1 && av[1][0] == '-') {
1400 switch (av[1][1]) {
1401 case 'h':
1402 case '?':
1403 usage();
1404 }
1405 name = av[2];
1406 } else
1407 name = av[1];
1408 if (!name)
1409 usage();
1410
1411 conf_parse(name);
1412 fixup_rootmenu(&rootmenu);
1413 conf_read(NULL);
1414 //zconfdump(stdout);
1415
1416 v = new ConfigMainWindow();
1417
1418 //zconfdump(stdout);
1419 v->show();
1420 configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
1421 configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1422 configApp->exec();
1423
1424 return 0;
1425 }
1426