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) && type == S_BOOLEAN) 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 << " 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->file->name << ":" 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 case P_CHOICE: 1105 if (sym_is_choice(sym)) { 1106 stream << "choice: "; 1107 expr_print(prop->expr, expr_print_help, 1108 &stream, E_NONE); 1109 stream << "<br>"; 1110 } 1111 break; 1112 default: 1113 stream << "unknown property: "; 1114 stream << prop_get_type_name(prop->type); 1115 stream << "<br>"; 1116 } 1117 if (prop->visible.expr) { 1118 stream << " dep: "; 1119 expr_print(prop->visible.expr, expr_print_help, 1120 &stream, E_NONE); 1121 stream << "<br>"; 1122 } 1123 } 1124 stream << "<br>"; 1125 1126 return debug; 1127 } 1128 1129 QString ConfigInfoView::print_filter(const QString &str) 1130 { 1131 QRegularExpression re("[<>&\"\\n]"); 1132 QString res = str; 1133 for (int i = 0; (i = res.indexOf(re, i)) >= 0;) { 1134 switch (res[i].toLatin1()) { 1135 case '<': 1136 res.replace(i, 1, "<"); 1137 i += 4; 1138 break; 1139 case '>': 1140 res.replace(i, 1, ">"); 1141 i += 4; 1142 break; 1143 case '&': 1144 res.replace(i, 1, "&"); 1145 i += 5; 1146 break; 1147 case '"': 1148 res.replace(i, 1, """); 1149 i += 6; 1150 break; 1151 case '\n': 1152 res.replace(i, 1, "<br>"); 1153 i += 4; 1154 break; 1155 } 1156 } 1157 return res; 1158 } 1159 1160 void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str) 1161 { 1162 QTextStream *stream = reinterpret_cast<QTextStream *>(data); 1163 1164 if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) { 1165 *stream << "<a href=\"s" << sym->name << "\">"; 1166 *stream << print_filter(str); 1167 *stream << "</a>"; 1168 } else { 1169 *stream << print_filter(str); 1170 } 1171 } 1172 1173 void ConfigInfoView::clicked(const QUrl &url) 1174 { 1175 QByteArray str = url.toEncoded(); 1176 const std::size_t count = str.size(); 1177 char *data = new char[count + 2]; // '$' + '\0' 1178 struct symbol **result; 1179 struct menu *m = NULL; 1180 1181 if (count < 1) { 1182 delete[] data; 1183 return; 1184 } 1185 1186 memcpy(data, str.constData(), count); 1187 data[count] = '\0'; 1188 1189 /* Seek for exact match */ 1190 data[0] = '^'; 1191 strcat(data, "$"); 1192 result = sym_re_search(data); 1193 if (!result) { 1194 delete[] data; 1195 return; 1196 } 1197 1198 sym = *result; 1199 1200 /* Seek for the menu which holds the symbol */ 1201 for (struct property *prop = sym->prop; prop; prop = prop->next) { 1202 if (prop->type != P_PROMPT && prop->type != P_MENU) 1203 continue; 1204 m = prop->menu; 1205 break; 1206 } 1207 1208 if (!m) { 1209 /* Symbol is not visible as a menu */ 1210 symbolInfo(); 1211 emit showDebugChanged(true); 1212 } else { 1213 emit menuSelected(m); 1214 } 1215 1216 free(result); 1217 delete[] data; 1218 } 1219 1220 void ConfigInfoView::contextMenuEvent(QContextMenuEvent *event) 1221 { 1222 contextMenu->popup(event->globalPos()); 1223 event->accept(); 1224 } 1225 1226 ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow *parent) 1227 : Parent(parent), result(NULL) 1228 { 1229 setObjectName("search"); 1230 setWindowTitle("Search Config"); 1231 1232 QVBoxLayout* layout1 = new QVBoxLayout(this); 1233 layout1->setContentsMargins(11, 11, 11, 11); 1234 layout1->setSpacing(6); 1235 1236 QHBoxLayout* layout2 = new QHBoxLayout(); 1237 layout2->setContentsMargins(0, 0, 0, 0); 1238 layout2->setSpacing(6); 1239 layout2->addWidget(new QLabel("Find:", this)); 1240 editField = new QLineEdit(this); 1241 connect(editField, &QLineEdit::returnPressed, 1242 this, &ConfigSearchWindow::search); 1243 layout2->addWidget(editField); 1244 searchButton = new QPushButton("Search", this); 1245 searchButton->setAutoDefault(false); 1246 connect(searchButton, &QPushButton::clicked, 1247 this, &ConfigSearchWindow::search); 1248 layout2->addWidget(searchButton); 1249 layout1->addLayout(layout2); 1250 1251 split = new QSplitter(this); 1252 split->setOrientation(Qt::Vertical); 1253 list = new ConfigList(split, "search"); 1254 list->mode = listMode; 1255 info = new ConfigInfoView(split, "search"); 1256 connect(list, &ConfigList::menuChanged, 1257 info, &ConfigInfoView::setInfo); 1258 connect(list, &ConfigList::menuChanged, 1259 parent, &ConfigMainWindow::setMenuLink); 1260 1261 layout1->addWidget(split); 1262 1263 QVariant x, y; 1264 int width, height; 1265 bool ok; 1266 1267 configSettings->beginGroup("search"); 1268 width = configSettings->value("/window width", parent->width() / 2).toInt(); 1269 height = configSettings->value("/window height", parent->height() / 2).toInt(); 1270 resize(width, height); 1271 x = configSettings->value("/window x"); 1272 y = configSettings->value("/window y"); 1273 if (x.isValid() && y.isValid()) 1274 move(x.toInt(), y.toInt()); 1275 QList<int> sizes = configSettings->readSizes("/split", &ok); 1276 if (ok) 1277 split->setSizes(sizes); 1278 configSettings->endGroup(); 1279 connect(configApp, &QApplication::aboutToQuit, 1280 this, &ConfigSearchWindow::saveSettings); 1281 } 1282 1283 void ConfigSearchWindow::saveSettings(void) 1284 { 1285 if (!objectName().isEmpty()) { 1286 configSettings->beginGroup(objectName()); 1287 configSettings->setValue("/window x", pos().x()); 1288 configSettings->setValue("/window y", pos().y()); 1289 configSettings->setValue("/window width", size().width()); 1290 configSettings->setValue("/window height", size().height()); 1291 configSettings->writeSizes("/split", split->sizes()); 1292 configSettings->endGroup(); 1293 } 1294 } 1295 1296 void ConfigSearchWindow::search(void) 1297 { 1298 struct symbol **p; 1299 struct property *prop; 1300 ConfigItem *lastItem = NULL; 1301 1302 free(result); 1303 list->clear(); 1304 info->clear(); 1305 1306 result = sym_re_search(editField->text().toLatin1()); 1307 if (!result) 1308 return; 1309 for (p = result; *p; p++) { 1310 for_all_prompts((*p), prop) 1311 lastItem = new ConfigItem(list, lastItem, prop->menu, 1312 menu_is_visible(prop->menu)); 1313 } 1314 } 1315 1316 /* 1317 * Construct the complete config widget 1318 */ 1319 ConfigMainWindow::ConfigMainWindow(void) 1320 : searchWindow(0) 1321 { 1322 bool ok = true; 1323 QVariant x, y; 1324 int width, height; 1325 char title[256]; 1326 1327 snprintf(title, sizeof(title), "%s%s", 1328 rootmenu.prompt->text, 1329 "" 1330 ); 1331 setWindowTitle(title); 1332 1333 QRect g = configApp->primaryScreen()->geometry(); 1334 width = configSettings->value("/window width", g.width() - 64).toInt(); 1335 height = configSettings->value("/window height", g.height() - 64).toInt(); 1336 resize(width, height); 1337 x = configSettings->value("/window x"); 1338 y = configSettings->value("/window y"); 1339 if ((x.isValid())&&(y.isValid())) 1340 move(x.toInt(), y.toInt()); 1341 1342 // set up icons 1343 ConfigItem::symbolYesIcon = QIcon(QPixmap(xpm_symbol_yes)); 1344 ConfigItem::symbolModIcon = QIcon(QPixmap(xpm_symbol_mod)); 1345 ConfigItem::symbolNoIcon = QIcon(QPixmap(xpm_symbol_no)); 1346 ConfigItem::choiceYesIcon = QIcon(QPixmap(xpm_choice_yes)); 1347 ConfigItem::choiceNoIcon = QIcon(QPixmap(xpm_choice_no)); 1348 ConfigItem::menuIcon = QIcon(QPixmap(xpm_menu)); 1349 ConfigItem::menubackIcon = QIcon(QPixmap(xpm_menuback)); 1350 1351 QWidget *widget = new QWidget(this); 1352 QVBoxLayout *layout = new QVBoxLayout(widget); 1353 setCentralWidget(widget); 1354 1355 split1 = new QSplitter(widget); 1356 split1->setOrientation(Qt::Horizontal); 1357 split1->setChildrenCollapsible(false); 1358 1359 menuList = new ConfigList(widget, "menu"); 1360 1361 split2 = new QSplitter(widget); 1362 split2->setChildrenCollapsible(false); 1363 split2->setOrientation(Qt::Vertical); 1364 1365 // create config tree 1366 configList = new ConfigList(widget, "config"); 1367 1368 helpText = new ConfigInfoView(widget, "help"); 1369 1370 layout->addWidget(split2); 1371 split2->addWidget(split1); 1372 split1->addWidget(configList); 1373 split1->addWidget(menuList); 1374 split2->addWidget(helpText); 1375 1376 setTabOrder(configList, helpText); 1377 configList->setFocus(); 1378 1379 backAction = new QAction(QPixmap(xpm_back), "Back", this); 1380 connect(backAction, &QAction::triggered, 1381 this, &ConfigMainWindow::goBack); 1382 1383 QAction *quitAction = new QAction("&Quit", this); 1384 quitAction->setShortcut(Qt::CTRL | Qt::Key_Q); 1385 connect(quitAction, &QAction::triggered, 1386 this, &ConfigMainWindow::close); 1387 1388 QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this); 1389 loadAction->setShortcut(Qt::CTRL | Qt::Key_L); 1390 connect(loadAction, &QAction::triggered, 1391 this, &ConfigMainWindow::loadConfig); 1392 1393 saveAction = new QAction(QPixmap(xpm_save), "&Save", this); 1394 saveAction->setShortcut(Qt::CTRL | Qt::Key_S); 1395 connect(saveAction, &QAction::triggered, 1396 this, &ConfigMainWindow::saveConfig); 1397 1398 conf_set_changed_callback(conf_changed); 1399 1400 // Set saveAction's initial state 1401 conf_changed(); 1402 configname = xstrdup(conf_get_configname()); 1403 1404 QAction *saveAsAction = new QAction("Save &As...", this); 1405 connect(saveAsAction, &QAction::triggered, 1406 this, &ConfigMainWindow::saveConfigAs); 1407 QAction *searchAction = new QAction("&Find", this); 1408 searchAction->setShortcut(Qt::CTRL | Qt::Key_F); 1409 connect(searchAction, &QAction::triggered, 1410 this, &ConfigMainWindow::searchConfig); 1411 singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this); 1412 singleViewAction->setCheckable(true); 1413 connect(singleViewAction, &QAction::triggered, 1414 this, &ConfigMainWindow::showSingleView); 1415 splitViewAction = new QAction(QPixmap(xpm_split_view), "Split View", this); 1416 splitViewAction->setCheckable(true); 1417 connect(splitViewAction, &QAction::triggered, 1418 this, &ConfigMainWindow::showSplitView); 1419 fullViewAction = new QAction(QPixmap(xpm_tree_view), "Full View", this); 1420 fullViewAction->setCheckable(true); 1421 connect(fullViewAction, &QAction::triggered, 1422 this, &ConfigMainWindow::showFullView); 1423 1424 QAction *showNameAction = new QAction("Show Name", this); 1425 showNameAction->setCheckable(true); 1426 connect(showNameAction, &QAction::toggled, 1427 configList, &ConfigList::setShowName); 1428 showNameAction->setChecked(configList->showName); 1429 1430 QActionGroup *optGroup = new QActionGroup(this); 1431 optGroup->setExclusive(true); 1432 connect(optGroup, &QActionGroup::triggered, 1433 configList, &ConfigList::setOptionMode); 1434 connect(optGroup, &QActionGroup::triggered, 1435 menuList, &ConfigList::setOptionMode); 1436 1437 ConfigList::showNormalAction = new QAction("Show Normal Options", optGroup); 1438 ConfigList::showNormalAction->setCheckable(true); 1439 ConfigList::showAllAction = new QAction("Show All Options", optGroup); 1440 ConfigList::showAllAction->setCheckable(true); 1441 ConfigList::showPromptAction = new QAction("Show Prompt Options", optGroup); 1442 ConfigList::showPromptAction->setCheckable(true); 1443 1444 QAction *showDebugAction = new QAction("Show Debug Info", this); 1445 showDebugAction->setCheckable(true); 1446 connect(showDebugAction, &QAction::toggled, 1447 helpText, &ConfigInfoView::setShowDebug); 1448 showDebugAction->setChecked(helpText->showDebug()); 1449 1450 QAction *showIntroAction = new QAction("Introduction", this); 1451 connect(showIntroAction, &QAction::triggered, 1452 this, &ConfigMainWindow::showIntro); 1453 QAction *showAboutAction = new QAction("About", this); 1454 connect(showAboutAction, &QAction::triggered, 1455 this, &ConfigMainWindow::showAbout); 1456 1457 // init tool bar 1458 QToolBar *toolBar = addToolBar("Tools"); 1459 toolBar->addAction(backAction); 1460 toolBar->addSeparator(); 1461 toolBar->addAction(loadAction); 1462 toolBar->addAction(saveAction); 1463 toolBar->addSeparator(); 1464 toolBar->addAction(singleViewAction); 1465 toolBar->addAction(splitViewAction); 1466 toolBar->addAction(fullViewAction); 1467 1468 // create file menu 1469 QMenu *menu = menuBar()->addMenu("&File"); 1470 menu->addAction(loadAction); 1471 menu->addAction(saveAction); 1472 menu->addAction(saveAsAction); 1473 menu->addSeparator(); 1474 menu->addAction(quitAction); 1475 1476 // create edit menu 1477 menu = menuBar()->addMenu("&Edit"); 1478 menu->addAction(searchAction); 1479 1480 // create options menu 1481 menu = menuBar()->addMenu("&Option"); 1482 menu->addAction(showNameAction); 1483 menu->addSeparator(); 1484 menu->addActions(optGroup->actions()); 1485 menu->addSeparator(); 1486 menu->addAction(showDebugAction); 1487 1488 // create help menu 1489 menu = menuBar()->addMenu("&Help"); 1490 menu->addAction(showIntroAction); 1491 menu->addAction(showAboutAction); 1492 1493 connect(helpText, &ConfigInfoView::anchorClicked, 1494 helpText, &ConfigInfoView::clicked); 1495 1496 connect(configList, &ConfigList::menuChanged, 1497 helpText, &ConfigInfoView::setInfo); 1498 connect(configList, &ConfigList::menuSelected, 1499 this, &ConfigMainWindow::changeMenu); 1500 connect(configList, &ConfigList::itemSelected, 1501 this, &ConfigMainWindow::changeItens); 1502 connect(configList, &ConfigList::parentSelected, 1503 this, &ConfigMainWindow::goBack); 1504 connect(menuList, &ConfigList::menuChanged, 1505 helpText, &ConfigInfoView::setInfo); 1506 connect(menuList, &ConfigList::menuSelected, 1507 this, &ConfigMainWindow::changeMenu); 1508 1509 connect(configList, &ConfigList::gotFocus, 1510 helpText, &ConfigInfoView::setInfo); 1511 connect(menuList, &ConfigList::gotFocus, 1512 helpText, &ConfigInfoView::setInfo); 1513 connect(menuList, &ConfigList::gotFocus, 1514 this, &ConfigMainWindow::listFocusChanged); 1515 connect(helpText, &ConfigInfoView::menuSelected, 1516 this, &ConfigMainWindow::setMenuLink); 1517 1518 QString listMode = configSettings->value("/listMode", "symbol").toString(); 1519 if (listMode == "single") 1520 showSingleView(); 1521 else if (listMode == "full") 1522 showFullView(); 1523 else /*if (listMode == "split")*/ 1524 showSplitView(); 1525 1526 // UI setup done, restore splitter positions 1527 QList<int> sizes = configSettings->readSizes("/split1", &ok); 1528 if (ok) 1529 split1->setSizes(sizes); 1530 1531 sizes = configSettings->readSizes("/split2", &ok); 1532 if (ok) 1533 split2->setSizes(sizes); 1534 } 1535 1536 void ConfigMainWindow::loadConfig(void) 1537 { 1538 QString str; 1539 QByteArray ba; 1540 const char *name; 1541 1542 str = QFileDialog::getOpenFileName(this, "", configname); 1543 if (str.isNull()) 1544 return; 1545 1546 ba = str.toLocal8Bit(); 1547 name = ba.data(); 1548 1549 if (conf_read(name)) 1550 QMessageBox::information(this, "qconf", "Unable to load configuration!"); 1551 1552 free(configname); 1553 configname = xstrdup(name); 1554 1555 ConfigList::updateListAllForAll(); 1556 } 1557 1558 bool ConfigMainWindow::saveConfig(void) 1559 { 1560 if (conf_write(configname)) { 1561 QMessageBox::information(this, "qconf", "Unable to save configuration!"); 1562 return false; 1563 } 1564 conf_write_autoconf(0); 1565 1566 return true; 1567 } 1568 1569 void ConfigMainWindow::saveConfigAs(void) 1570 { 1571 QString str; 1572 QByteArray ba; 1573 const char *name; 1574 1575 str = QFileDialog::getSaveFileName(this, "", configname); 1576 if (str.isNull()) 1577 return; 1578 1579 ba = str.toLocal8Bit(); 1580 name = ba.data(); 1581 1582 if (conf_write(name)) { 1583 QMessageBox::information(this, "qconf", "Unable to save configuration!"); 1584 } 1585 conf_write_autoconf(0); 1586 1587 free(configname); 1588 configname = xstrdup(name); 1589 } 1590 1591 void ConfigMainWindow::searchConfig(void) 1592 { 1593 if (!searchWindow) 1594 searchWindow = new ConfigSearchWindow(this); 1595 searchWindow->show(); 1596 } 1597 1598 void ConfigMainWindow::changeItens(struct menu *menu) 1599 { 1600 configList->setRootMenu(menu); 1601 } 1602 1603 void ConfigMainWindow::changeMenu(struct menu *menu) 1604 { 1605 menuList->setRootMenu(menu); 1606 } 1607 1608 void ConfigMainWindow::setMenuLink(struct menu *menu) 1609 { 1610 struct menu *parent; 1611 ConfigList* list = NULL; 1612 ConfigItem* item; 1613 1614 if (configList->menuSkip(menu)) 1615 return; 1616 1617 switch (configList->mode) { 1618 case singleMode: 1619 list = configList; 1620 parent = menu_get_parent_menu(menu); 1621 if (!parent) 1622 return; 1623 list->setRootMenu(parent); 1624 break; 1625 case menuMode: 1626 if (menu->flags & MENU_ROOT) { 1627 menuList->setRootMenu(menu); 1628 configList->clearSelection(); 1629 list = configList; 1630 } else { 1631 parent = menu_get_parent_menu(menu->parent); 1632 if (!parent) 1633 return; 1634 1635 /* Select the config view */ 1636 item = configList->findConfigItem(parent); 1637 if (item) { 1638 configList->setSelected(item, true); 1639 configList->scrollToItem(item); 1640 } 1641 1642 menuList->setRootMenu(parent); 1643 menuList->clearSelection(); 1644 list = menuList; 1645 } 1646 break; 1647 case fullMode: 1648 list = configList; 1649 break; 1650 default: 1651 break; 1652 } 1653 1654 if (list) { 1655 item = list->findConfigItem(menu); 1656 if (item) { 1657 list->setSelected(item, true); 1658 list->scrollToItem(item); 1659 list->setFocus(); 1660 helpText->setInfo(menu); 1661 } 1662 } 1663 } 1664 1665 void ConfigMainWindow::listFocusChanged(void) 1666 { 1667 if (menuList->mode == menuMode) 1668 configList->clearSelection(); 1669 } 1670 1671 void ConfigMainWindow::goBack(void) 1672 { 1673 if (configList->rootEntry == &rootmenu) 1674 return; 1675 1676 configList->setParentMenu(); 1677 } 1678 1679 void ConfigMainWindow::showSingleView(void) 1680 { 1681 singleViewAction->setEnabled(false); 1682 singleViewAction->setChecked(true); 1683 splitViewAction->setEnabled(true); 1684 splitViewAction->setChecked(false); 1685 fullViewAction->setEnabled(true); 1686 fullViewAction->setChecked(false); 1687 1688 backAction->setEnabled(true); 1689 1690 menuList->hide(); 1691 menuList->setRootMenu(0); 1692 configList->mode = singleMode; 1693 if (configList->rootEntry == &rootmenu) 1694 configList->updateListAll(); 1695 else 1696 configList->setRootMenu(&rootmenu); 1697 configList->setFocus(); 1698 } 1699 1700 void ConfigMainWindow::showSplitView(void) 1701 { 1702 singleViewAction->setEnabled(true); 1703 singleViewAction->setChecked(false); 1704 splitViewAction->setEnabled(false); 1705 splitViewAction->setChecked(true); 1706 fullViewAction->setEnabled(true); 1707 fullViewAction->setChecked(false); 1708 1709 backAction->setEnabled(false); 1710 1711 configList->mode = menuMode; 1712 if (configList->rootEntry == &rootmenu) 1713 configList->updateListAll(); 1714 else 1715 configList->setRootMenu(&rootmenu); 1716 configList->setAllOpen(true); 1717 configApp->processEvents(); 1718 menuList->mode = symbolMode; 1719 menuList->setRootMenu(&rootmenu); 1720 menuList->setAllOpen(true); 1721 menuList->show(); 1722 menuList->setFocus(); 1723 } 1724 1725 void ConfigMainWindow::showFullView(void) 1726 { 1727 singleViewAction->setEnabled(true); 1728 singleViewAction->setChecked(false); 1729 splitViewAction->setEnabled(true); 1730 splitViewAction->setChecked(false); 1731 fullViewAction->setEnabled(false); 1732 fullViewAction->setChecked(true); 1733 1734 backAction->setEnabled(false); 1735 1736 menuList->hide(); 1737 menuList->setRootMenu(0); 1738 configList->mode = fullMode; 1739 if (configList->rootEntry == &rootmenu) 1740 configList->updateListAll(); 1741 else 1742 configList->setRootMenu(&rootmenu); 1743 configList->setFocus(); 1744 } 1745 1746 /* 1747 * ask for saving configuration before quitting 1748 */ 1749 void ConfigMainWindow::closeEvent(QCloseEvent* e) 1750 { 1751 if (!conf_get_changed()) { 1752 e->accept(); 1753 return; 1754 } 1755 1756 QMessageBox mb(QMessageBox::Icon::Warning, "qconf", 1757 "Save configuration?"); 1758 1759 QPushButton *yb = mb.addButton(QMessageBox::Yes); 1760 QPushButton *db = mb.addButton(QMessageBox::No); 1761 QPushButton *cb = mb.addButton(QMessageBox::Cancel); 1762 1763 yb->setText("&Save Changes"); 1764 db->setText("&Discard Changes"); 1765 cb->setText("Cancel Exit"); 1766 1767 mb.setDefaultButton(yb); 1768 mb.setEscapeButton(cb); 1769 1770 switch (mb.exec()) { 1771 case QMessageBox::Yes: 1772 if (saveConfig()) 1773 e->accept(); 1774 else 1775 e->ignore(); 1776 break; 1777 case QMessageBox::No: 1778 e->accept(); 1779 break; 1780 case QMessageBox::Cancel: 1781 e->ignore(); 1782 break; 1783 } 1784 } 1785 1786 void ConfigMainWindow::showIntro(void) 1787 { 1788 static const QString str = 1789 "Welcome to the qconf graphical configuration tool.\n" 1790 "\n" 1791 "For bool and tristate options, a blank box indicates the " 1792 "feature is disabled, a check indicates it is enabled, and a " 1793 "dot indicates that it is to be compiled as a module. Clicking " 1794 "on the box will cycle through the three states. For int, hex, " 1795 "and string options, double-clicking or pressing F2 on the " 1796 "Value cell will allow you to edit the value.\n" 1797 "\n" 1798 "If you do not see an option (e.g., a device driver) that you " 1799 "believe should be present, try turning on Show All Options " 1800 "under the Options menu. Enabling Show Debug Info will help you" 1801 "figure out what other options must be enabled to support the " 1802 "option you are interested in, and hyperlinks will navigate to " 1803 "them.\n" 1804 "\n" 1805 "Toggling Show Debug Info under the Options menu will show the " 1806 "dependencies, which you can then match by examining other " 1807 "options.\n"; 1808 1809 QMessageBox::information(this, "qconf", str); 1810 } 1811 1812 void ConfigMainWindow::showAbout(void) 1813 { 1814 static const QString str = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n" 1815 "Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>.\n" 1816 "\n" 1817 "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n" 1818 "\n" 1819 "Qt Version: "; 1820 1821 QMessageBox::information(this, "qconf", str + qVersion()); 1822 } 1823 1824 void ConfigMainWindow::saveSettings(void) 1825 { 1826 configSettings->setValue("/window x", pos().x()); 1827 configSettings->setValue("/window y", pos().y()); 1828 configSettings->setValue("/window width", size().width()); 1829 configSettings->setValue("/window height", size().height()); 1830 1831 QString entry; 1832 switch(configList->mode) { 1833 case singleMode : 1834 entry = "single"; 1835 break; 1836 1837 case symbolMode : 1838 entry = "split"; 1839 break; 1840 1841 case fullMode : 1842 entry = "full"; 1843 break; 1844 1845 default: 1846 break; 1847 } 1848 configSettings->setValue("/listMode", entry); 1849 1850 configSettings->writeSizes("/split1", split1->sizes()); 1851 configSettings->writeSizes("/split2", split2->sizes()); 1852 } 1853 1854 void ConfigMainWindow::conf_changed(void) 1855 { 1856 if (saveAction) 1857 saveAction->setEnabled(conf_get_changed()); 1858 } 1859 1860 void fixup_rootmenu(struct menu *menu) 1861 { 1862 struct menu *child; 1863 static int menu_cnt = 0; 1864 1865 menu->flags |= MENU_ROOT; 1866 for (child = menu->list; child; child = child->next) { 1867 if (child->prompt && child->prompt->type == P_MENU) { 1868 menu_cnt++; 1869 fixup_rootmenu(child); 1870 menu_cnt--; 1871 } else if (!menu_cnt) 1872 fixup_rootmenu(child); 1873 } 1874 } 1875 1876 static const char *progname; 1877 1878 static void usage(void) 1879 { 1880 printf("%s [-s] <config>\n", progname); 1881 exit(0); 1882 } 1883 1884 int main(int ac, char** av) 1885 { 1886 ConfigMainWindow* v; 1887 const char *name; 1888 1889 progname = av[0]; 1890 if (ac > 1 && av[1][0] == '-') { 1891 switch (av[1][1]) { 1892 case 's': 1893 conf_set_message_callback(NULL); 1894 break; 1895 case 'h': 1896 case '?': 1897 usage(); 1898 } 1899 name = av[2]; 1900 } else 1901 name = av[1]; 1902 if (!name) 1903 usage(); 1904 1905 conf_parse(name); 1906 fixup_rootmenu(&rootmenu); 1907 conf_read(NULL); 1908 //zconfdump(stdout); 1909 1910 configApp = new QApplication(ac, av); 1911 1912 configSettings = new ConfigSettings(); 1913 configSettings->beginGroup("/kconfig/qconf"); 1914 v = new ConfigMainWindow(); 1915 1916 //zconfdump(stdout); 1917 configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit())); 1918 configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings())); 1919 v->show(); 1920 configApp->exec(); 1921 1922 configSettings->endGroup(); 1923 delete configSettings; 1924 delete v; 1925 delete configApp; 1926 1927 return 0; 1928 } 1929