Linux Audio

Check our new training course

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