qconf.cc 45.3 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
L
Linus Torvalds 已提交
2 3
/*
 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
4
 * Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>
L
Linus Torvalds 已提交
5 6
 */

7
#include <QAction>
8 9
#include <QApplication>
#include <QCloseEvent>
10
#include <QDebug>
11
#include <QDesktopWidget>
12
#include <QFileDialog>
13 14 15
#include <QLabel>
#include <QLayout>
#include <QList>
16
#include <QMenu>
17 18 19
#include <QMenuBar>
#include <QMessageBox>
#include <QToolBar>
L
Linus Torvalds 已提交
20 21 22 23 24 25

#include <stdlib.h>

#include "lkc.h"
#include "qconf.h"

26
#include "images.h"
L
Linus Torvalds 已提交
27

28

L
Linus Torvalds 已提交
29
static QApplication *configApp;
30
static ConfigSettings *configSettings;
L
Linus Torvalds 已提交
31

32
QAction *ConfigMainWindow::saveAction;
33

34 35
static inline QString qgettext(const char* str)
{
36
	return QString::fromLocal8Bit(str);
37 38
}

39 40 41 42 43
ConfigSettings::ConfigSettings()
	: QSettings("kernel.org", "qconf")
{
}

L
Linus Torvalds 已提交
44 45 46
/**
 * Reads a list of integer values from the application settings.
 */
47
QList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
L
Linus Torvalds 已提交
48
{
49
	QList<int> result;
L
Li Zefan 已提交
50

51 52 53 54 55 56 57 58 59 60 61 62
	if (contains(key))
	{
		QStringList entryList = value(key).toStringList();
		QStringList::Iterator it;

		for (it = entryList.begin(); it != entryList.end(); ++it)
			result.push_back((*it).toInt());

		*ok = true;
	}
	else
		*ok = false;
L
Linus Torvalds 已提交
63 64 65 66 67 68 69

	return result;
}

/**
 * Writes a list of integer values to the application settings.
 */
70
bool ConfigSettings::writeSizes(const QString& key, const QList<int>& value)
L
Linus Torvalds 已提交
71 72
{
	QStringList stringList;
73
	QList<int>::ConstIterator it;
L
Linus Torvalds 已提交
74 75 76

	for (it = value.begin(); it != value.end(); ++it)
		stringList.push_back(QString::number(*it));
77
	setValue(key, stringList);
78

79
	return true;
L
Linus Torvalds 已提交
80 81
}

82 83 84 85 86 87 88 89 90 91 92 93 94 95

/*
 * set the new data
 * TODO check the value
 */
void ConfigItem::okRename(int col)
{
}

/*
 * update the displayed of a menu entry
 */
void ConfigItem::updateMenu(void)
{
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
	ConfigList* list;
	struct symbol* sym;
	struct property *prop;
	QString prompt;
	int type;
	tristate expr;

	list = listView();
	if (goParent) {
		setPixmap(promptColIdx, list->menuBackPix);
		prompt = "..";
		goto set_prompt;
	}

	sym = menu->sym;
	prop = menu->prompt;
112
	prompt = qgettext(menu_get_prompt(menu));
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145

	if (prop) switch (prop->type) {
	case P_MENU:
		if (list->mode == singleMode || list->mode == symbolMode) {
			/* a menuconfig entry is displayed differently
			 * depending whether it's at the view root or a child.
			 */
			if (sym && list->rootEntry == menu)
				break;
			setPixmap(promptColIdx, list->menuPix);
		} else {
			if (sym)
				break;
			setPixmap(promptColIdx, QIcon());
		}
		goto set_prompt;
	case P_COMMENT:
		setPixmap(promptColIdx, QIcon());
		goto set_prompt;
	default:
		;
	}
	if (!sym)
		goto set_prompt;

	setText(nameColIdx, QString::fromLocal8Bit(sym->name));

	type = sym_get_type(sym);
	switch (type) {
	case S_BOOLEAN:
	case S_TRISTATE:
		char ch;

146
		if (!sym_is_changeable(sym) && list->optMode == normalOpt) {
147
			setPixmap(promptColIdx, QIcon());
148 149 150
			setText(noColIdx, QString());
			setText(modColIdx, QString());
			setText(yesColIdx, QString());
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
			break;
		}
		expr = sym_get_tristate_value(sym);
		switch (expr) {
		case yes:
			if (sym_is_choice_value(sym) && type == S_BOOLEAN)
				setPixmap(promptColIdx, list->choiceYesPix);
			else
				setPixmap(promptColIdx, list->symbolYesPix);
			setText(yesColIdx, "Y");
			ch = 'Y';
			break;
		case mod:
			setPixmap(promptColIdx, list->symbolModPix);
			setText(modColIdx, "M");
			ch = 'M';
			break;
		default:
			if (sym_is_choice_value(sym) && type == S_BOOLEAN)
				setPixmap(promptColIdx, list->choiceNoPix);
			else
				setPixmap(promptColIdx, list->symbolNoPix);
			setText(noColIdx, "N");
			ch = 'N';
			break;
		}
		if (expr != no)
			setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0);
		if (expr != mod)
			setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0);
		if (expr != yes)
			setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0);

		setText(dataColIdx, QChar(ch));
		break;
	case S_INT:
	case S_HEX:
	case S_STRING:
		const char* data;

		data = sym_get_string_value(sym);

		setText(dataColIdx, data);
		if (type == S_STRING)
			prompt = QString("%1: %2").arg(prompt).arg(data);
		else
			prompt = QString("(%2) %1").arg(prompt).arg(data);
		break;
	}
	if (!sym_has_value(sym) && visible)
201
		prompt += " (NEW)";
202 203
set_prompt:
	setText(promptColIdx, prompt);
204 205 206 207
}

void ConfigItem::testUpdateMenu(bool v)
{
208 209 210 211 212 213 214 215 216 217 218 219 220 221
	ConfigItem* i;

	visible = v;
	if (!menu)
		return;

	sym_calc_value(menu->sym);
	if (menu->flags & MENU_CHANGED) {
		/* the menu entry changed, so update all list items */
		menu->flags &= ~MENU_CHANGED;
		for (i = (ConfigItem*)menu->data; i; i = i->nextItem)
			i->updateMenu();
	} else if (listView()->updateAll)
		updateMenu();
222 223 224
}


225 226 227 228 229
/*
 * construct a menu entry
 */
void ConfigItem::init(void)
{
230 231 232 233 234 235 236 237 238 239
	if (menu) {
		ConfigList* list = listView();
		nextItem = (ConfigItem*)menu->data;
		menu->data = this;

		if (list->mode != fullMode)
			setExpanded(true);
		sym_calc_value(menu->sym);
	}
	updateMenu();
240 241 242 243 244 245 246
}

/*
 * destruct a menu entry
 */
ConfigItem::~ConfigItem(void)
{
247 248 249 250 251 252 253 254 255
	if (menu) {
		ConfigItem** ip = (ConfigItem**)&menu->data;
		for (; *ip; ip = &(*ip)->nextItem) {
			if (*ip == this) {
				*ip = nextItem;
				break;
			}
		}
	}
256 257
}

258 259 260
ConfigLineEdit::ConfigLineEdit(ConfigView* parent)
	: Parent(parent)
{
261
	connect(this, SIGNAL(editingFinished()), SLOT(hide()));
262 263
}

264
void ConfigLineEdit::show(ConfigItem* i)
L
Linus Torvalds 已提交
265 266
{
	item = i;
267 268 269
	if (sym_get_string_value(item->menu->sym))
		setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym)));
	else
270
		setText(QString());
L
Linus Torvalds 已提交
271 272 273 274 275 276 277
	Parent::show();
	setFocus();
}

