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