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