File Index
Files and directories
Sign in
FILE

qconf.cc

File preview with syntax highlighting.

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