void ConfigLineEdit::keyPressEvent(QKeyEvent* e)
{
	switch (e->key()) {
278
	case Qt::Key_Escape:
L
Linus Torvalds 已提交
279
		break;
280 281
	case Qt::Key_Return:
	case Qt::Key_Enter:
282
		sym_set_string_value(item->menu->sym, text().toLatin1());
L
Linus Torvalds 已提交
283 284 285 286 287 288 289 290 291 292 293
		parent()->updateList(item);
		break;
	default:
		Parent::keyPressEvent(e);
		return;
	}
	e->accept();
	parent()->list->setFocus();
	hide();
}

294
ConfigList::ConfigList(ConfigView* p, const char *name)
295 296 297 298 299
	: Parent(p),
	  updateAll(false),
	  symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no),
	  choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no),
	  menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void),
300
	  showName(false), showRange(false), showData(false), mode(singleMode), optMode(normalOpt),
301 302
	  rootEntry(0), headerPopup(0)
{
303
	setObjectName(name);
304
	setSortingEnabled(false);
305 306
	setRootIsDecorated(true);

307 308 309
	setVerticalScrollMode(ScrollPerPixel);
	setHorizontalScrollMode(ScrollPerPixel);

310
	setHeaderLabels(QStringList() << "Option" << "Name" << "N" << "M" << "Y" << "Value");
311

312
	connect(this, SIGNAL(itemSelectionChanged(void)),
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
		SLOT(updateSelection(void)));

	if (name) {
		configSettings->beginGroup(name);
		showName = configSettings->value("/showName", false).toBool();
		showRange = configSettings->value("/showRange", false).toBool();
		showData = configSettings->value("/showData", false).toBool();
		optMode = (enum optionMode)configSettings->value("/optionMode", 0).toInt();
		configSettings->endGroup();
		connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
	}

	addColumn(promptColIdx);

	reinit();
}

bool ConfigList::menuSkip(struct menu *menu)
{
	if (optMode == normalOpt && menu_is_visible(menu))
		return false;
	if (optMode == promptOpt && menu_has_prompt(menu))
		return false;
	if (optMode == allOpt)
		return false;
	return true;
339 340 341 342
}

void ConfigList::reinit(void)
{
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
	removeColumn(dataColIdx);
	removeColumn(yesColIdx);
	removeColumn(modColIdx);
	removeColumn(noColIdx);
	removeColumn(nameColIdx);

	if (showName)
		addColumn(nameColIdx);
	if (showRange) {
		addColumn(noColIdx);
		addColumn(modColIdx);
		addColumn(yesColIdx);
	}
	if (showData)
		addColumn(dataColIdx);

	updateListAll();
360 361 362 363
}

void ConfigList::saveSettings(void)
{
364 365 366 367 368 369 370 371
	if (!objectName().isEmpty()) {
		configSettings->beginGroup(objectName());
		configSettings->setValue("/showName", showName);
		configSettings->setValue("/showRange", showRange);
		configSettings->setValue("/showData", showData);
		configSettings->setValue("/optionMode", (int)optMode);
		configSettings->endGroup();
	}
372 373 374 375
}

ConfigItem* ConfigList::findConfigItem(struct menu *menu)
{
376 377 378 379 380 381 382 383
	ConfigItem* item = (ConfigItem*)menu->data;

	for (; item; item = item->nextItem) {
		if (this == item->listView())
			break;
	}

	return item;
384 385 386 387
}

void ConfigList::updateSelection(void)
{
388 389 390
	struct menu *menu;
	enum prop_type type;

B
Boris Barbulovski 已提交
391 392 393
	if (selectedItems().count() == 0)
		return;

394 395 396 397 398 399 400 401 402 403 404
	ConfigItem* item = (ConfigItem*)selectedItems().first();
	if (!item)
		return;

	menu = item->menu;
	emit menuChanged(menu);
	if (!menu)
		return;
	type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
	if (mode == menuMode && type == P_MENU)
		emit menuSelected(menu);
405 406 407 408
}

void ConfigList::updateList(ConfigItem* item)
{
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
	ConfigItem* last = 0;

	if (!rootEntry) {
		if (mode != listMode)
			goto update;
		QTreeWidgetItemIterator it(this);
		ConfigItem* item;

		while (*it) {
			item = (ConfigItem*)(*it);
			if (!item->menu)
				continue;
			item->testUpdateMenu(menu_is_visible(item->menu));

			++it;
		}
		return;
	}

	if (rootEntry != &rootmenu && (mode == singleMode ||
	    (mode == symbolMode && rootEntry->parent != &rootmenu))) {
430
		item = (ConfigItem *)topLevelItem(0);
431
		if (!item)
432
			item = new ConfigItem(this, 0, true);
433
		last = item;
434 435 436 437 438 439 440 441 442 443 444
	}
	if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) &&
	    rootEntry->sym && rootEntry->prompt) {
		item = last ? last->nextSibling() : firstChild();
		if (!item)
			item = new ConfigItem(this, last, rootEntry, true);
		else
			item->testUpdateMenu(true);

		updateMenuList(item, rootEntry);
		update();
445
		resizeColumnToContents(0);
446 447 448 449 450
		return;
	}
update:
	updateMenuList(this, rootEntry);
	update();
451
	resizeColumnToContents(0);
452 453 454 455
}

void ConfigList::setValue(ConfigItem* item, tristate val)
{
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
	struct symbol* sym;
	int type;
	tristate oldval;

	sym = item->menu ? item->menu->sym : 0;
	if (!sym)
		return;

	type = sym_get_type(sym);
	switch (type) {
	case S_BOOLEAN:
	case S_TRISTATE:
		oldval = sym_get_tristate_value(sym);

		if (!sym_set_tristate_value(sym, val))
			return;
		if (oldval == no && item->menu->list)
			item->setExpanded(true);
		parent()->updateList(item);
		break;
	}
477 478 479 480
}

void ConfigList::changeValue(ConfigItem* item)
{
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
	struct symbol* sym;
	struct menu* menu;
	int type, oldexpr, newexpr;

	menu = item->menu;
	if (!menu)
		return;
	sym = menu->sym;
	if (!sym) {
		if (item->menu->list)
			item->setExpanded(!item->isExpanded());
		return;
	}

	type = sym_get_type(sym);
	switch (type) {
	case S_BOOLEAN:
	case S_TRISTATE:
		oldexpr = sym_get_tristate_value(sym);
		newexpr = sym_toggle_tristate_value(sym);
		if (item->menu->list) {
			if (oldexpr == newexpr)
				item->setExpanded(!item->isExpanded());
			else if (oldexpr == no)
				item->setExpanded(true);
		}
		if (oldexpr != newexpr)
			parent()->updateList(item);
		break;
	case S_INT:
	case S_HEX:
	case S_STRING:
513
		parent()->lineEdit->show(item);
514 515
		break;
	}
516 517 518 519
}

void ConfigList::setRootMenu(struct menu *menu)
{
520 521 522 523 524 525 526 527 528 529 530
	enum prop_type type;

	if (rootEntry == menu)
		return;
	type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
	if (type != P_MENU)
		return;
	updateMenuList(this, 0);
	rootEntry = menu;
	updateListAll();
	if (currentItem()) {
531
		setSelected(currentItem(), hasFocus());
532 533
		scrollToItem(currentItem());
	}
534 535 536 537
}

void ConfigList::setParentMenu(void)
{
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
	ConfigItem* item;
	struct menu *oldroot;

	oldroot = rootEntry;
	if (rootEntry == &rootmenu)
		return;
	setRootMenu(menu_get_parent_menu(rootEntry->parent));

	QTreeWidgetItemIterator it(this);
	while (*it) {
		item = (ConfigItem *)(*it);
		if (item->menu == oldroot) {
			setCurrentItem(item);
			scrollToItem(item);
			break;
		}

		++it;
	}
557 558 559 560 561 562 563 564 565
}

/*
 * update all the children of a menu entry
 *   removes/adds the entries from the parent widget as necessary
 *
 * parent: either the menu list widget or a menu entry widget
 * menu: entry to be updated
 */
