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