qconf.cc 43 KB

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