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