1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> 4 * Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com> 5 */ 6 7 #include <QAction> 8 #include <QActionGroup> 9 #include <QApplication> 10 #include <QCloseEvent> 11 #include <QDebug> 12 #include <QFileDialog> 13 #include <QLabel> 14 #include <QLayout> 15 #include <QList> 16 #include <QMenu> 17 #include <QMenuBar> 18 #include <QMessageBox> 19 #include <QRegularExpression> 20 #include <QScreen> 21 #include <QToolBar> 22 23 #include <stdlib.h> 24 25 #include <xalloc.h> 26 #include "lkc.h" 27 #include "qconf.h" 28 29 #include "images.h" 30 31 32 static QApplication *configApp; 33 static ConfigSettings *configSettings; 34 35 QAction *ConfigMainWindow::saveAction; 36 37 ConfigSettings::ConfigSettings() 38 : QSettings("kernel.org", "qconf") 39 { 40 } 41 42 /** 43 * Reads a list of integer values from the application settings. 44 */ 45 QList<int> ConfigSettings::readSizes(const QString& key, bool *ok) 46 { 47 QList<int> result; 48 49 if (contains(key)) 50 { 51 QStringList entryList = value(key).toStringList(); 52 QStringList::Iterator it; 53 54 for (it = entryList.begin(); it != entryList.end(); ++it) 55 result.push_back((*it).toInt()); 56 57 *ok = true; 58 } 59 else 60 *ok = false; 61 62 return result; 63 } 64 65 /** 66 * Writes a list of integer values to the application settings. 67 */ 68 bool ConfigSettings::writeSizes(const QString& key, const QList<int>& value) 69 { 70 QStringList stringList; 71 QList<int>::ConstIterator it; 72 73 for (it = value.begin(); it != value.end(); ++it) 74 stringList.push_back(QString::number(*it)); 75 setValue(key, stringList); 76 77 return true; 78 } 79 80 QIcon ConfigItem::symbolYesIcon; 81 QIcon ConfigItem::symbolModIcon; 82 QIcon ConfigItem::symbolNoIcon; 83 QIcon ConfigItem::choiceYesIcon; 84 QIcon ConfigItem::choiceNoIcon; 85 QIcon ConfigItem::menuIcon; 86 QIcon ConfigItem::menubackIcon; 87 88 /* 89 * update the displayed of a menu entry 90 */ 91 void ConfigItem::updateMenu(void) 92 { 93 ConfigList* list; 94 struct symbol* sym; 95 struct property *prop; 96 QString prompt; 97 int type; 98 tristate expr; 99 100 list = listView(); 101 if (goParent) { 102 setIcon(promptColIdx, menubackIcon); 103 prompt = ".."; 104 goto set_prompt; 105 } 106 107 sym = menu->sym; 108 prop = menu->prompt; 109 prompt = menu_get_prompt(menu); 110 111 if (prop) switch (prop->type) { 112 case P_MENU: 113 if (list->mode == singleMode || list->mode == symbolMode) { 114 /* a menuconfig entry is displayed differently 115 * depending whether it's at the view root or a child. 116 */ 117 if (sym && list->rootEntry == menu) 118 break; 119 setIcon(promptColIdx, menuIcon); 120 } else { 121 if (sym) 122 break; 123 setIcon(promptColIdx, QIcon()); 124 } 125 goto set_prompt; 126 case P_COMMENT: 127 setIcon(promptColIdx, QIcon()); 128 prompt = "*** " + prompt + " ***"; 129 goto set_prompt; 130 default: 131 ; 132 } 133 if (!sym) 134 goto set_prompt; 135 136 setText(nameColIdx, sym->name); 137 138 type = sym_get_type(sym); 139 switch (type) { 140 case S_BOOLEAN: 141 case S_TRISTATE: 142 char ch; 143 144 if (!sym_is_changeable(sym) && list->optMode == normalOpt) { 145 setIcon(promptColIdx, QIcon()); 146 break; 147 } 148 expr = sym_get_tristate_value(sym); 149 switch (expr) { 150 case yes: 151 if (sym_is_choice_value(sym)) 152 setIcon(promptColIdx, choiceYesIcon); 153 else 154 setIcon(promptColIdx, symbolYesIcon); 155 ch = 'Y'; 156 break; 157 case mod: 158 setIcon(promptColIdx, symbolModIcon); 159 ch = 'M'; 160 break; 161 default: 162 if (sym_is_choice_value(sym) && type == S_BOOLEAN) 163 setIcon(promptColIdx, choiceNoIcon); 164 else 165 setIcon(promptColIdx, symbolNoIcon); 166 ch = 'N'; 167 break; 168 } 169 170 setText(dataColIdx, QChar(ch)); 171 break; 172 case S_INT: 173 case S_HEX: 174 case S_STRING: 175 setText(dataColIdx, sym_get_string_value(sym)); 176 break; 177 } 178 if (!sym_has_value(sym) && visible) 179 prompt += " (NEW)"; 180 set_prompt: 181 setText(promptColIdx, prompt); 182 } 183 184 void ConfigItem::testUpdateMenu(bool v) 185 { 186 ConfigItem* i; 187 188 visible = v; 189 if (!menu) 190 return; 191 192 sym_calc_value(menu->sym); 193 if (menu->flags & MENU_CHANGED) { 194 /* the menu entry changed, so update all list items */ 195 menu->flags &= ~MENU_CHANGED; 196 for (i = (ConfigItem*)menu->data; i; i = i->nextItem) 197 i->updateMenu(); 198 } else if (listView()->updateAll) 199 updateMenu(); 200 } 201 202 203 /* 204 * construct a menu entry 205 */ 206 void ConfigItem::init(void) 207 { 208 if (menu) { 209 ConfigList* list = listView(); 210 nextItem = (ConfigItem*)menu->data; 211 menu->data = this; 212 213 if (list->mode != fullMode) 214 setExpanded(true); 215 sym_calc_value(menu->sym); 216 217 if (menu->sym) { 218 enum symbol_type type = menu->sym->type; 219 220 // Allow to edit "int", "hex", and "string" in-place in 221 // the data column. Unfortunately, you cannot specify 222 // the flags per column. Set ItemIsEditable for all 223 // columns here, and check the column in createEditor(). 224 if (type == S_INT || type == S_HEX || type == S_STRING) 225 setFlags(flags() | Qt::ItemIsEditable); 226 } 227 } 228 updateMenu(); 229 } 230 231 /* 232 * destruct a menu entry 233 */ 234 ConfigItem::~ConfigItem(void) 235 { 236 if (menu) { 237 ConfigItem** ip = (ConfigItem**)&menu->data; 238 for (; *ip; ip = &(*ip)->nextItem) { 239 if (*ip == this) { 240 *ip = nextItem; 241 break; 242 } 243 } 244 } 245 } 246 247 QWidget *ConfigItemDelegate::createEditor(QWidget *parent, 248 const QStyleOptionViewItem &option, 249 const QModelIndex &index) const 250 { 251 ConfigItem *item; 252 253 // Only the data column is editable 254 if (index.column() != dataColIdx) 255 return nullptr; 256 257 // You cannot edit invisible menus 258 item = static_cast<ConfigItem *>(index.internalPointer()); 259 if (!item || !item->menu || !menu_is_visible(item->menu)) 260 return nullptr; 261 262 return QStyledItemDelegate::createEditor(parent, option, index); 263 } 264 265 void ConfigItemDelegate::setModelData(QWidget *editor, 266 QAbstractItemModel *model, 267 const QModelIndex &index) const 268 { 269 QLineEdit *lineEdit; 270 ConfigItem *item; 271 struct symbol *sym; 272 bool success; 273 274 lineEdit = qobject_cast<QLineEdit *>(editor); 275 // If this is not a QLineEdit, use the parent's default. 276 // (does this happen?) 277 if (!lineEdit) 278 goto parent; 279 280 item = static_cast<ConfigItem *>(index.internalPointer()); 281 if (!item || !item->menu) 282 goto parent; 283 284 sym = item->menu->sym; 285 if (!sym) 286 goto parent; 287 288 success = sym_set_string_value(sym, lineEdit->text().toUtf8().data()); 289 if (success) { 290 ConfigList::updateListForAll(); 291 } else { 292 QMessageBox::information(editor, "qconf", 293 "Cannot set the data (maybe due to out of range).\n" 294 "Setting the old value."); 295 lineEdit->setText(sym_get_string_value(sym)); 296 } 297 298 parent: 299 QStyledItemDelegate::setModelData(editor, model, index); 300 } 301 302 ConfigList::ConfigList(QWidget *parent, const char *name) 303 : QTreeWidget(parent), 304 updateAll(false), 305 showName(false), mode(singleMode), optMode(normalOpt), 306 rootEntry(0), headerPopup(0) 307 { 308 setObjectName(name); 309 setSortingEnabled(false); 310 setRootIsDecorated(true); 311 312 setVerticalScrollMode(ScrollPerPixel); 313 setHorizontalScrollMode(ScrollPerPixel); 314 315 setHeaderLabels(QStringList() << "Option" << "Name" << "Value"); 316 317 connect(this, &ConfigList::itemSelectionChanged, 318 this, &ConfigList::updateSelection); 319 320 if (name) { 321 configSettings->beginGroup(name); 322 showName = configSettings->value("/showName", false).toBool(); 323 optMode = (enum optionMode)configSettings->value("/optionMode", 0).toInt(); 324 configSettings->endGroup(); 325 connect(configApp, &QApplication::aboutToQuit, 326 this, &ConfigList::saveSettings); 327 } 328 329 showColumn(promptColIdx); 330 331 setItemDelegate(new ConfigItemDelegate(this)); 332 333 allLists.append(this); 334 335 reinit(); 336 } 337 338 ConfigList::~ConfigList() 339 { 340 allLists.removeOne(this); 341 } 342 343 bool ConfigList::menuSkip(struct menu *menu) 344 { 345 if (optMode == normalOpt && menu_is_visible(menu)) 346 return false; 347 if (optMode == promptOpt && menu_has_prompt(menu)) 348 return false; 349 if (optMode == allOpt) 350 return false; 351 return true; 352 } 353 354 void ConfigList::reinit(void) 355 { 356 hideColumn(nameColIdx); 357 358 if (showName) 359 showColumn(nameColIdx); 360 361 updateListAll(); 362 } 363 364 void ConfigList::setOptionMode(QAction *action) 365 { 366 if (action == showNormalAction) 367 optMode = normalOpt; 368 else if (action == showAllAction) 369 optMode = allOpt; 370 else 371 optMode = promptOpt; 372 373 updateListAll(); 374 } 375 376 void ConfigList::saveSettings(void) 377 { 378 if (!objectName().isEmpty()) { 379 configSettings->beginGroup(objectName()); 380 configSettings->setValue("/showName", showName); 381 configSettings->setValue("/optionMode", (int)optMode); 382 configSettings->endGroup(); 383 } 384 } 385 386 ConfigItem* ConfigList::findConfigItem(struct menu *menu) 387 { 388 ConfigItem* item = (ConfigItem*)menu->data; 389 390 for (; item; item = item->nextItem) { 391 if (this == item->listView()) 392 break; 393 } 394 395 return item; 396 } 397 398 void ConfigList::updateSelection(void) 399 { 400 struct menu *menu; 401 enum prop_type type; 402 403 if (selectedItems().count() == 0) 404 return; 405 406 ConfigItem* item = (ConfigItem*)selectedItems().first(); 407 if (!item) 408 return; 409 410 menu = item->menu; 411 emit menuChanged(menu); 412 if (!menu) 413 return; 414 type = menu->prompt ? menu->prompt->type : P_UNKNOWN; 415 if (mode == menuMode && type == P_MENU) 416 emit menuSelected(menu); 417 } 418 419 void ConfigList::updateList() 420 { 421 ConfigItem* last = 0; 422 ConfigItem *item; 423 424 if (!rootEntry) { 425 if (mode != listMode) 426 goto update; 427 QTreeWidgetItemIterator it(this); 428 429 while (*it) { 430 item = (ConfigItem*)(*it); 431 if (!item->menu) 432 continue; 433 item->testUpdateMenu(menu_is_visible(item->menu)); 434 435 ++it; 436 } 437 return; 438 } 439 440 if (rootEntry != &rootmenu && (mode == singleMode || 441 (mode == symbolMode && rootEntry->parent != &rootmenu))) { 442 item = (ConfigItem *)topLevelItem(0); 443 if (!item) 444 item = new ConfigItem(this, 0, true); 445 last = item; 446 } 447 if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) && 448 rootEntry->sym && rootEntry->prompt) { 449 item = last ? last->nextSibling() : nullptr; 450 if (!item) 451 item = new ConfigItem(this, last, rootEntry, true); 452 else 453 item->testUpdateMenu(true); 454 455 updateMenuList(item, rootEntry); 456 update(); 457 resizeColumnToContents(0); 458 return; 459 } 460 update: 461 updateMenuList(rootEntry); 462 update(); 463 resizeColumnToContents(0); 464 } 465 466 void ConfigList::updateListForAll() 467 { 468 QListIterator<ConfigList *> it(allLists); 469 470 while (it.hasNext()) { 471 ConfigList *list = it.next(); 472 473 list->updateList(); 474 } 475 } 476 477 void ConfigList::updateListAllForAll() 478 { 479 QListIterator<ConfigList *> it(allLists); 480 481 while (it.hasNext()) { 482 ConfigList *list = it.next(); 483 484 list->updateList(); 485 } 486 } 487 488 void ConfigList::setValue(ConfigItem* item, tristate val) 489 { 490 struct symbol* sym; 491 int type; 492 tristate oldval; 493 494 sym = item->menu ? item->menu->sym : 0; 495 if (!sym) 496 return; 497 498 type = sym_get_type(sym); 499 switch (type) { 500 case S_BOOLEAN: 501 case S_TRISTATE: 502 oldval = sym_get_tristate_value(sym); 503 504 if (!sym_set_tristate_value(sym, val)) 505 return; 506 if (oldval == no && item->menu->list) 507 item->setExpanded(true); 508 ConfigList::updateListForAll(); 509 break; 510 } 511 } 512 513 void ConfigList::changeValue(ConfigItem* item) 514 { 515 struct symbol* sym; 516 struct menu* menu; 517 int type, oldexpr, newexpr; 518 519 menu = item->menu; 520 if (!menu) 521 return; 522 sym = menu->sym; 523 if (!sym) { 524 if (item->menu->list) 525 item->setExpanded(!item->isExpanded()); 526 return; 527 } 528 529 type = sym_get_type(sym); 530 switch (type) { 531 case S_BOOLEAN: 532 case S_TRISTATE: 533 oldexpr = sym_get_tristate_value(sym); 534 newexpr = sym_toggle_tristate_value(sym); 535 if (item->menu->list) { 536 if (oldexpr == newexpr) 537 item->setExpanded(!item->isExpanded()); 538 else if (oldexpr == no) 539 item->setExpanded(true); 540 } 541 if (oldexpr != newexpr) 542 ConfigList::updateListForAll(); 543 break; 544 default: 545 break; 546 } 547 } 548 549 void ConfigList::setRootMenu(struct menu *menu) 550 { 551 enum prop_type type; 552 553 if (rootEntry == menu) 554 return; 555 type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN; 556 if (type != P_MENU) 557 return; 558 updateMenuList(0); 559 rootEntry = menu; 560 updateListAll(); 561 if (currentItem()) { 562 setSelected(currentItem(), hasFocus()); 563 scrollToItem(currentItem()); 564 } 565 } 566 567 void ConfigList::setParentMenu(void) 568 { 569 ConfigItem* item; 570 struct menu *oldroot; 571 572 oldroot = rootEntry; 573 if (rootEntry == &rootmenu) 574 return; 575 setRootMenu(menu_get_parent_menu(rootEntry->parent)); 576 577 QTreeWidgetItemIterator it(this); 578 while (*it) { 579 item = (ConfigItem *)(*it); 580 if (item->menu == oldroot) { 581 setCurrentItem(item); 582 scrollToItem(item); 583 break; 584 } 585 586 ++it; 587 } 588 } 589 590 /* 591 * update all the children of a menu entry 592 * removes/adds the entries from the parent widget as necessary 593 * 594 * parent: either the menu list widget or a menu entry widget 595 * menu: entry to be updated 596 */ 597 void ConfigList::updateMenuList(ConfigItem *parent, struct menu* menu) 598 { 599 struct menu* child; 600 ConfigItem* item; 601 ConfigItem* last; 602 bool visible; 603 enum prop_type type; 604 605 if (!menu) { 606 while (parent->childCount() > 0) 607 { 608 delete parent->takeChild(0); 609 } 610 611 return; 612 } 613 614 last = parent->firstChild(); 615 if (last && !last->goParent) 616 last = 0; 617 for (child = menu->list; child; child = child->next) { 618 item = last ? last->nextSibling() : parent->firstChild(); 619 type = child->prompt ? child->prompt->type : P_UNKNOWN; 620 621 switch (mode) { 622 case menuMode: 623 if (!(child->flags & MENU_ROOT)) 624 goto hide; 625 break; 626 case symbolMode: 627 if (child->flags & MENU_ROOT) 628 goto hide; 629 break; 630 default: 631 break; 632 } 633 634 visible = menu_is_visible(child); 635 if (!menuSkip(child)) { 636 if (!child->sym && !child->list && !child->prompt) 637 continue; 638 if (!item || item->menu != child) 639 item = new ConfigItem(parent, last, child, visible); 640 else 641 item->testUpdateMenu(visible); 642 643 if (mode == fullMode || mode == menuMode || type != P_MENU) 644 updateMenuList(item, child); 645 else 646 updateMenuList(item, 0); 647 last = item; 648 continue; 649 } 650 hide: 651 if (item && item->menu == child) { 652 last = parent->firstChild(); 653 if (last == item) 654 last = 0; 655 else while (last->nextSibling() != item) 656 last = last->nextSibling(); 657 delete item; 658 } 659 } 660 } 661 662 void ConfigList::updateMenuList(struct menu *menu) 663 { 664 struct menu* child; 665 ConfigItem* item; 666 ConfigItem* last; 667 bool visible; 668 enum prop_type type; 669 670 if (!menu) { 671 while (topLevelItemCount() > 0) 672 { 673 delete takeTopLevelItem(0); 674 } 675 676 return; 677 } 678 679 last = (ConfigItem *)topLevelItem(0); 680 if (last && !last->goParent) 681 last = 0; 682 for (child = menu->list; child; child = child->next) { 683 item = last ? last->nextSibling() : (ConfigItem *)topLevelItem(0); 684 type = child->prompt ? child->prompt->type : P_UNKNOWN; 685 686 switch (mode) { 687 case menuMode: 688 if (!(child->flags & MENU_ROOT)) 689 goto hide; 690 break; 691 case symbolMode: 692 if (child->flags & MENU_ROOT) 693 goto hide; 694 break; 695 default: 696 break; 697 } 698 699 visible = menu_is_visible(child); 700 if (!menuSkip(child)) { 701 if (!child->sym && !child->list && !child->prompt) 702 continue; 703 if (!item || item->menu != child) 704 item = new ConfigItem(this, last, child, visible); 705 else 706 item->testUpdateMenu(visible); 707 708 if (mode == fullMode || mode == menuMode || type != P_MENU) 709 updateMenuList(item, child); 710 else 711 updateMenuList(item, 0); 712 last = item; 713 continue; 714 } 715 hide: 716 if (item && item->menu == child) { 717 last = (ConfigItem *)topLevelItem(0); 718 if (last == item) 719 last = 0; 720 else while (last->nextSibling() != item) 721 last = last->nextSibling(); 722 delete item; 723 } 724 } 725 } 726 727 void ConfigList::keyPressEvent(QKeyEvent* ev) 728 { 729 QTreeWidgetItem* i = currentItem(); 730 ConfigItem* item; 731 struct menu *menu; 732 enum prop_type type; 733 734 if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) { 735 emit parentSelected(); 736 ev->accept(); 737 return; 738 } 739 740 if (!i) { 741 Parent::keyPressEvent(ev); 742 return; 743 } 744 item = (ConfigItem*)i; 745 746 switch (ev->key()) { 747 case Qt::Key_Return: 748 case Qt::Key_Enter: 749 if (item->goParent) { 750 emit parentSelected(); 751 break; 752 } 753 menu = item->menu; 754 if (!menu) 755 break; 756 type = menu->prompt ? menu->prompt->type : P_UNKNOWN; 757 if (type == P_MENU && rootEntry != menu && 758 mode != fullMode && mode != menuMode) { 759 if (mode == menuMode) 760 emit menuSelected(menu); 761 else 762 emit itemSelected(menu); 763 break; 764 } 765 case Qt::Key_Space: 766 changeValue(item); 767 break; 768 case Qt::Key_N: 769 setValue(item, no); 770 break; 771 case Qt::Key_M: 772 setValue(item, mod); 773 break; 774 case Qt::Key_Y: 775 setValue(item, yes); 776 break; 777 default: 778 Parent::keyPressEvent(ev); 779 return; 780 } 781 ev->accept(); 782 } 783 784 void ConfigList::mousePressEvent(QMouseEvent* e) 785 { 786 //QPoint p(contentsToViewport(e->pos())); 787 //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y()); 788 Parent::mousePressEvent(e); 789 } 790 791 void ConfigList::mouseReleaseEvent(QMouseEvent* e) 792 { 793 QPoint p = e->pos(); 794 ConfigItem* item = (ConfigItem*)itemAt(p); 795 struct menu *menu; 796 enum prop_type ptype; 797 QIcon icon; 798 int idx, x; 799 800 if (!item) 801 goto skip; 802 803 menu = item->menu; 804 x = header()->offset() + p.x(); 805 idx = header()->logicalIndexAt(x); 806 switch (idx) { 807 case promptColIdx: 808 icon = item->icon(promptColIdx); 809 if (!icon.isNull()) { 810 int off = header()->sectionPosition(0) + visualRect(indexAt(p)).x() + 4; // 4 is Hardcoded image offset. There might be a way to do it properly. 811 if (x >= off && x < off + icon.availableSizes().first().width()) { 812 if (item->goParent) { 813 emit parentSelected(); 814 break; 815 } else if (!menu) 816 break; 817 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; 818 if (ptype == P_MENU && rootEntry != menu && 819 mode != fullMode && mode != menuMode && 820 mode != listMode) 821 emit menuSelected(menu); 822 else 823 changeValue(item); 824 } 825 } 826 break; 827 case dataColIdx: 828 changeValue(item); 829 break; 830 } 831 832 skip: 833 //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y()); 834 Parent::mouseReleaseEvent(e); 835 } 836 837 void ConfigList::mouseMoveEvent(QMouseEvent* e) 838 { 839 //QPoint p(contentsToViewport(e->pos())); 840 //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y()); 841 Parent::mouseMoveEvent(e); 842 } 843 844 void ConfigList::mouseDoubleClickEvent(QMouseEvent* e) 845 { 846 QPoint p = e->pos(); 847 ConfigItem* item = (ConfigItem*)itemAt(p); 848 struct menu *menu; 849 enum prop_type ptype; 850 851 if (!item) 852 goto skip; 853 if (item->goParent) { 854 emit parentSelected(); 855 goto skip; 856 } 857 menu = item->menu; 858 if (!menu) 859 goto skip; 860 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; 861 if (ptype == P_MENU && mode != listMode) { 862 if (mode == singleMode) 863 emit itemSelected(menu); 864 else if (mode == symbolMode) 865 emit menuSelected(menu); 866 } else if (menu->sym) 867 changeValue(item); 868 869 skip: 870 //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y()); 871 Parent::mouseDoubleClickEvent(e); 872 } 873 874 void ConfigList::focusInEvent(QFocusEvent *e) 875 { 876 struct menu *menu = NULL; 877 878 Parent::focusInEvent(e); 879 880 ConfigItem* item = (ConfigItem *)currentItem(); 881 if (item) { 882 setSelected(item, true); 883 menu = item->menu; 884 } 885 emit gotFocus(menu); 886 } 887 888 void ConfigList::contextMenuEvent(QContextMenuEvent *e) 889 { 890 if (!headerPopup) { 891 QAction *action; 892 893 headerPopup = new QMenu(this); 894 action = new QAction("Show Name", this); 895 action->setCheckable(true); 896 connect(action, &QAction::toggled, 897 this, &ConfigList::setShowName); 898 connect(this, &ConfigList::showNameChanged, 899 action, &QAction::setChecked); 900 action->setChecked(showName); 901 headerPopup->addAction(action); 902 } 903 904 headerPopup->exec(e->globalPos()); 905 e->accept(); 906 } 907 908 void ConfigList::setShowName(bool on) 909 { 910 if (showName == on) 911 return; 912 913 showName = on; 914 reinit(); 915 emit showNameChanged(on); 916 } 917 918 QList<ConfigList *> ConfigList::allLists; 919 QAction *ConfigList::showNormalAction; 920 QAction *ConfigList::showAllAction; 921 QAction *ConfigList::showPromptAction; 922 923 void ConfigList::setAllOpen(bool open) 924 { 925 QTreeWidgetItemIterator it(this); 926 927 while (*it) { 928 (*it)->setExpanded(open); 929 930 ++it; 931 } 932 } 933 934 ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name) 935 : Parent(parent), sym(0), _menu(0) 936 { 937 setObjectName(name); 938 setOpenLinks(false); 939 940 if (!objectName().isEmpty()) { 941 configSettings->beginGroup(objectName()); 942 setShowDebug(configSettings->value("/showDebug", false).toBool()); 943 configSettings->endGroup(); 944 connect(configApp, &QApplication::aboutToQuit, 945 this, &ConfigInfoView::saveSettings); 946 } 947 948 contextMenu = createStandardContextMenu(); 949 QAction *action = new QAction("Show Debug Info", contextMenu); 950 951 action->setCheckable(true); 952 connect(action, &QAction::toggled, 953 this, &ConfigInfoView::setShowDebug); 954 connect(this, &ConfigInfoView::showDebugChanged, 955 action, &QAction::setChecked); 956 action->setChecked(showDebug()); 957 contextMenu->addSeparator(); 958 contextMenu->addAction(action); 959 } 960 961 void ConfigInfoView::saveSettings(void) 962 { 963 if (!objectName().isEmpty()) { 964 configSettings->beginGroup(objectName()); 965 configSettings->setValue("/showDebug", showDebug()); 966 configSettings->endGroup(); 967 } 968 } 969 970 void ConfigInfoView::setShowDebug(bool b) 971 { 972 if (_showDebug != b) { 973 _showDebug = b; 974 if (_menu) 975 menuInfo(); 976 else if (sym) 977 symbolInfo(); 978 emit showDebugChanged(b); 979 } 980 } 981 982 void ConfigInfoView::setInfo(struct menu *m) 983 { 984 if (_menu == m) 985 return; 986 _menu = m; 987 sym = NULL; 988 if (!_menu) 989 clear(); 990 else 991 menuInfo(); 992 } 993 994 void ConfigInfoView::symbolInfo(void) 995 { 996 QString str; 997 998 str += "<big>Symbol: <b>"; 999 str += print_filter(sym->name); 1000 str += "</b></big><br><br>value: "; 1001 str += print_filter(sym_get_string_value(sym)); 1002 str += "<br>visibility: "; 1003 str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n"; 1004 str += "<br>"; 1005 str += debug_info(sym); 1006 1007 setText(str); 1008 } 1009 1010 void ConfigInfoView::menuInfo(void) 1011 { 1012 struct symbol* sym; 1013 QString info; 1014 QTextStream stream(&info); 1015 1016 sym = _menu->sym; 1017 if (sym) { 1018 if (_menu->prompt) { 1019 stream << "<big><b>"; 1020 stream << print_filter(_menu->prompt->text); 1021 stream << "</b></big>"; 1022 if (sym->name) { 1023 stream << " ("; 1024 if (showDebug()) 1025 stream << "<a href=\"s" << sym->name << "\">"; 1026 stream << print_filter(sym->name); 1027 if (showDebug()) 1028 stream << "</a>"; 1029 stream << ")"; 1030 } 1031 } else if (sym->name) { 1032 stream << "<big><b>"; 1033 if (showDebug()) 1034 stream << "<a href=\"s" << sym->name << "\">"; 1035 stream << print_filter(sym->name); 1036 if (showDebug()) 1037 stream << "</a>"; 1038 stream << "</b></big>"; 1039 } 1040 stream << "<br><br>"; 1041 1042 if (showDebug()) 1043 stream << debug_info(sym); 1044 1045 struct gstr help_gstr = str_new(); 1046 1047 menu_get_ext_help(_menu, &help_gstr); 1048 stream << print_filter(str_get(&help_gstr)); 1049 str_free(&help_gstr); 1050 } else if (_menu->prompt) { 1051 stream << "<big><b>"; 1052 stream << print_filter(_menu->prompt->text); 1053 stream << "</b></big><br><br>"; 1054 if (showDebug()) { 1055 if (_menu->prompt->visible.expr) { 1056 stream << " dep: "; 1057 expr_print(_menu->prompt->visible.expr, 1058 expr_print_help, &stream, E_NONE); 1059 stream << "<br><br>"; 1060 } 1061 1062 stream << "defined at " << _menu->filename << ":" 1063 << _menu->lineno << "<br><br>"; 1064 } 1065 } 1066 1067 setText(info); 1068 } 1069 1070 QString ConfigInfoView::debug_info(struct symbol *sym) 1071 { 1072 QString debug; 1073 QTextStream stream(&debug); 1074 1075 stream << "type: "; 1076 stream << print_filter(sym_type_name(sym->type)); 1077 if (sym_is_choice(sym)) 1078 stream << " (choice)"; 1079 debug += "<br>"; 1080 if (sym->rev_dep.expr) { 1081 stream << "reverse dep: "; 1082 expr_print(sym->rev_dep.expr, expr_print_help, &stream, E_NONE); 1083 stream << "<br>"; 1084 } 1085 for (struct property *prop = sym->prop; prop; prop = prop->next) { 1086 switch (prop->type) { 1087 case P_PROMPT: 1088 case P_MENU: 1089 stream << "prompt: <a href=\"m" << sym->name << "\">"; 1090 stream << print_filter(prop->text); 1091 stream << "</a><br>"; 1092 break; 1093 case P_DEFAULT: 1094 case P_SELECT: 1095 case P_RANGE: 1096 case P_COMMENT: 1097 case P_IMPLY: 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 << " 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, "<"); 1129 i += 4; 1130 break; 1131 case '>': 1132 res.replace(i, 1, ">"); 1133 i += 4; 1134 break; 1135 case '&': 1136 res.replace(i, 1, "&"); 1137 i += 5; 1138 break; 1139 case '"': 1140 res.replace(i, 1, """); 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