566
void ConfigList::updateMenuList(ConfigItem *parent, struct menu* menu)
567
{
568 569 570 571 572 573 574
	struct menu* child;
	ConfigItem* item;
	ConfigItem* last;
	bool visible;
	enum prop_type type;

	if (!menu) {
575 576 577 578 579
		while (parent->childCount() > 0)
		{
			delete parent->takeChild(0);
		}

580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618
		return;
	}

	last = parent->firstChild();
	if (last && !last->goParent)
		last = 0;
	for (child = menu->list; child; child = child->next) {
		item = last ? last->nextSibling() : parent->firstChild();
		type = child->prompt ? child->prompt->type : P_UNKNOWN;

		switch (mode) {
		case menuMode:
			if (!(child->flags & MENU_ROOT))
				goto hide;
			break;
		case symbolMode:
			if (child->flags & MENU_ROOT)
				goto hide;
			break;
		default:
			break;
		}

		visible = menu_is_visible(child);
		if (!menuSkip(child)) {
			if (!child->sym && !child->list && !child->prompt)
				continue;
			if (!item || item->menu != child)
				item = new ConfigItem(parent, last, child, visible);
			else
				item->testUpdateMenu(visible);

			if (mode == fullMode || mode == menuMode || type != P_MENU)
				updateMenuList(item, child);
			else
				updateMenuList(item, 0);
			last = item;
			continue;
		}
619
hide:
620 621 622 623 624 625 626 627 628
		if (item && item->menu == child) {
			last = parent->firstChild();
			if (last == item)
				last = 0;
			else while (last->nextSibling() != item)
				last = last->nextSibling();
			delete item;
		}
	}
629 630
}

631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683
void ConfigList::updateMenuList(ConfigList *parent, struct menu* menu)
{
	struct menu* child;
	ConfigItem* item;
	ConfigItem* last;
	bool visible;
	enum prop_type type;

	if (!menu) {
		while (parent->topLevelItemCount() > 0)
		{
			delete parent->takeTopLevelItem(0);
		}

		return;
	}

	last = (ConfigItem*)parent->topLevelItem(0);
	if (last && !last->goParent)
		last = 0;
	for (child = menu->list; child; child = child->next) {
		item = last ? last->nextSibling() : (ConfigItem*)parent->topLevelItem(0);
		type = child->prompt ? child->prompt->type : P_UNKNOWN;

		switch (mode) {
		case menuMode:
			if (!(child->flags & MENU_ROOT))
				goto hide;
			break;
		case symbolMode:
			if (child->flags & MENU_ROOT)
				goto hide;
			break;
		default:
			break;
		}

		visible = menu_is_visible(child);
		if (!menuSkip(child)) {
			if (!child->sym && !child->list && !child->prompt)
				continue;
			if (!item || item->menu != child)
				item = new ConfigItem(parent, last, child, visible);
			else
				item->testUpdateMenu(visible);

			if (mode == fullMode || mode == menuMode || type != P_MENU)
				updateMenuList(item, child);
			else
				updateMenuList(item, 0);
			last = item;
			continue;
		}
684
hide:
685 686 687 688 689 690 691 692 693 694 695
		if (item && item->menu == child) {
			last = (ConfigItem*)parent->topLevelItem(0);
			if (last == item)
				last = 0;
			else while (last->nextSibling() != item)
				last = last->nextSibling();
			delete item;
		}
	}
}

696 697
void ConfigList::keyPressEvent(QKeyEvent* ev)
{
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
	QTreeWidgetItem* i = currentItem();
	ConfigItem* item;
	struct menu *menu;
	enum prop_type type;

	if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) {
		emit parentSelected();
		ev->accept();
		return;
	}

	if (!i) {
		Parent::keyPressEvent(ev);
		return;
	}
	item = (ConfigItem*)i;

	switch (ev->key()) {
	case Qt::Key_Return:
	case Qt::Key_Enter:
		if (item->goParent) {
			emit parentSelected();
			break;
		}
		menu = item->menu;
		if (!menu)
			break;
		type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
		if (type == P_MENU && rootEntry != menu &&
		    mode != fullMode && mode != menuMode) {
728 729 730 731
			if (mode == menuMode)
				emit menuSelected(menu);
			else
				emit itemSelected(menu);
732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750
			break;
		}
	case Qt::Key_Space:
		changeValue(item);
		break;
	case Qt::Key_N:
		setValue(item, no);
		break;
	case Qt::Key_M:
		setValue(item, mod);
		break;
	case Qt::Key_Y:
		setValue(item, yes);
		break;
	default:
		Parent::keyPressEvent(ev);
		return;
	}
	ev->accept();
751 752
}

753
void ConfigList::mousePressEvent(QMouseEvent* e)
754
{
755 756 757
	//QPoint p(contentsToViewport(e->pos()));
	//printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
	Parent::mousePressEvent(e);
758
}
759

760
void ConfigList::mouseReleaseEvent(QMouseEvent* e)
761
{
762 763 764 765 766 767 768 769 770 771 772 773
	QPoint p = e->pos();
	ConfigItem* item = (ConfigItem*)itemAt(p);
	struct menu *menu;
	enum prop_type ptype;
	QIcon icon;
	int idx, x;

	if (!item)
		goto skip;

	menu = item->menu;
	x = header()->offset() + p.x();
774
	idx = header()->logicalIndexAt(x);
775 776 777
	switch (idx) {
	case promptColIdx:
		icon = item->pixmap(promptColIdx);
778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793
		if (!icon.isNull()) {
			int off = header()->sectionPosition(0) + visualRect(indexAt(p)).x() + 4; // 4 is Hardcoded image offset. There might be a way to do it properly.
			if (x >= off && x < off + icon.availableSizes().first().width()) {
				if (item->goParent) {
					emit parentSelected();
					break;
				} else if (!menu)
					break;
				ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
				if (ptype == P_MENU && rootEntry != menu &&
				    mode != fullMode && mode != menuMode)
					emit menuSelected(menu);
				else
					changeValue(item);
			}
		}
794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811
		break;
	case noColIdx:
		setValue(item, no);
		break;
	case modColIdx:
		setValue(item, mod);
		break;
	case yesColIdx:
		setValue(item, yes);
		break;
	case dataColIdx:
		changeValue(item);
		break;
	}

skip:
	//printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
	Parent::mouseReleaseEvent(e);
812 813
}

814
void ConfigList::mouseMoveEvent(QMouseEvent* e)
815
{
816 817 818
	//QPoint p(contentsToViewport(e->pos()));
	//printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
	Parent::mouseMoveEvent(e);
819 820
}

821
void ConfigList::mouseDoubleClickEvent(QMouseEvent* e)
822
{
823
	QPoint p = e->pos();
824 825 826 827 828 829 830 831 832 833 834 835 836 837
	ConfigItem* item = (ConfigItem*)itemAt(p);
	struct menu *menu;
	enum prop_type ptype;

	if (!item)
		goto skip;
	if (item->goParent) {
		emit parentSelected();
		goto skip;
	}
	menu = item->menu;
	if (!menu)
		goto skip;
	ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
838 839 840 841 842 843
	if (ptype == P_MENU) {
		if (mode == singleMode)
			emit itemSelected(menu);
		else if (mode == symbolMode)
			emit menuSelected(menu);
	} else if (menu->sym)
844 845 846 847 848
		changeValue(item);

skip:
	//printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
	Parent::mouseDoubleClickEvent(e);
849 850 851 852
}

void ConfigList::focusInEvent(QFocusEvent *e)
{
853 854 855 856 857 858
	struct menu *menu = NULL;

	Parent::focusInEvent(e);

	ConfigItem* item = (ConfigItem *)currentItem();
	if (item) {
859
		setSelected(item, true);
860 861 862
		menu = item->menu;
	}
	emit gotFocus(menu);
863 864 865 866
}

