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