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