~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/scripts/kconfig/qconf.cc

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php