qconf.cc 43 KB

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