void ConfigList::contextMenuEvent(QContextMenuEvent *e)
{
867 868 869 870 871
	if (e->y() <= header()->geometry().bottom()) {
		if (!headerPopup) {
			QAction *action;

			headerPopup = new QMenu(this);
872
			action = new QAction("Show Name", this);
873 874 875 876 877 878 879
			  action->setCheckable(true);
			  connect(action, SIGNAL(toggled(bool)),
				  parent(), SLOT(setShowName(bool)));
			  connect(parent(), SIGNAL(showNameChanged(bool)),
				  action, SLOT(setOn(bool)));
			  action->setChecked(showName);
			  headerPopup->addAction(action);
880
			action = new QAction("Show Range", this);
881 882 883 884 885 886 887
			  action->setCheckable(true);
			  connect(action, SIGNAL(toggled(bool)),
				  parent(), SLOT(setShowRange(bool)));
			  connect(parent(), SIGNAL(showRangeChanged(bool)),
				  action, SLOT(setOn(bool)));
			  action->setChecked(showRange);
			  headerPopup->addAction(action);
888
			action = new QAction("Show Data", this);
889 890 891 892 893 894 895 896 897 898 899 900
			  action->setCheckable(true);
			  connect(action, SIGNAL(toggled(bool)),
				  parent(), SLOT(setShowData(bool)));
			  connect(parent(), SIGNAL(showDataChanged(bool)),
				  action, SLOT(setOn(bool)));
			  action->setChecked(showData);
			  headerPopup->addAction(action);
		}
		headerPopup->exec(e->globalPos());
		e->accept();
	} else
		e->ignore();
901 902
}

903 904 905 906
ConfigView*ConfigView::viewList;
QAction *ConfigView::showNormalAction;
QAction *ConfigView::showAllAction;
QAction *ConfigView::showPromptAction;
L
Linus Torvalds 已提交
907

908
ConfigView::ConfigView(QWidget* parent, const char *name)
909
	: Parent(parent)
L
Linus Torvalds 已提交
910
{
911
	setObjectName(name);
912
	QVBoxLayout *verticalLayout = new QVBoxLayout(this);
913
	verticalLayout->setContentsMargins(0, 0, 0, 0);
914

915
	list = new ConfigList(this);
916
	verticalLayout->addWidget(list);
L
Linus Torvalds 已提交
917 918
	lineEdit = new ConfigLineEdit(this);
	lineEdit->hide();
919
	verticalLayout->addWidget(lineEdit);
L
Linus Torvalds 已提交
920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936

	this->nextView = viewList;
	viewList = this;
}

ConfigView::~ConfigView(void)
{
	ConfigView** vp;

	for (vp = &viewList; *vp; vp = &(*vp)->nextView) {
		if (*vp == this) {
			*vp = nextView;
			break;
		}
	}
}

937
void ConfigView::setOptionMode(QAction *act)
938
{
939 940 941 942 943 944 945 946
	if (act == showNormalAction)
		list->optMode = normalOpt;
	else if (act == showAllAction)
		list->optMode = allOpt;
	else
		list->optMode = promptOpt;

	list->updateListAll();
947 948 949 950
}

void ConfigView::setShowName(bool b)
{
951 952 953 954 955
	if (list->showName != b) {
		list->showName = b;
		list->reinit();
		emit showNameChanged(b);
	}
956 957 958 959
}

void ConfigView::setShowRange(bool b)
{
960 961 962 963 964
	if (list->showRange != b) {
		list->showRange = b;
		list->reinit();
		emit showRangeChanged(b);
	}
965 966 967 968
}

void ConfigView::setShowData(bool b)
{
969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984
	if (list->showData != b) {
		list->showData = b;
		list->reinit();
		emit showDataChanged(b);
	}
}

void ConfigList::setAllOpen(bool open)
{
	QTreeWidgetItemIterator it(this);

	while (*it) {
		(*it)->setExpanded(open);

		++it;
	}
985 986
}

987
void ConfigView::updateList(ConfigItem* item)
L
Linus Torvalds 已提交
988
{
989 990 991 992
	ConfigView* v;

	for (v = viewList; v; v = v->nextView)
		v->list->updateList(item);
L
Linus Torvalds 已提交
993 994 995 996
}

void ConfigView::updateListAll(void)
{
997 998 999 1000
	ConfigView* v;

	for (v = viewList; v; v = v->nextView)
		v->list->updateListAll();
L
Linus Torvalds 已提交
1001 1002
}

1003
ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
1004
	: Parent(parent), sym(0), _menu(0)
1005
{
1006
	setObjectName(name);
1007
	setOpenLinks(false);
1008 1009 1010

	if (!objectName().isEmpty()) {
		configSettings->beginGroup(objectName());
1011
		setShowDebug(configSettings->value("/showDebug", false).toBool());
1012 1013 1014 1015 1016 1017 1018
		configSettings->endGroup();
		connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
	}
}

void ConfigInfoView::saveSettings(void)
{
1019 1020 1021 1022 1023
	if (!objectName().isEmpty()) {
		configSettings->beginGroup(objectName());
		configSettings->setValue("/showDebug", showDebug());
		configSettings->endGroup();
	}
1024 1025 1026 1027 1028 1029
}

void ConfigInfoView::setShowDebug(bool b)
{
	if (_showDebug != b) {
		_showDebug = b;
A
Alexander Stein 已提交
1030
		if (_menu)
1031
			menuInfo();
1032 1033
		else if (sym)
			symbolInfo();
1034 1035 1036 1037 1038 1039
		emit showDebugChanged(b);
	}
}

void ConfigInfoView::setInfo(struct menu *m)
{
A
Alexander Stein 已提交
1040
	if (_menu == m)
1041
		return;
A
Alexander Stein 已提交
1042
	_menu = m;
1043
	sym = NULL;
A
Alexander Stein 已提交
1044
	if (!_menu)
1045
		clear();
1046
	else
1047 1048 1049
		menuInfo();
}

1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
void ConfigInfoView::symbolInfo(void)
{
	QString str;

	str += "<big>Symbol: <b>";
	str += print_filter(sym->name);
	str += "</b></big><br><br>value: ";
	str += print_filter(sym_get_string_value(sym));
	str += "<br>visibility: ";
	str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n";
	str += "<br>";
	str += debug_info(sym);

	setText(str);
}

