1 /* 2 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> 3 * Released under the terms of the GNU GPL v2.0. 4 */ 5 6 #include <qapplication.h> 7 #include <qmainwindow.h> 8 #include <qtoolbar.h> 9 #include <qvbox.h> 10 #include <qsplitter.h> 11 #include <qlistview.h> 12 #include <qtextview.h> 13 #include <qlineedit.h> 14 #include <qmenubar.h> 15 #include <qmessagebox.h> 16 #include <qaction.h> 17 #include <qheader.h> 18 #include <qfiledialog.h> 19 #include <qregexp.h> 20 21 #include <stdlib.h> 22 23 #include "lkc.h" 24 #include "qconf.h" 25 26 #include "qconf.moc" 27 #include "images.c" 28 29 #ifdef _ 30 # undef _ 31 # define _ qgettext 32 #endif 33 34 static QApplication *configApp; 35 36 static inline QString qgettext(const char* str) 37 { 38 return QString::fromLocal8Bit(gettext(str)); 39 } 40 41 static inline QString qgettext(const QString& str) 42 { 43 return QString::fromLocal8Bit(gettext(str.latin1())); 44 } 45 46 ConfigSettings::ConfigSettings() 47 : showAll(false), showName(false), showRange(false), showData(false) 48 { 49 } 50 51 #if QT_VERSION >= 300 52 /** 53 * Reads the list column settings from the application settings. 54 */ 55 void ConfigSettings::readListSettings() 56 { 57 showAll = readBoolEntry("/kconfig/qconf/showAll", false); 58 showName = readBoolEntry("/kconfig/qconf/showName", false); 59 showRange = readBoolEntry("/kconfig/qconf/showRange", false); 60 showData = readBoolEntry("/kconfig/qconf/showData", false); 61 } 62 63 /** 64 * Reads a list of integer values from the application settings. 65 */ 66 QValueList<int> ConfigSettings::readSizes(const QString& key, bool *ok) 67 { 68 QValueList<int> result; 69 QStringList entryList = readListEntry(key, ok); 70 if (ok) { 71 QStringList::Iterator it; 72 for (it = entryList.begin(); it != entryList.end(); ++it) 73 result.push_back((*it).toInt()); 74 } 75 76 return result; 77 } 78 79 /** 80 * Writes a list of integer values to the application settings. 81 */ 82 bool ConfigSettings::writeSizes(const QString& key, const QValueList<int>& value) 83 { 84 QStringList stringList; 85 QValueList<int>::ConstIterator it; 86 87 for (it = value.begin(); it != value.end(); ++it) 88 stringList.push_back(QString::number(*it)); 89 return writeEntry(key, stringList); 90 } 91 #endif 92 93 94 /* 95 * update all the children of a menu entry 96 * removes/adds the entries from the parent widget as necessary 97 * 98 * parent: either the menu list widget or a menu entry widget 99 * menu: entry to be updated 100 */ 101 template <class P> 102 void ConfigList::updateMenuList(P* parent, struct menu* menu) 103 { 104 struct menu* child; 105 ConfigItem* item; 106 ConfigItem* last; 107 bool visible; 108 enum prop_type type; 109 110 if (!menu) { 111 while ((item = parent->firstChild())) 112 delete item; 113 return; 114 } 115 116 last = parent->firstChild(); 117 if (last && !last->goParent) 118 last = 0; 119 for (child = menu->list; child; child = child->next) { 120 item = last ? last->nextSibling() : parent->firstChild(); 121 type = child->prompt ? child->prompt->type : P_UNKNOWN; 122 123 switch (mode) { 124 case menuMode: 125 if (!(child->flags & MENU_ROOT)) 126 goto hide; 127 break; 128 case symbolMode: 129 if (child->flags & MENU_ROOT) 130 goto hide; 131 break; 132 default: 133 break; 134 } 135 136 visible = menu_is_visible(child); 137 if (showAll || visible) { 138 if (!item || item->menu != child) 139 item = new ConfigItem(parent, last, child, visible); 140 else 141 item->testUpdateMenu(visible); 142 143 if (mode == fullMode || mode == menuMode || type != P_MENU) 144 updateMenuList(item, child); 145 else 146 updateMenuList(item, 0); 147 last = item; 148 continue; 149 } 150 hide: 151 if (item && item->menu == child) { 152 last = parent->firstChild(); 153 if (last == item) 154 last = 0; 155 else while (last->nextSibling() != item) 156 last = last->nextSibling(); 157 delete item; 158 } 159 } 160 } 161 162 #if QT_VERSION >= 300 163 /* 164 * set the new data 165 * TODO check the value 166 */ 167 void ConfigItem::okRename(int col) 168 { 169 Parent::okRename(col); 170 sym_set_string_value(menu->sym, text(dataColIdx).latin1()); 171 } 172 #endif 173 174 /* 175 * update the displayed of a menu entry 176 */ 177 void ConfigItem::updateMenu(void) 178 { 179 ConfigList* list; 180 struct symbol* sym; 181 struct property *prop; 182 QString prompt; 183 int type; 184 tristate expr; 185 186 list = listView(); 187 if (goParent) { 188 setPixmap(promptColIdx, list->menuBackPix); 189 prompt = ".."; 190 goto set_prompt; 191 } 192 193 sym = menu->sym; 194 prop = menu->prompt; 195 prompt = QString::fromLocal8Bit(menu_get_prompt(menu)); 196 197 if (prop) switch (prop->type) { 198 case P_MENU: 199 if (list->mode == singleMode || list->mode == symbolMode) { 200 /* a menuconfig entry is displayed differently 201 * depending whether it's at the view root or a child. 202 */ 203 if (sym && list->rootEntry == menu) 204 break; 205 setPixmap(promptColIdx, list->menuPix); 206 } else { 207 if (sym) 208 break; 209 setPixmap(promptColIdx, 0); 210 } 211 goto set_prompt; 212 case P_COMMENT: 213 setPixmap(promptColIdx, 0); 214 goto set_prompt; 215 default: 216 ; 217 } 218 if (!sym) 219 goto set_prompt; 220 221 setText(nameColIdx, QString::fromLocal8Bit(sym->name)); 222 223 type = sym_get_type(sym); 224 switch (type) { 225 case S_BOOLEAN: 226 case S_TRISTATE: 227 char ch; 228 229 if (!sym_is_changable(sym) && !list->showAll) { 230 setPixmap(promptColIdx, 0); 231 setText(noColIdx, QString::null); 232 setText(modColIdx, QString::null); 233 setText(yesColIdx, QString::null); 234 break; 235 } 236 expr = sym_get_tristate_value(sym); 237 switch (expr) { 238 case yes: 239 if (sym_is_choice_value(sym) && type == S_BOOLEAN) 240 setPixmap(promptColIdx, list->choiceYesPix); 241 else 242 setPixmap(promptColIdx, list->symbolYesPix); 243 setText(yesColIdx, "Y"); 244 ch = 'Y'; 245 break; 246 case mod: 247 setPixmap(promptColIdx, list->symbolModPix); 248 setText(modColIdx, "M"); 249 ch = 'M'; 250 break; 251 default: 252 if (sym_is_choice_value(sym) && type == S_BOOLEAN) 253 setPixmap(promptColIdx, list->choiceNoPix); 254 else 255 setPixmap(promptColIdx, list->symbolNoPix); 256 setText(noColIdx, "N"); 257 ch = 'N'; 258 break; 259 } 260 if (expr != no) 261 setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0); 262 if (expr != mod) 263 setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0); 264 if (expr != yes) 265 setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0); 266 267 setText(dataColIdx, QChar(ch)); 268 break; 269 case S_INT: 270 case S_HEX: 271 case S_STRING: 272 const char* data; 273 274 data = sym_get_string_value(sym); 275 276 #if QT_VERSION >= 300 277 int i = list->mapIdx(dataColIdx); 278 if (i >= 0) 279 setRenameEnabled(i, TRUE); 280 #endif 281 setText(dataColIdx, data); 282 if (type == S_STRING) 283 prompt = QString("%1: %2").arg(prompt).arg(data); 284 else 285 prompt = QString("(%2) %1").arg(prompt).arg(data); 286 break; 287 } 288 if (!sym_has_value(sym) && visible) 289 prompt += " (NEW)"; 290 set_prompt: 291 setText(promptColIdx, prompt); 292 } 293 294 void ConfigItem::testUpdateMenu(bool v) 295 { 296 ConfigItem* i; 297 298 visible = v; 299 if (!menu) 300 return; 301 302 sym_calc_value(menu->sym); 303 if (menu->flags & MENU_CHANGED) { 304 /* the menu entry changed, so update all list items */ 305 menu->flags &= ~MENU_CHANGED; 306 for (i = (ConfigItem*)menu->data; i; i = i->nextItem) 307 i->updateMenu(); 308 } else if (listView()->updateAll) 309 updateMenu(); 310 } 311 312 void ConfigItem::paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align) 313 { 314 ConfigList* list = listView(); 315 316 if (visible) { 317 if (isSelected() && !list->hasFocus() && list->mode == menuMode) 318 Parent::paintCell(p, list->inactivedColorGroup, column, width, align); 319 else 320 Parent::paintCell(p, cg, column, width, align); 321 } else 322 Parent::paintCell(p, list->disabledColorGroup, column, width, align); 323 } 324 325 /* 326 * construct a menu entry 327 */ 328 void ConfigItem::init(void) 329 { 330 if (menu) { 331 ConfigList* list = listView(); 332 nextItem = (ConfigItem*)menu->data; 333 menu->data = this; 334 335 if (list->mode != fullMode) 336 setOpen(TRUE); 337 sym_calc_value(menu->sym); 338 } 339 updateMenu(); 340 } 341 342 /* 343 * destruct a menu entry 344 */ 345 ConfigItem::~ConfigItem(void) 346 { 347 if (menu) { 348 ConfigItem** ip = (ConfigItem**)&menu->data; 349 for (; *ip; ip = &(*ip)->nextItem) { 350 if (*ip == this) { 351 *ip = nextItem; 352 break; 353 } 354 } 355 } 356 } 357 358 void ConfigLineEdit::show(ConfigItem* i) 359 { 360 item = i; 361 if (sym_get_string_value(item->menu->sym)) 362 setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym))); 363 else 364 setText(QString::null); 365 Parent::show(); 366 setFocus(); 367 } 368 369 void ConfigLineEdit::keyPressEvent(QKeyEvent* e) 370 { 371 switch (e->key()) { 372 case Key_Escape: 373 break; 374 case Key_Return: 375 case Key_Enter: 376 sym_set_string_value(item->menu->sym, text().latin1()); 377 parent()->updateList(item); 378 break; 379 default: 380 Parent::keyPressEvent(e); 381 return; 382 } 383 e->accept(); 384 parent()->list->setFocus(); 385 hide(); 386 } 387 388 ConfigList::ConfigList(ConfigView* p, ConfigMainWindow* cv, ConfigSettings* configSettings) 389 : Parent(p), cview(cv), 390 updateAll(false), 391 symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no), 392 choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no), 393 menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void), 394 showAll(false), showName(false), showRange(false), showData(false), 395 rootEntry(0) 396 { 397 int i; 398 399 setSorting(-1); 400 setRootIsDecorated(TRUE); 401 disabledColorGroup = palette().active(); 402 disabledColorGroup.setColor(QColorGroup::Text, palette().disabled().text()); 403 inactivedColorGroup = palette().active(); 404 inactivedColorGroup.setColor(QColorGroup::Highlight, palette().disabled().highlight()); 405 406 connect(this, SIGNAL(selectionChanged(void)), 407 SLOT(updateSelection(void))); 408 409 if (configSettings) { 410 showAll = configSettings->showAll; 411 showName = configSettings->showName; 412 showRange = configSettings->showRange; 413 showData = configSettings->showData; 414 } 415 416 for (i = 0; i < colNr; i++) 417 colMap[i] = colRevMap[i] = -1; 418 addColumn(promptColIdx, "Option"); 419 420 reinit(); 421 } 422 423 void ConfigList::reinit(void) 424 { 425 removeColumn(dataColIdx); 426 removeColumn(yesColIdx); 427 removeColumn(modColIdx); 428 removeColumn(noColIdx); 429 removeColumn(nameColIdx); 430 431 if (showName) 432 addColumn(nameColIdx, "Name"); 433 if (showRange) { 434 addColumn(noColIdx, "N"); 435 addColumn(modColIdx, "M"); 436 addColumn(yesColIdx, "Y"); 437 } 438 if (showData) 439 addColumn(dataColIdx, "Value"); 440 441 updateListAll(); 442 } 443 444 void ConfigList::updateSelection(void) 445 { 446 struct menu *menu; 447 enum prop_type type; 448 449 ConfigItem* item = (ConfigItem*)selectedItem(); 450 if (!item) 451 return; 452 453 cview->setHelp(item); 454 455 menu = item->menu; 456 if (!menu) 457 return; 458 type = menu->prompt ? menu->prompt->type : P_UNKNOWN; 459 if (mode == menuMode && type == P_MENU) 460 emit menuSelected(menu); 461 } 462 463 void ConfigList::updateList(ConfigItem* item) 464 { 465 ConfigItem* last = 0; 466 467 if (!rootEntry) 468 goto update; 469 470 if (rootEntry != &rootmenu && (mode == singleMode || 471 (mode == symbolMode && rootEntry->parent != &rootmenu))) { 472 item = firstChild(); 473 if (!item) 474 item = new ConfigItem(this, 0, true); 475 last = item; 476 } 477 if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) && 478 rootEntry->sym && rootEntry->prompt) { 479 item = last ? last->nextSibling() : firstChild(); 480 if (!item) 481 item = new ConfigItem(this, last, rootEntry, true); 482 else 483 item->testUpdateMenu(true); 484 485 updateMenuList(item, rootEntry); 486 triggerUpdate(); 487 return; 488 } 489 update: 490 updateMenuList(this, rootEntry); 491 triggerUpdate(); 492 } 493 494 void ConfigList::setAllOpen(bool open) 495 { 496 QListViewItemIterator it(this); 497 498 for (; it.current(); it++) 499 it.current()->setOpen(open); 500 } 501 502 void ConfigList::setValue(ConfigItem* item, tristate val) 503 { 504 struct symbol* sym; 505 int type; 506 tristate oldval; 507 508 sym = item->menu ? item->menu->sym : 0; 509 if (!sym) 510 return; 511 512 type = sym_get_type(sym); 513 switch (type) { 514 case S_BOOLEAN: 515 case S_TRISTATE: 516 oldval = sym_get_tristate_value(sym); 517 518 if (!sym_set_tristate_value(sym, val)) 519 return; 520 if (oldval == no && item->menu->list) 521 item->setOpen(TRUE); 522 parent()->updateList(item); 523 break; 524 } 525 } 526 527 void ConfigList::changeValue(ConfigItem* item) 528 { 529 struct symbol* sym; 530 struct menu* menu; 531 int type, oldexpr, newexpr; 532 533 menu = item->menu; 534 if (!menu) 535 return; 536 sym = menu->sym; 537 if (!sym) { 538 if (item->menu->list) 539 item->setOpen(!item->isOpen()); 540 return; 541 } 542 543 type = sym_get_type(sym); 544 switch (type) { 545 case S_BOOLEAN: 546 case S_TRISTATE: 547 oldexpr = sym_get_tristate_value(sym); 548 newexpr = sym_toggle_tristate_value(sym); 549 if (item->menu->list) { 550 if (oldexpr == newexpr) 551 item->setOpen(!item->isOpen()); 552 else if (oldexpr == no) 553 item->setOpen(TRUE); 554 } 555 if (oldexpr != newexpr) 556 parent()->updateList(item); 557 break; 558 case S_INT: 559 case S_HEX: 560 case S_STRING: 561 #if QT_VERSION >= 300 562 if (colMap[dataColIdx] >= 0) 563 item->startRename(colMap[dataColIdx]); 564 else 565 #endif 566 parent()->lineEdit->show(item); 567 break; 568 } 569 } 570 571 void ConfigList::setRootMenu(struct menu *menu) 572 { 573 enum prop_type type; 574 575 if (rootEntry == menu) 576 return; 577 type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN; 578 if (type != P_MENU) 579 return; 580 updateMenuList(this, 0); 581 rootEntry = menu; 582 updateListAll(); 583 setSelected(currentItem(), hasFocus()); 584 } 585 586 void ConfigList::setParentMenu(void) 587 { 588 ConfigItem* item; 589 struct menu *oldroot; 590 591 oldroot = rootEntry; 592 if (rootEntry == &rootmenu) 593 return; 594 setRootMenu(menu_get_parent_menu(rootEntry->parent)); 595 596 QListViewItemIterator it(this); 597 for (; (item = (ConfigItem*)it.current()); it++) { 598 if (item->menu == oldroot) { 599 setCurrentItem(item); 600 ensureItemVisible(item); 601 break; 602 } 603 } 604 } 605 606 void ConfigList::keyPressEvent(QKeyEvent* ev) 607 { 608 QListViewItem* i = currentItem(); 609 ConfigItem* item; 610 struct menu *menu; 611 enum prop_type type; 612 613 if (ev->key() == Key_Escape && mode != fullMode) { 614 emit parentSelected(); 615 ev->accept(); 616 return; 617 } 618 619 if (!i) { 620 Parent::keyPressEvent(ev); 621 return; 622 } 623 item = (ConfigItem*)i; 624 625 switch (ev->key()) { 626 case Key_Return: 627 case Key_Enter: 628 if (item->goParent) { 629 emit parentSelected(); 630 break; 631 } 632 menu = item->menu; 633 if (!menu) 634 break; 635 type = menu->prompt ? menu->prompt->type : P_UNKNOWN; 636 if (type == P_MENU && rootEntry != menu && 637 mode != fullMode && mode != menuMode) { 638 emit menuSelected(menu); 639 break; 640 } 641 case Key_Space: 642 changeValue(item); 643 break; 644 case Key_N: 645 setValue(item, no); 646 break; 647 case Key_M: 648 setValue(item, mod); 649 break; 650 case Key_Y: 651 setValue(item, yes); 652 break; 653 default: 654 Parent::keyPressEvent(ev); 655 return; 656 } 657 ev->accept(); 658 } 659 660 void ConfigList::contentsMousePressEvent(QMouseEvent* e) 661 { 662 //QPoint p(contentsToViewport(e->pos())); 663 //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y()); 664 Parent::contentsMousePressEvent(e); 665 } 666 667 void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e) 668 { 669 QPoint p(contentsToViewport(e->pos())); 670 ConfigItem* item = (ConfigItem*)itemAt(p); 671 struct menu *menu; 672 enum prop_type ptype; 673 const QPixmap* pm; 674 int idx, x; 675 676 if (!item) 677 goto skip; 678 679 menu = item->menu; 680 x = header()->offset() + p.x(); 681 idx = colRevMap[header()->sectionAt(x)]; 682 switch (idx) { 683 case promptColIdx: 684 pm = item->pixmap(promptColIdx); 685 if (pm) { 686 int off = header()->sectionPos(0) + itemMargin() + 687 treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0)); 688 if (x >= off && x < off + pm->width()) { 689 if (item->goParent) { 690 emit parentSelected(); 691 break; 692 } else if (!menu) 693 break; 694 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; 695 if (ptype == P_MENU && rootEntry != menu && 696 mode != fullMode && mode != menuMode) 697 emit menuSelected(menu); 698 else 699 changeValue(item); 700 } 701 } 702 break; 703 case noColIdx: 704 setValue(item, no); 705 break; 706 case modColIdx: 707 setValue(item, mod); 708 break; 709 case yesColIdx: 710 setValue(item, yes); 711 break; 712 case dataColIdx: 713 changeValue(item); 714 break; 715 } 716 717 skip: 718 //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y()); 719 Parent::contentsMouseReleaseEvent(e); 720 } 721 722 void ConfigList::contentsMouseMoveEvent(QMouseEvent* e) 723 { 724 //QPoint p(contentsToViewport(e->pos())); 725 //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y()); 726 Parent::contentsMouseMoveEvent(e); 727 } 728 729 void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e) 730 { 731 QPoint p(contentsToViewport(e->pos())); 732 ConfigItem* item = (ConfigItem*)itemAt(p); 733 struct menu *menu; 734 enum prop_type ptype; 735 736 if (!item) 737 goto skip; 738 if (item->goParent) { 739 emit parentSelected(); 740 goto skip; 741 } 742 menu = item->menu; 743 if (!menu) 744 goto skip; 745 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; 746 if (ptype == P_MENU && (mode == singleMode || mode == symbolMode)) 747 emit menuSelected(menu); 748 else if (menu->sym) 749 changeValue(item); 750 751 skip: 752 //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y()); 753 Parent::contentsMouseDoubleClickEvent(e); 754 } 755 756 void ConfigList::focusInEvent(QFocusEvent *e) 757 { 758 Parent::focusInEvent(e); 759 760 QListViewItem* item = currentItem(); 761 if (!item) 762 return; 763 764 setSelected(item, TRUE); 765 emit gotFocus(); 766 } 767 768 ConfigView* ConfigView::viewList; 769 770 ConfigView::ConfigView(QWidget* parent, ConfigMainWindow* cview, 771 ConfigSettings *configSettings) 772 : Parent(parent) 773 { 774 list = new ConfigList(this, cview, configSettings); 775 lineEdit = new ConfigLineEdit(this); 776 lineEdit->hide(); 777 778 this->nextView = viewList; 779 viewList = this; 780 } 781 782 ConfigView::~ConfigView(void) 783 { 784 ConfigView** vp; 785 786 for (vp = &viewList; *vp; vp = &(*vp)->nextView) { 787 if (*vp == this) { 788 *vp = nextView; 789 break; 790 } 791 } 792 } 793 794 void ConfigView::updateList(ConfigItem* item) 795 { 796 ConfigView* v; 797 798 for (v = viewList; v; v = v->nextView) 799 v->list->updateList(item); 800 } 801 802 void ConfigView::updateListAll(void) 803 { 804 ConfigView* v; 805 806 for (v = viewList; v; v = v->nextView) 807 v->list->updateListAll(); 808 } 809 810 /* 811 * Construct the complete config widget 812 */ 813 ConfigMainWindow::ConfigMainWindow(void) 814 { 815 QMenuBar* menu; 816 bool ok; 817 int x, y, width, height; 818 819 QWidget *d = configApp->desktop(); 820 821 ConfigSettings* configSettings = new ConfigSettings(); 822 #if QT_VERSION >= 300 823 width = configSettings->readNumEntry("/kconfig/qconf/window width", d->width() - 64); 824 height = configSettings->readNumEntry("/kconfig/qconf/window height", d->height() - 64); 825 resize(width, height); 826 x = configSettings->readNumEntry("/kconfig/qconf/window x", 0, &ok); 827 if (ok) 828 y = configSettings->readNumEntry("/kconfig/qconf/window y", 0, &ok); 829 if (ok) 830 move(x, y); 831 showDebug = configSettings->readBoolEntry("/kconfig/qconf/showDebug", false); 832 833 // read list settings into configSettings, will be used later for ConfigList setup 834 configSettings->readListSettings(); 835 #else 836 width = d->width() - 64; 837 height = d->height() - 64; 838 resize(width, height); 839 showDebug = false; 840 #endif 841 842 split1 = new QSplitter(this); 843 split1->setOrientation(QSplitter::Horizontal); 844 setCentralWidget(split1); 845 846 menuView = new ConfigView(split1, this, configSettings); 847 menuList = menuView->list; 848 849 split2 = new QSplitter(split1); 850 split2->setOrientation(QSplitter::Vertical); 851 852 // create config tree 853 configView = new ConfigView(split2, this, configSettings); 854 configList = configView->list; 855 856 helpText = new QTextView(split2); 857 helpText->setTextFormat(Qt::RichText); 858 859 setTabOrder(configList, helpText); 860 configList->setFocus(); 861 862 menu = menuBar(); 863 toolBar = new QToolBar("Tools", this); 864 865 backAction = new QAction("Back", QPixmap(xpm_back), "Back", 0, this); 866 connect(backAction, SIGNAL(activated()), SLOT(goBack())); 867 backAction->setEnabled(FALSE); 868 QAction *quitAction = new QAction("Quit", "&Quit", CTRL+Key_Q, this); 869 connect(quitAction, SIGNAL(activated()), SLOT(close())); 870 QAction *loadAction = new QAction("Load", QPixmap(xpm_load), "&Load", CTRL+Key_L, this); 871 connect(loadAction, SIGNAL(activated()), SLOT(loadConfig())); 872 QAction *saveAction = new QAction("Save", QPixmap(xpm_save), "&Save", CTRL+Key_S, this); 873 connect(saveAction, SIGNAL(activated()), SLOT(saveConfig())); 874 QAction *saveAsAction = new QAction("Save As...", "Save &As...", 0, this); 875 connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs())); 876 QAction *singleViewAction = new QAction("Single View", QPixmap(xpm_single_view), "Split View", 0, this); 877 connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView())); 878 QAction *splitViewAction = new QAction("Split View", QPixmap(xpm_split_view), "Split View", 0, this); 879 connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView())); 880 QAction *fullViewAction = new QAction("Full View", QPixmap(xpm_tree_view), "Full View", 0, this); 881 connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView())); 882 883 QAction *showNameAction = new QAction(NULL, "Show Name", 0, this); 884 showNameAction->setToggleAction(TRUE); 885 showNameAction->setOn(configList->showName); 886 connect(showNameAction, SIGNAL(toggled(bool)), SLOT(setShowName(bool))); 887 QAction *showRangeAction = new QAction(NULL, "Show Range", 0, this); 888 showRangeAction->setToggleAction(TRUE); 889 showRangeAction->setOn(configList->showRange); 890 connect(showRangeAction, SIGNAL(toggled(bool)), SLOT(setShowRange(bool))); 891 QAction *showDataAction = new QAction(NULL, "Show Data", 0, this); 892 showDataAction->setToggleAction(TRUE); 893 showDataAction->setOn(configList->showData); 894 connect(showDataAction, SIGNAL(toggled(bool)), SLOT(setShowData(bool))); 895 QAction *showAllAction = new QAction(NULL, "Show All Options", 0, this); 896 showAllAction->setToggleAction(TRUE); 897 showAllAction->setOn(configList->showAll); 898 connect(showAllAction, SIGNAL(toggled(bool)), SLOT(setShowAll(bool))); 899 QAction *showDebugAction = new QAction(NULL, "Show Debug Info", 0, this); 900 showDebugAction->setToggleAction(TRUE); 901 showDebugAction->setOn(showDebug); 902 connect(showDebugAction, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool))); 903 904 QAction *showIntroAction = new QAction(NULL, "Introduction", 0, this); 905 connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro())); 906 QAction *showAboutAction = new QAction(NULL, "About", 0, this); 907 connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout())); 908 909 // init tool bar 910 backAction->addTo(toolBar); 911 toolBar->addSeparator(); 912 loadAction->addTo(toolBar); 913 saveAction->addTo(toolBar); 914 toolBar->addSeparator(); 915 singleViewAction->addTo(toolBar); 916 splitViewAction->addTo(toolBar); 917 fullViewAction->addTo(toolBar); 918 919 // create config menu 920 QPopupMenu* config = new QPopupMenu(this); 921 menu->insertItem("&File", config); 922 loadAction->addTo(config); 923 saveAction->addTo(config); 924 saveAsAction->addTo(config); 925 config->insertSeparator(); 926 quitAction->addTo(config); 927 928 // create options menu 929 QPopupMenu* optionMenu = new QPopupMenu(this); 930 menu->insertItem("&Option", optionMenu); 931 showNameAction->addTo(optionMenu); 932 showRangeAction->addTo(optionMenu); 933 showDataAction->addTo(optionMenu); 934 optionMenu->insertSeparator(); 935 showAllAction->addTo(optionMenu); 936 showDebugAction->addTo(optionMenu); 937 938 // create help menu 939 QPopupMenu* helpMenu = new QPopupMenu(this); 940 menu->insertSeparator(); 941 menu->insertItem("&Help", helpMenu); 942 showIntroAction->addTo(helpMenu); 943 showAboutAction->addTo(helpMenu); 944 945 connect(configList, SIGNAL(menuSelected(struct menu *)), 946 SLOT(changeMenu(struct menu *))); 947 connect(configList, SIGNAL(parentSelected()), 948 SLOT(goBack())); 949 connect(menuList, SIGNAL(menuSelected(struct menu *)), 950 SLOT(changeMenu(struct menu *))); 951 952 connect(configList, SIGNAL(gotFocus(void)), 953 SLOT(listFocusChanged(void))); 954 connect(menuList, SIGNAL(gotFocus(void)), 955 SLOT(listFocusChanged(void))); 956 957 #if QT_VERSION >= 300 958 QString listMode = configSettings->readEntry("/kconfig/qconf/listMode", "symbol"); 959 if (listMode == "single") 960 showSingleView(); 961 else if (listMode == "full") 962 showFullView(); 963 else /*if (listMode == "split")*/ 964 showSplitView(); 965 966 // UI setup done, restore splitter positions 967 QValueList<int> sizes = configSettings->readSizes("/kconfig/qconf/split1", &ok); 968 if (ok) 969 split1->setSizes(sizes); 970 971 sizes = configSettings->readSizes("/kconfig/qconf/split2", &ok); 972 if (ok) 973 split2->setSizes(sizes); 974 #else 975 showSplitView(); 976 #endif 977 delete configSettings; 978 } 979 980 static QString print_filter(const QString &str) 981 { 982 QRegExp re("[<>&\"\\n]"); 983 QString res = str; 984 for (int i = 0; (i = res.find(re, i)) >= 0;) { 985 switch (res[i].latin1()) { 986 case '<': 987 res.replace(i, 1, "<"); 988 i += 4; 989 break; 990 case '>': 991 res.replace(i, 1, ">"); 992 i += 4; 993 break; 994 case '&': 995 res.replace(i, 1, "&"); 996 i += 5; 997 break; 998 case '"': 999 res.replace(i, 1, """); 1000 i += 6; 1001 break; 1002 case '\n': 1003 res.replace(i, 1, "<br>"); 1004 i += 4; 1005 break; 1006 } 1007 } 1008 return res; 1009 } 1010 1011 static void expr_print_help(void *data, const char *str) 1012 { 1013 reinterpret_cast<QString*>(data)->append(print_filter(str)); 1014 } 1015 1016 /* 1017 * display a new help entry as soon as a new menu entry is selected 1018 */ 1019 void ConfigMainWindow::setHelp(QListViewItem* item) 1020 { 1021 struct symbol* sym; 1022 struct menu* menu = 0; 1023 1024 configList->parent()->lineEdit->hide(); 1025 if (item) 1026 menu = ((ConfigItem*)item)->menu; 1027 if (!menu) { 1028 helpText->setText(QString::null); 1029 return; 1030 } 1031 1032 QString head, debug, help; 1033 menu = ((ConfigItem*)item)->menu; 1034 sym = menu->sym; 1035 if (sym) { 1036 if (menu->prompt) { 1037 head += "<big><b>"; 1038 head += print_filter(_(menu->prompt->text)); 1039 head += "</b></big>"; 1040 if (sym->name) { 1041 head += " ("; 1042 head += print_filter(_(sym->name)); 1043 head += ")"; 1044 } 1045 } else if (sym->name) { 1046 head += "<big><b>"; 1047 head += print_filter(_(sym->name)); 1048 head += "</b></big>"; 1049 } 1050 head += "<br><br>"; 1051 1052 if (showDebug) { 1053 debug += "type: "; 1054 debug += print_filter(sym_type_name(sym->type)); 1055 if (sym_is_choice(sym)) 1056 debug += " (choice)"; 1057 debug += "<br>"; 1058 if (sym->rev_dep.expr) { 1059 debug += "reverse dep: "; 1060 expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE); 1061 debug += "<br>"; 1062 } 1063 for (struct property *prop = sym->prop; prop; prop = prop->next) { 1064 switch (prop->type) { 1065 case P_PROMPT: 1066 case P_MENU: 1067 debug += "prompt: "; 1068 debug += print_filter(_(prop->text)); 1069 debug += "<br>"; 1070 break; 1071 case P_DEFAULT: 1072 debug += "default: "; 1073 expr_print(prop->expr, expr_print_help, &debug, E_NONE); 1074 debug += "<br>"; 1075 break; 1076 case P_CHOICE: 1077 if (sym_is_choice(sym)) { 1078 debug += "choice: "; 1079 expr_print(prop->expr, expr_print_help, &debug, E_NONE); 1080 debug += "<br>"; 1081 } 1082 break; 1083 case P_SELECT: 1084 debug += "select: "; 1085 expr_print(prop->expr, expr_print_help, &debug, E_NONE); 1086 debug += "<br>"; 1087 break; 1088 case P_RANGE: 1089 debug += "range: "; 1090 expr_print(prop->expr, expr_print_help, &debug, E_NONE); 1091 debug += "<br>"; 1092 break; 1093 default: 1094 debug += "unknown property: "; 1095 debug += prop_get_type_name(prop->type); 1096 debug += "<br>"; 1097 } 1098 if (prop->visible.expr) { 1099 debug += " dep: "; 1100 expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE); 1101 debug += "<br>"; 1102 } 1103 } 1104 debug += "<br>"; 1105 } 1106 1107 help = print_filter(_(sym->help)); 1108 } else if (menu->prompt) { 1109 head += "<big><b>"; 1110 head += print_filter(_(menu->prompt->text)); 1111 head += "</b></big><br><br>"; 1112 if (showDebug) { 1113 if (menu->prompt->visible.expr) { 1114 debug += " dep: "; 1115 expr_print(menu->prompt->visible.expr, expr_print_help, &debug, E_NONE); 1116 debug += "<br><br>"; 1117 } 1118 } 1119 } 1120 if (showDebug) 1121 debug += QString().sprintf("defined at %s:%d<br><br>", menu->file->name, menu->lineno); 1122 helpText->setText(head + debug + help); 1123 } 1124 1125 void ConfigMainWindow::loadConfig(void) 1126 { 1127 QString s = QFileDialog::getOpenFileName(".config", NULL, this); 1128 if (s.isNull()) 1129 return; 1130 if (conf_read(QFile::encodeName(s))) 1131 QMessageBox::information(this, "qconf", "Unable to load configuration!"); 1132 ConfigView::updateListAll(); 1133 } 1134 1135 void ConfigMainWindow::saveConfig(void) 1136 { 1137 if (conf_write(NULL)) 1138 QMessageBox::information(this, "qconf", "Unable to save configuration!"); 1139 } 1140 1141 void ConfigMainWindow::saveConfigAs(void) 1142 { 1143 QString s = QFileDialog::getSaveFileName(".config", NULL, this); 1144 if (s.isNull()) 1145 return; 1146 if (conf_write(QFile::encodeName(s))) 1147 QMessageBox::information(this, "qconf", "Unable to save configuration!"); 1148 } 1149 1150 void ConfigMainWindow::changeMenu(struct menu *menu) 1151 { 1152 configList->setRootMenu(menu); 1153 backAction->setEnabled(TRUE); 1154 } 1155 1156 void ConfigMainWindow::listFocusChanged(void) 1157 { 1158 if (menuList->hasFocus()) { 1159 if (menuList->mode == menuMode) 1160 configList->clearSelection(); 1161 setHelp(menuList->selectedItem()); 1162 } else if (configList->hasFocus()) { 1163 setHelp(configList->selectedItem()); 1164 } 1165 } 1166 1167 void ConfigMainWindow::goBack(void) 1168 { 1169 ConfigItem* item; 1170 1171 configList->setParentMenu(); 1172 if (configList->rootEntry == &rootmenu) 1173 backAction->setEnabled(FALSE); 1174 item = (ConfigItem*)menuList->selectedItem(); 1175 while (item) { 1176 if (item->menu == configList->rootEntry) { 1177 menuList->setSelected(item, TRUE); 1178 break; 1179 } 1180 item = (ConfigItem*)item->parent(); 1181 } 1182 } 1183 1184 void ConfigMainWindow::showSingleView(void) 1185 { 1186 menuView->hide(); 1187 menuList->setRootMenu(0); 1188 configList->mode = singleMode; 1189 if (configList->rootEntry == &rootmenu) 1190 configList->updateListAll(); 1191 else 1192 configList->setRootMenu(&rootmenu); 1193 configList->setAllOpen(TRUE); 1194 configList->setFocus(); 1195 } 1196 1197 void ConfigMainWindow::showSplitView(void) 1198 { 1199 configList->mode = symbolMode; 1200 if (configList->rootEntry == &rootmenu) 1201 configList->updateListAll(); 1202 else 1203 configList->setRootMenu(&rootmenu); 1204 configList->setAllOpen(TRUE); 1205 configApp->processEvents(); 1206 menuList->mode = menuMode; 1207 menuList->setRootMenu(&rootmenu); 1208 menuList->setAllOpen(TRUE); 1209 menuView->show(); 1210 menuList->setFocus(); 1211 } 1212 1213 void ConfigMainWindow::showFullView(void) 1214 { 1215 menuView->hide(); 1216 menuList->setRootMenu(0); 1217 configList->mode = fullMode; 1218 if (configList->rootEntry == &rootmenu) 1219 configList->updateListAll(); 1220 else 1221 configList->setRootMenu(&rootmenu); 1222 configList->setAllOpen(FALSE); 1223 configList->setFocus(); 1224 } 1225 1226 void ConfigMainWindow::setShowAll(bool b) 1227 { 1228 if (configList->showAll == b) 1229 return; 1230 configList->showAll = b; 1231 configList->updateListAll(); 1232 menuList->showAll = b; 1233 menuList->updateListAll(); 1234 } 1235 1236 void ConfigMainWindow::setShowDebug(bool b) 1237 { 1238 if (showDebug == b) 1239 return; 1240 showDebug = b; 1241 } 1242 1243 void ConfigMainWindow::setShowName(bool b) 1244 { 1245 if (configList->showName == b) 1246 return; 1247 configList->showName = b; 1248 configList->reinit(); 1249 menuList->showName = b; 1250 menuList->reinit(); 1251 } 1252 1253 void ConfigMainWindow::setShowRange(bool b) 1254 { 1255 if (configList->showRange == b) 1256 return; 1257 configList->showRange = b; 1258 configList->reinit(); 1259 menuList->showRange = b; 1260 menuList->reinit(); 1261 } 1262 1263 void ConfigMainWindow::setShowData(bool b) 1264 { 1265 if (configList->showData == b) 1266 return; 1267 configList->showData = b; 1268 configList->reinit(); 1269 menuList->showData = b; 1270 menuList->reinit(); 1271 } 1272 1273 /* 1274 * ask for saving configuration before quitting 1275 * TODO ask only when something changed 1276 */ 1277 void ConfigMainWindow::closeEvent(QCloseEvent* e) 1278 { 1279 if (!sym_change_count) { 1280 e->accept(); 1281 return; 1282 } 1283 QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning, 1284 QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape); 1285 mb.setButtonText(QMessageBox::Yes, "&Save Changes"); 1286 mb.setButtonText(QMessageBox::No, "&Discard Changes"); 1287 mb.setButtonText(QMessageBox::Cancel, "Cancel Exit"); 1288 switch (mb.exec()) { 1289 case QMessageBox::Yes: 1290 conf_write(NULL); 1291 case QMessageBox::No: 1292 e->accept(); 1293 break; 1294 case QMessageBox::Cancel: 1295 e->ignore(); 1296 break; 1297 } 1298 } 1299 1300 void ConfigMainWindow::showIntro(void) 1301 { 1302 static char str[] = "Welcome to the qconf graphical kernel configuration tool for Linux.\n\n" 1303 "For each option, a blank box indicates the feature is disabled, a check\n" 1304 "indicates it is enabled, and a dot indicates that it is to be compiled\n" 1305 "as a module. Clicking on the box will cycle through the three states.\n\n" 1306 "If you do not see an option (e.g., a device driver) that you believe\n" 1307 "should be present, try turning on Show All Options under the Options menu.\n" 1308 "Although there is no cross reference yet to help you figure out what other\n" 1309 "options must be enabled to support the option you are interested in, you can\n" 1310 "still view the help of a grayed-out option.\n\n" 1311 "Toggling Show Debug Info under the Options menu will show the dependencies,\n" 1312 "which you can then match by examining other options.\n\n"; 1313 1314 QMessageBox::information(this, "qconf", str); 1315 } 1316 1317 void ConfigMainWindow::showAbout(void) 1318 { 1319 static char str[] = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n\n" 1320 "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n"; 1321 1322 QMessageBox::information(this, "qconf", str); 1323 } 1324 1325 void ConfigMainWindow::saveSettings(void) 1326 { 1327 #if QT_VERSION >= 300 1328 ConfigSettings *configSettings = new ConfigSettings; 1329 configSettings->writeEntry("/kconfig/qconf/window x", pos().x()); 1330 configSettings->writeEntry("/kconfig/qconf/window y", pos().y()); 1331 configSettings->writeEntry("/kconfig/qconf/window width", size().width()); 1332 configSettings->writeEntry("/kconfig/qconf/window height", size().height()); 1333 configSettings->writeEntry("/kconfig/qconf/showName", configList->showName); 1334 configSettings->writeEntry("/kconfig/qconf/showRange", configList->showRange); 1335 configSettings->writeEntry("/kconfig/qconf/showData", configList->showData); 1336 configSettings->writeEntry("/kconfig/qconf/showAll", configList->showAll); 1337 configSettings->writeEntry("/kconfig/qconf/showDebug", showDebug); 1338 1339 QString entry; 1340 switch(configList->mode) { 1341 case singleMode : 1342 entry = "single"; 1343 break; 1344 1345 case symbolMode : 1346 entry = "split"; 1347 break; 1348 1349 case fullMode : 1350 entry = "full"; 1351 break; 1352 } 1353 configSettings->writeEntry("/kconfig/qconf/listMode", entry); 1354 1355 configSettings->writeSizes("/kconfig/qconf/split1", split1->sizes()); 1356 configSettings->writeSizes("/kconfig/qconf/split2", split2->sizes()); 1357 1358 delete configSettings; 1359 #endif 1360 } 1361 1362 void fixup_rootmenu(struct menu *menu) 1363 { 1364 struct menu *child; 1365 static int menu_cnt = 0; 1366 1367 menu->flags |= MENU_ROOT; 1368 for (child = menu->list; child; child = child->next) { 1369 if (child->prompt && child->prompt->type == P_MENU) { 1370 menu_cnt++; 1371 fixup_rootmenu(child); 1372 menu_cnt--; 1373 } else if (!menu_cnt) 1374 fixup_rootmenu(child); 1375 } 1376 } 1377 1378 static const char *progname; 1379 1380 static void usage(void) 1381 { 1382 printf("%s <config>\n", progname); 1383 exit(0); 1384 } 1385 1386 int main(int ac, char** av) 1387 { 1388 ConfigMainWindow* v; 1389 const char *name; 1390 1391 bindtextdomain(PACKAGE, LOCALEDIR); 1392 textdomain(PACKAGE); 1393 1394 #ifndef LKC_DIRECT_LINK 1395 kconfig_load(); 1396 #endif 1397 1398 progname = av[0]; 1399 configApp = new QApplication(ac, av); 1400 if (ac > 1 && av[1][0] == '-') { 1401 switch (av[1][1]) { 1402 case 'h': 1403 case '?': 1404 usage(); 1405 } 1406 name = av[2]; 1407 } else 1408 name = av[1]; 1409 if (!name) 1410 usage(); 1411 1412 conf_parse(name); 1413 fixup_rootmenu(&rootmenu); 1414 conf_read(NULL); 1415 //zconfdump(stdout); 1416 1417 v = new ConfigMainWindow(); 1418 1419 //zconfdump(stdout); 1420 v->show(); 1421 configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit())); 1422 configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings())); 1423 configApp->exec(); 1424 1425 return 0; 1426 } 1427