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