1066 1067 1068 1069 1070
void ConfigInfoView::menuInfo(void)
{
	struct symbol* sym;
	QString head, debug, help;

A
Alexander Stein 已提交
1071
	sym = _menu->sym;
1072
	if (sym) {
A
Alexander Stein 已提交
1073
		if (_menu->prompt) {
1074
			head += "<big><b>";
1075
			head += print_filter(_menu->prompt->text);
1076 1077 1078
			head += "</b></big>";
			if (sym->name) {
				head += " (";
1079
				if (showDebug())
1080
					head += QString().sprintf("<a href=\"s%s\">", sym->name);
1081
				head += print_filter(sym->name);
1082 1083
				if (showDebug())
					head += "</a>";
1084 1085 1086 1087
				head += ")";
			}
		} else if (sym->name) {
			head += "<big><b>";
1088
			if (showDebug())
1089
				head += QString().sprintf("<a href=\"s%s\">", sym->name);
1090
			head += print_filter(sym->name);
1091 1092
			if (showDebug())
				head += "</a>";
1093 1094 1095 1096 1097 1098 1099
			head += "</b></big>";
		}
		head += "<br><br>";

		if (showDebug())
			debug = debug_info(sym);

1100
		struct gstr help_gstr = str_new();
A
Alexander Stein 已提交
1101
		menu_get_ext_help(_menu, &help_gstr);
1102 1103
		help = print_filter(str_get(&help_gstr));
		str_free(&help_gstr);
A
Alexander Stein 已提交
1104
	} else if (_menu->prompt) {
1105
		head += "<big><b>";
1106
		head += print_filter(_menu->prompt->text);
1107 1108
		head += "</b></big><br><br>";
		if (showDebug()) {
A
Alexander Stein 已提交
1109
			if (_menu->prompt->visible.expr) {
1110
				debug += "&nbsp;&nbsp;dep: ";
A
Alexander Stein 已提交
1111
				expr_print(_menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
1112 1113 1114 1115 1116
				debug += "<br><br>";
			}
		}
	}
	if (showDebug())
A
Alexander Stein 已提交
1117
		debug += QString().sprintf("defined at %s:%d<br><br>", _menu->file->name, _menu->lineno);
1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139

	setText(head + debug + help);
}

QString ConfigInfoView::debug_info(struct symbol *sym)
{
	QString debug;

	debug += "type: ";
	debug += print_filter(sym_type_name(sym->type));
	if (sym_is_choice(sym))
		debug += " (choice)";
	debug += "<br>";
	if (sym->rev_dep.expr) {
		debug += "reverse dep: ";
		expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
		debug += "<br>";
	}
	for (struct property *prop = sym->prop; prop; prop = prop->next) {
		switch (prop->type) {
		case P_PROMPT:
		case P_MENU:
1140
			debug += QString().sprintf("prompt: <a href=\"m%s\">", sym->name);
1141
			debug += print_filter(prop->text);
1142
			debug += "</a><br>";
1143 1144
			break;
		case P_DEFAULT:
1145 1146
		case P_SELECT:
		case P_RANGE:
1147 1148 1149
		case P_COMMENT:
		case P_IMPLY:
		case P_SYMBOL:
1150 1151
			debug += prop_get_type_name(prop->type);
			debug += ": ";
1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181
			expr_print(prop->expr, expr_print_help, &debug, E_NONE);
			debug += "<br>";
			break;
		case P_CHOICE:
			if (sym_is_choice(sym)) {
				debug += "choice: ";
				expr_print(prop->expr, expr_print_help, &debug, E_NONE);
				debug += "<br>";
			}
			break;
		default:
			debug += "unknown property: ";
			debug += prop_get_type_name(prop->type);
			debug += "<br>";
		}
		if (prop->visible.expr) {
			debug += "&nbsp;&nbsp;&nbsp;&nbsp;dep: ";
			expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE);
			debug += "<br>";
		}
	}
	debug += "<br>";

	return debug;
}

QString ConfigInfoView::print_filter(const QString &str)
{
	QRegExp re("[<>&\"\\n]");
	QString res = str;
1182 1183
	for (int i = 0; (i = res.indexOf(re, i)) >= 0;) {
		switch (res[i].toLatin1()) {
1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208
		case '<':
			res.replace(i, 1, "&lt;");
			i += 4;
			break;
		case '>':
			res.replace(i, 1, "&gt;");
			i += 4;
			break;
		case '&':
			res.replace(i, 1, "&amp;");
			i += 5;
			break;
		case '"':
			res.replace(i, 1, "&quot;");
			i += 6;
			break;
		case '\n':
			res.replace(i, 1, "<br>");
			i += 4;
			break;
		}
	}
	return res;
}

1209
void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str)
1210
{
1211 1212 1213 1214
	QString* text = reinterpret_cast<QString*>(data);
	QString str2 = print_filter(str);

	if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
1215
		*text += QString().sprintf("<a href=\"s%s\">", sym->name);
1216 1217 1218 1219
		*text += str2;
		*text += "</a>";
	} else
		*text += str2;
1220 1221
}

1222 1223 1224 1225 1226 1227 1228 1229 1230 1231
void ConfigInfoView::clicked(const QUrl &url)
{
	QByteArray str = url.toEncoded();
	const std::size_t count = str.size();
	char *data = new char[count + 1];
	struct symbol **result;
	struct menu *m = NULL;

	if (count < 1) {
		qInfo() << "Clicked link is empty";
1232
		delete[] data;
1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244
		return;
	}

	memcpy(data, str.constData(), count);
	data[count] = '\0';

	/* Seek for exact match */
	data[0] = '^';
	strcat(data, "$");
	result = sym_re_search(data);
	if (!result) {
		qInfo() << "Clicked symbol is invalid:" << data;
1245
		delete[] data;
1246 1247 1248 1249 1250
		return;
	}

	sym = *result;

1251
	/* Seek for the menu which holds the symbol */
1252 1253 1254 1255 1256 1257 1258 1259
	for (struct property *prop = sym->prop; prop; prop = prop->next) {
		    if (prop->type != P_PROMPT && prop->type != P_MENU)
			    continue;
		    m = prop->menu;
		    break;
	}

	if (!m) {
1260 1261 1262 1263 1264
		/* Symbol is not visible as a menu */
		symbolInfo();
		emit showDebugChanged(true);
	} else {
		emit menuSelected(m);
1265 1266 1267 1268 1269 1270
	}

	free(result);
	delete data;
}

1271
QMenu* ConfigInfoView::createStandardContextMenu(const QPoint & pos)
1272
{
1273
	QMenu* popup = Parent::createStandardContextMenu(pos);
1274
	QAction* action = new QAction("Show Debug Info", popup);
1275 1276 1277 1278 1279

	action->setCheckable(true);
	connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
	connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
	action->setChecked(showDebug());
1280
	popup->addSeparator();
1281
	popup->addAction(action);
1282 1283 1284
	return popup;
}

1285
void ConfigInfoView::contextMenuEvent(QContextMenuEvent *e)
1286
{
1287
	Parent::contextMenuEvent(e);
1288 1289
}

1290
ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *name)
1291
	: Parent(parent), result(NULL)
1292
{
1293
	setObjectName(name);
1294
	setWindowTitle("Search Config");
1295

1296 1297 1298 1299 1300 1301
	QVBoxLayout* layout1 = new QVBoxLayout(this);
	layout1->setContentsMargins(11, 11, 11, 11);
	layout1->setSpacing(6);
	QHBoxLayout* layout2 = new QHBoxLayout(0);
	layout2->setContentsMargins(0, 0, 0, 0);
	layout2->setSpacing(6);
1302
	layout2->addWidget(new QLabel("Find:", this));
1303 1304 1305
	editField = new QLineEdit(this);
	connect(editField, SIGNAL(returnPressed()), SLOT(search()));
	layout2->addWidget(editField);
1306
	searchButton = new QPushButton("Search", this);
1307
	searchButton->setAutoDefault(false);
1308 1309 1310 1311
	connect(searchButton, SIGNAL(clicked()), SLOT(search()));
	layout2->addWidget(searchButton);
	layout1->addLayout(layout2);

1312
	split = new QSplitter(this);
1313
	split->setOrientation(Qt::Vertical);
1314
	list = new ConfigView(split, name);
1315
	list->list->mode = listMode;
1316
	info = new ConfigInfoView(split, name);
1317 1318
	connect(list->list, SIGNAL(menuChanged(struct menu *)),
		info, SLOT(setInfo(struct menu *)));
1319 1320 1321
	connect(list->list, SIGNAL(menuChanged(struct menu *)),
		parent, SLOT(setMenuLink(struct menu *)));

1322
	layout1->addWidget(split);
1323 1324

	if (name) {
1325 1326
		QVariant x, y;
		int width, height;
1327 1328 1329
		bool ok;

		configSettings->beginGroup(name);
1330 1331
		width = configSettings->value("/window width", parent->width() / 2).toInt();
		height = configSettings->value("/window height", parent->height() / 2).toInt();
1332
		resize(width, height);
1333 1334 1335 1336
		x = configSettings->value("/window x");
		y = configSettings->value("/window y");
		if ((x.isValid())&&(y.isValid()))
			move(x.toInt(), y.toInt());
1337
		QList<int> sizes = configSettings->readSizes("/split", &ok);
1338 1339 1340 1341 1342 1343 1344 1345 1346
		if (ok)
			split->setSizes(sizes);
		configSettings->endGroup();
		connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
	}
}

void ConfigSearchWindow::saveSettings(void)
{
1347 1348 1349 1350 1351 1352 1353 1354 1355
	if (!objectName().isEmpty()) {
		configSettings->beginGroup(objectName());
		configSettings->setValue("/window x", pos().x());
		configSettings->setValue("/window y", pos().y());
		configSettings->setValue("/window width", size().width());
		configSettings->setValue("/window height", size().height());
		configSettings->writeSizes("/split", split->sizes());
		configSettings->endGroup();
	}
1356 1357 1358 1359
}

void ConfigSearchWindow::search(void)
{
1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375
	struct symbol **p;
	struct property *prop;
	ConfigItem *lastItem = NULL;

	free(result);
	list->list->clear();
	info->clear();

	result = sym_re_search(editField->text().toLatin1());
	if (!result)
		return;
	for (p = result; *p; p++) {
		for_all_prompts((*p), prop)
			lastItem = new ConfigItem(list->list, lastItem, prop->menu,
						  menu_is_visible(prop->menu));
	}
1376 1377
}

L
Linus Torvalds 已提交
1378 1379 1380 1381
/*
 * Construct the complete config widget
 */
ConfigMainWindow::ConfigMainWindow(void)
1382
	: searchWindow(0)
L
Linus Torvalds 已提交
1383 1384
{
	QMenuBar* menu;
1385
	bool ok = true;
1386 1387
	QVariant x, y;
	int width, height;
R
Randy Dunlap 已提交
1388
	char title[256];
L
Linus Torvalds 已提交
1389

1390
	QDesktopWidget *d = configApp->desktop();
1391 1392
	snprintf(title, sizeof(title), "%s%s",
		rootmenu.prompt->text,
1393 1394
		""
		);
1395
	setWindowTitle(title);
L
Linus Torvalds 已提交
1396

1397 1398
	width = configSettings->value("/window width", d->width() - 64).toInt();
	height = configSettings->value("/window height", d->height() - 64).toInt();
L
Linus Torvalds 已提交
1399
	resize(width, height);
1400 1401 1402 1403
	x = configSettings->value("/window x");
	y = configSettings->value("/window y");
	if ((x.isValid())&&(y.isValid()))
		move(x.toInt(), y.toInt());
L
Linus Torvalds 已提交
1404

1405 1406 1407 1408 1409
	QWidget *widget = new QWidget(this);
	QVBoxLayout *layout = new QVBoxLayout(widget);
	setCentralWidget(widget);

	split1 = new QSplitter(widget);
1410
	split1->setOrientation(Qt::Horizontal);
1411
	split1->setChildrenCollapsible(false);
L
Linus Torvalds 已提交
1412

1413
	menuView = new ConfigView(widget, "menu");
L
Linus Torvalds 已提交
1414 1415
	menuList = menuView->list;

1416 1417
	split2 = new QSplitter(widget);
	split2->setChildrenCollapsible(false);
1418
	split2->setOrientation(Qt::Vertical);
L
Linus Torvalds 已提交
1419 1420

	// create config tree
1421
	configView = new ConfigView(widget, "config");
L
Linus Torvalds 已提交
1422 1423
	configList = configView->list;

1424 1425 1426 1427 1428 1429 1430
	helpText = new ConfigInfoView(widget, "help");

	layout->addWidget(split2);
	split2->addWidget(split1);
	split1->addWidget(configView);
	split1->addWidget(menuView);
	split2->addWidget(helpText);
L
Linus Torvalds 已提交
1431 1432 1433 1434 1435

	setTabOrder(configList, helpText);
	configList->setFocus();

	menu = menuBar();
1436
	toolBar = new QToolBar("Tools", this);
1437
	addToolBar(toolBar);
L
Linus Torvalds 已提交
1438

1439
	backAction = new QAction(QPixmap(xpm_back), "Back", this);
1440 1441
	connect(backAction, SIGNAL(triggered(bool)), SLOT(goBack()));

1442
	QAction *quitAction = new QAction("&Quit", this);
1443
	quitAction->setShortcut(Qt::CTRL + Qt::Key_Q);
1444 1445
	connect(quitAction, SIGNAL(triggered(bool)), SLOT(close()));

1446
	QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this);
1447
	loadAction->setShortcut(Qt::CTRL + Qt::Key_L);
1448 1449
	connect(loadAction, SIGNAL(triggered(bool)), SLOT(loadConfig()));

1450
	saveAction = new QAction(QPixmap(xpm_save), "&Save", this);
1451
	saveAction->setShortcut(Qt::CTRL + Qt::Key_S);
1452 1453
	connect(saveAction, SIGNAL(triggered(bool)), SLOT(saveConfig()));

1454
	conf_set_changed_callback(conf_changed);
1455

1456 1457
	// Set saveAction's initial state
	conf_changed();
1458 1459
	configname = xstrdup(conf_get_configname());

1460
	QAction *saveAsAction = new QAction("Save &As...", this);
1461
	  connect(saveAsAction, SIGNAL(triggered(bool)), SLOT(saveConfigAs()));
1462
	QAction *searchAction = new QAction("&Find", this);
1463
	searchAction->setShortcut(Qt::CTRL + Qt::Key_F);
1464
	  connect(searchAction, SIGNAL(triggered(bool)), SLOT(searchConfig()));
1465
	singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this);
1466
	singleViewAction->setCheckable(true);
1467
	  connect(singleViewAction, SIGNAL(triggered(bool)), SLOT(showSingleView()));
1468
	splitViewAction = new QAction(QPixmap(xpm_split_view), "Split View", this);
1469
	splitViewAction->setCheckable(true);
1470
	  connect(splitViewAction, SIGNAL(triggered(bool)), SLOT(showSplitView()));
1471
	fullViewAction = new QAction(QPixmap(xpm_tree_view), "Full View", this);
1472
	fullViewAction->setCheckable(true);
1473
	  connect(fullViewAction, SIGNAL(triggered(bool)), SLOT(showFullView()));
L
Linus Torvalds 已提交
1474

1475
	QAction *showNameAction = new QAction("Show Name", this);
1476
	  showNameAction->setCheckable(true);
1477
	  connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
1478
	  showNameAction->setChecked(configView->showName());
1479
	QAction *showRangeAction = new QAction("Show Range", this);
1480
	  showRangeAction->setCheckable(true);
1481
	  connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
1482
	QAction *showDataAction = new QAction("Show Data", this);
1483
	  showDataAction->setCheckable(true);
1484
	  connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
1485 1486

	QActionGroup *optGroup = new QActionGroup(this);
1487
	optGroup->setExclusive(true);
1488
	connect(optGroup, SIGNAL(triggered(QAction*)), configView,
1489
		SLOT(setOptionMode(QAction *)));
1490
	connect(optGroup, SIGNAL(triggered(QAction *)), menuView,
1491 1492
		SLOT(setOptionMode(QAction *)));

1493 1494 1495
	configView->showNormalAction = new QAction("Show Normal Options", optGroup);
	configView->showAllAction = new QAction("Show All Options", optGroup);
	configView->showPromptAction = new QAction("Show Prompt Options", optGroup);
1496 1497 1498
	configView->showNormalAction->setCheckable(true);
	configView->showAllAction->setCheckable(true);
	configView->showPromptAction->setCheckable(true);
1499

1500
	QAction *showDebugAction = new QAction("Show Debug Info", this);
1501
	  showDebugAction->setCheckable(true);
1502
	  connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
1503
	  showDebugAction->setChecked(helpText->showDebug());
L
Linus Torvalds 已提交
1504

1505
	QAction *showIntroAction = new QAction("Introduction", this);
1506
	  connect(showIntroAction, SIGNAL(triggered(bool)), SLOT(showIntro()));
1507
	QAction *showAboutAction = new QAction("About", this);
1508
	  connect(showAboutAction, SIGNAL(triggered(bool)), SLOT(showAbout()));
L
Linus Torvalds 已提交
1509 1510

	// init tool bar
1511
	toolBar->addAction(backAction);
L
Linus Torvalds 已提交
1512
	toolBar->addSeparator();
1513 1514
	toolBar->addAction(loadAction);
	toolBar->addAction(saveAction);
L
Linus Torvalds 已提交
1515
	toolBar->addSeparator();
1516 1517 1518
	toolBar->addAction(singleViewAction);
	toolBar->addAction(splitViewAction);
	toolBar->addAction(fullViewAction);
L
Linus Torvalds 已提交
1519 1520

	// create config menu
1521
	QMenu* config = menu->addMenu("&File");
1522 1523 1524
	config->addAction(loadAction);
	config->addAction(saveAction);
	config->addAction(saveAsAction);
1525
	config->addSeparator();
1526
	config->addAction(quitAction);
L
Linus Torvalds 已提交
1527

1528
	// create edit menu
1529
	QMenu* editMenu = menu->addMenu("&Edit");
1530
	editMenu->addAction(searchAction);
1531

L
Linus Torvalds 已提交
1532
	// create options menu
1533
	QMenu* optionMenu = menu->addMenu("&Option");
1534 1535 1536
	optionMenu->addAction(showNameAction);
	optionMenu->addAction(showRangeAction);
	optionMenu->addAction(showDataAction);
1537
	optionMenu->addSeparator();
1538
	optionMenu->addActions(optGroup->actions());
1539
	optionMenu->addSeparator();
1540
	optionMenu->addAction(showDebugAction);
L
Linus Torvalds 已提交
1541 1542

	// create help menu
1543
	menu->addSeparator();
1544
	QMenu* helpMenu = menu->addMenu("&Help");
1545 1546
	helpMenu->addAction(showIntroAction);
	helpMenu->addAction(showAboutAction);
L
Linus Torvalds 已提交
1547

1548 1549 1550
	connect (helpText, SIGNAL (anchorClicked (const QUrl &)),
		 helpText, SLOT (clicked (const QUrl &)) );

1551 1552 1553 1554
	connect(configList, SIGNAL(menuChanged(struct menu *)),
		helpText, SLOT(setInfo(struct menu *)));
	connect(configList, SIGNAL(menuSelected(struct menu *)),
		SLOT(changeMenu(struct menu *)));
1555 1556
	connect(configList, SIGNAL(itemSelected(struct menu *)),
		SLOT(changeItens(struct menu *)));
1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569
	connect(configList, SIGNAL(parentSelected()),
		SLOT(goBack()));
	connect(menuList, SIGNAL(menuChanged(struct menu *)),
		helpText, SLOT(setInfo(struct menu *)));
	connect(menuList, SIGNAL(menuSelected(struct menu *)),
		SLOT(changeMenu(struct menu *)));

	connect(configList, SIGNAL(gotFocus(struct menu *)),
		helpText, SLOT(setInfo(struct menu *)));
	connect(menuList, SIGNAL(gotFocus(struct menu *)),
		helpText, SLOT(setInfo(struct menu *)));
	connect(menuList, SIGNAL(gotFocus(struct menu *)),
		SLOT(listFocusChanged(void)));
1570 1571
	connect(helpText, SIGNAL(menuSelected(struct menu *)),
		SLOT(setMenuLink(struct menu *)));
L
Linus Torvalds 已提交
1572

1573
	QString listMode = configSettings->value("/listMode", "symbol").toString();
L
Linus Torvalds 已提交
1574 1575 1576 1577 1578 1579 1580 1581
	if (listMode == "single")
		showSingleView();
	else if (listMode == "full")
		showFullView();
	else /*if (listMode == "split")*/
		showSplitView();

	// UI setup done, restore splitter positions
1582
	QList<int> sizes = configSettings->readSizes("/split1", &ok);
L
Linus Torvalds 已提交
1583 1584 1585
	if (ok)
		split1->setSizes(sizes);

1586
	sizes = configSettings->readSizes("/split2", &ok);
L
Linus Torvalds 已提交
1587 1588 1589 1590 1591 1592
	if (ok)
		split2->setSizes(sizes);
}

void ConfigMainWindow::loadConfig(void)
{
1593 1594 1595 1596 1597 1598
	QString str;
	QByteArray ba;
	const char *name;

	str = QFileDialog::getOpenFileName(this, "", configname);
	if (str.isNull())
L
Linus Torvalds 已提交
1599
		return;
1600 1601 1602 1603 1604

	ba = str.toLocal8Bit();
	name = ba.data();

	if (conf_read(name))
1605
		QMessageBox::information(this, "qconf", "Unable to load configuration!");
1606 1607 1608 1609

	free(configname);
	configname = xstrdup(name);

L
Linus Torvalds 已提交
1610 1611 1612
	ConfigView::updateListAll();
}

1613
bool ConfigMainWindow::saveConfig(void)
L
Linus Torvalds 已提交
1614
{
1615
	if (conf_write(configname)) {
1616
		QMessageBox::information(this, "qconf", "Unable to save configuration!");
1617 1618
		return false;
	}
1619 1620
	conf_write_autoconf(0);

1621
	return true;
L
Linus Torvalds 已提交
1622 1623 1624 1625
}

void ConfigMainWindow::saveConfigAs(void)
{
1626 1627 1628 1629 1630 1631
	QString str;
	QByteArray ba;
	const char *name;

	str = QFileDialog::getSaveFileName(this, "", configname);
	if (str.isNull())
L
Linus Torvalds 已提交
1632
		return;
1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643

	ba = str.toLocal8Bit();
	name = ba.data();

	if (conf_write(name)) {
		QMessageBox::information(this, "qconf", "Unable to save configuration!");
	}
	conf_write_autoconf(0);

	free(configname);
	configname = xstrdup(name);
L
Linus Torvalds 已提交
1644 1645
}

1646 1647 1648
void ConfigMainWindow::searchConfig(void)
{
	if (!searchWindow)
1649
		searchWindow = new ConfigSearchWindow(this, "search");
1650 1651 1652
	searchWindow->show();
}

1653
void ConfigMainWindow::changeItens(struct menu *menu)
L
Linus Torvalds 已提交
1654
{
1655
	configList->setRootMenu(menu);
L
Linus Torvalds 已提交
1656 1657
}

1658 1659 1660 1661 1662
void ConfigMainWindow::changeMenu(struct menu *menu)
{
	menuList->setRootMenu(menu);
}

1663
void ConfigMainWindow::setMenuLink(struct menu *menu)
L
Linus Torvalds 已提交
1664
{
1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679
	struct menu *parent;
	ConfigList* list = NULL;
	ConfigItem* item;

	if (configList->menuSkip(menu))
		return;

	switch (configList->mode) {
	case singleMode:
		list = configList;
		parent = menu_get_parent_menu(menu);
		if (!parent)
			return;
		list->setRootMenu(parent);
		break;
1680
	case menuMode:
1681
		if (menu->flags & MENU_ROOT) {
1682
			menuList->setRootMenu(menu);
1683 1684
			configList->clearSelection();
			list = configList;
1685
		} else {
1686 1687 1688
			parent = menu_get_parent_menu(menu->parent);
			if (!parent)
				return;
1689 1690 1691

			/* Select the config view */
			item = configList->findConfigItem(parent);
1692
			if (item) {
1693
				configList->setSelected(item, true);
1694
				configList->scrollToItem(item);
1695
			}
1696 1697 1698 1699

			menuList->setRootMenu(parent);
			menuList->clearSelection();
			list = menuList;
1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711
		}
		break;
	case fullMode:
		list = configList;
		break;
	default:
		break;
	}

	if (list) {
		item = list->findConfigItem(menu);
		if (item) {
1712
			list->setSelected(item, true);
1713 1714
			list->scrollToItem(item);
			list->setFocus();
1715
			helpText->setInfo(menu);
1716 1717
		}
	}
L
Linus Torvalds 已提交
1718 1719
}

1720 1721
void ConfigMainWindow::listFocusChanged(void)
{
1722 1723
	if (menuList->mode == menuMode)
		configList->clearSelection();
1724 1725
}

L
Linus Torvalds 已提交
1726 1727
void ConfigMainWindow::goBack(void)
{
1728
	if (configList->rootEntry == &rootmenu)
B
Boris Barbulovski 已提交
1729 1730
		return;

1731
	configList->setParentMenu();
L
Linus Torvalds 已提交
1732 1733 1734 1735
}

void ConfigMainWindow::showSingleView(void)
{
1736 1737 1738 1739 1740 1741 1742
	singleViewAction->setEnabled(false);
	singleViewAction->setChecked(true);
	splitViewAction->setEnabled(true);
	splitViewAction->setChecked(false);
	fullViewAction->setEnabled(true);
	fullViewAction->setChecked(false);

1743 1744
	backAction->setEnabled(true);

L
Linus Torvalds 已提交
1745
	menuView->hide();
1746 1747 1748 1749 1750 1751
	menuList->setRootMenu(0);
	configList->mode = singleMode;
	if (configList->rootEntry == &rootmenu)
		configList->updateListAll();
	else
		configList->setRootMenu(&rootmenu);
L
Linus Torvalds 已提交
1752 1753 1754 1755 1756
	configList->setFocus();
}

void ConfigMainWindow::showSplitView(void)
{
1757 1758 1759 1760 1761 1762 1763
	singleViewAction->setEnabled(true);
	singleViewAction->setChecked(false);
	splitViewAction->setEnabled(false);
	splitViewAction->setChecked(true);
	fullViewAction->setEnabled(true);
	fullViewAction->setChecked(false);

1764 1765
	backAction->setEnabled(false);

1766
	configList->mode = menuMode;
1767 1768 1769 1770 1771 1772
	if (configList->rootEntry == &rootmenu)
		configList->updateListAll();
	else
		configList->setRootMenu(&rootmenu);
	configList->setAllOpen(true);
	configApp->processEvents();
1773
	menuList->mode = symbolMode;
1774 1775
	menuList->setRootMenu(&rootmenu);
	menuList->setAllOpen(true);
L
Linus Torvalds 已提交
1776 1777 1778 1779 1780 1781
	menuView->show();
	menuList->setFocus();
}

void ConfigMainWindow::showFullView(void)
{
1782 1783 1784 1785 1786 1787 1788
	singleViewAction->setEnabled(true);
	singleViewAction->setChecked(false);
	splitViewAction->setEnabled(true);
	splitViewAction->setChecked(false);
	fullViewAction->setEnabled(false);
	fullViewAction->setChecked(true);

1789 1790
	backAction->setEnabled(false);

L
Linus Torvalds 已提交
1791
	menuView->hide();
1792 1793 1794 1795 1796 1797
	menuList->setRootMenu(0);
	configList->mode = fullMode;
	if (configList->rootEntry == &rootmenu)
		configList->updateListAll();
	else
		configList->setRootMenu(&rootmenu);
L
Linus Torvalds 已提交
1798 1799 1800 1801 1802 1803 1804 1805
	configList->setFocus();
}

/*
 * ask for saving configuration before quitting
 */
void ConfigMainWindow::closeEvent(QCloseEvent* e)
{
1806
	if (!conf_get_changed()) {
L
Linus Torvalds 已提交
1807 1808 1809
		e->accept();
		return;
	}
1810
	QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning,
L
Linus Torvalds 已提交
1811
			QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
1812 1813 1814
	mb.setButtonText(QMessageBox::Yes, "&Save Changes");
	mb.setButtonText(QMessageBox::No, "&Discard Changes");
	mb.setButtonText(QMessageBox::Cancel, "Cancel Exit");
L
Linus Torvalds 已提交
1815 1816
	switch (mb.exec()) {
	case QMessageBox::Yes:
1817 1818 1819 1820 1821
		if (saveConfig())
			e->accept();
		else
			e->ignore();
		break;
L
Linus Torvalds 已提交
1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832
	case QMessageBox::No:
		e->accept();
		break;
	case QMessageBox::Cancel:
		e->ignore();
		break;
	}
}

void ConfigMainWindow::showIntro(void)
{
1833
	static const QString str = "Welcome to the qconf graphical configuration tool.\n\n"
L
Linus Torvalds 已提交
1834 1835 1836 1837 1838 1839 1840 1841 1842
		"For each option, a blank box indicates the feature is disabled, a check\n"
		"indicates it is enabled, and a dot indicates that it is to be compiled\n"
		"as a module.  Clicking on the box will cycle through the three states.\n\n"
		"If you do not see an option (e.g., a device driver) that you believe\n"
		"should be present, try turning on Show All Options under the Options menu.\n"
		"Although there is no cross reference yet to help you figure out what other\n"
		"options must be enabled to support the option you are interested in, you can\n"
		"still view the help of a grayed-out option.\n\n"
		"Toggling Show Debug Info under the Options menu will show the dependencies,\n"
1843
		"which you can then match by examining other options.\n\n";
L
Linus Torvalds 已提交
1844 1845 1846 1847 1848 1849

	QMessageBox::information(this, "qconf", str);
}

void ConfigMainWindow::showAbout(void)
{
1850
	static const QString str = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n"
1851
		"Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>.\n\n"
1852
		"Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n";
L
Linus Torvalds 已提交
1853 1854 1855 1856 1857 1858

	QMessageBox::information(this, "qconf", str);
}

void ConfigMainWindow::saveSettings(void)
{
1859 1860 1861 1862
	configSettings->setValue("/window x", pos().x());
	configSettings->setValue("/window y", pos().y());
	configSettings->setValue("/window width", size().width());
	configSettings->setValue("/window height", size().height());
L
Linus Torvalds 已提交
1863 1864

	QString entry;
1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876
	switch(configList->mode) {
	case singleMode :
		entry = "single";
		break;

	case symbolMode :
		entry = "split";
		break;

	case fullMode :
		entry = "full";
		break;
1877

1878 1879 1880
	default:
		break;
	}
1881
	configSettings->setValue("/listMode", entry);
L
Linus Torvalds 已提交
1882

1883 1884
	configSettings->writeSizes("/split1", split1->sizes());
	configSettings->writeSizes("/split2", split2->sizes());
L
Linus Torvalds 已提交
1885 1886
}

1887 1888 1889 1890 1891 1892
void ConfigMainWindow::conf_changed(void)
{
	if (saveAction)
		saveAction->setEnabled(conf_get_changed());
}

L
Linus Torvalds 已提交
1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912
void fixup_rootmenu(struct menu *menu)
{
	struct menu *child;
	static int menu_cnt = 0;

	menu->flags |= MENU_ROOT;
	for (child = menu->list; child; child = child->next) {
		if (child->prompt && child->prompt->type == P_MENU) {
			menu_cnt++;
			fixup_rootmenu(child);
			menu_cnt--;
		} else if (!menu_cnt)
			fixup_rootmenu(child);
	}
}

static const char *progname;

static void usage(void)
{
1913
	printf("%s [-s] <config>\n", progname);
L
Linus Torvalds 已提交
1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925
	exit(0);
}

int main(int ac, char** av)
{
	ConfigMainWindow* v;
	const char *name;

	progname = av[0];
	configApp = new QApplication(ac, av);
	if (ac > 1 && av[1][0] == '-') {
		switch (av[1][1]) {
1926 1927 1928
		case 's':
			conf_set_message_callback(NULL);
			break;
L
Linus Torvalds 已提交
1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943
		case 'h':
		case '?':
			usage();
		}
		name = av[2];
	} else
		name = av[1];
	if (!name)
		usage();

	conf_parse(name);
	fixup_rootmenu(&rootmenu);
	conf_read(NULL);
	//zconfdump(stdout);

1944 1945
	configSettings = new ConfigSettings();
	configSettings->beginGroup("/kconfig/qconf");
L
Linus Torvalds 已提交
1946 1947 1948 1949 1950
	v = new ConfigMainWindow();

	//zconfdump(stdout);
	configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
	configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
1951
	v->show();
L
Linus Torvalds 已提交
1952 1953
	configApp->exec();

1954 1955
	configSettings->endGroup();
	delete configSettings;
1956 1957
	delete v;
	delete configApp;
1958

L
Linus Torvalds 已提交
1959 1960
	return 0;
}