
/**********************************************************************/
/*   TimeMon (c)  1994  Helmut Maierhofer			      */
/*   KDE-ified M. Maierhofer 1998                                     */
/*   maintained by Dirk A. Mueller <mueller@kde.org>                  */
/**********************************************************************/

/*
 * timemon.h
 *
 * Definitions for the timemon widget.
 */

#include <config.h>

//#include <string.h>

#include <qpainter.h>
#include <qtimer.h>
#include <qtooltip.h>

#include <kconfig.h>
#include <kglobal.h>
#include <klocale.h>
#include <khelpmenu.h>
#include <kpopupmenu.h>
#include <kprocess.h>
#include <kmessagebox.h>
#include <kdebug.h>

#include "timemon.h"
#include "confdlg.h"
#include "sample.h"

#include "timemon.moc"
#include <stdio.h>

// Update colour settings with the new ones from the config dialog.
void KTimeMon::updateConfig(KConfDialog *d)
{
    kernelColour = d->getKernelColour();
    userColour = d->getUserColour();
    niceColour = d->getNiceColour();
    cachedColour = d->getCachedColour();
    usedColour = d->getUsedColour();
    buffersColour = d->getBuffersColour();
    swapColour = d->getSwapColour();
    bgColour = d->getBgColour();

    tooltip = d->getToolTip();
}

// -----------------------------------------------------------------------------
// some KPanelApplet API functions

int KTimeMon::widthForHeight(int)
{
    return 32;
}


int KTimeMon::heightForWidth(int)
{
    return 32;

}

void KTimeMon::about()
{
    kdDebug() << "about called" << endl;
}


void KTimeMon::help()
{
    kdDebug() << "help called" << endl;
}

void KTimeMon::preferences()
{
    kdDebug() << "preferences called" << endl;
}


// -----------------------------------------------------------------------------
// Repaint the object; get the current sample and paint the bar graphs
// correspondingly. Use a pixmap to minimise flicker.

void KTimeMon::paintEvent(QPaintEvent *)
{
    int w, h, x, y, b;

    w = vertical ? width() : height();
    h = vertical ? height() : width();

    b = (w - 2) / 3;		// bar width (1 pixel gap)

    x = 0;

    KSample::Sample s;

    if (sample != 0)
        s = sample->getSample(h);
    else
        s.fill(h);

    QPixmap pixmap(width(), height());
    pixmap.fill(bgColour);

    QPainter painter(&pixmap);

    if (true) {			// normal mode
        y = h - s.kernel; paintRect(x, y, b, s.kernel, kernelColour, &painter);
        y -= s.user; paintRect(x, y, b, s.user, userColour, &painter);
        y -= s.nice; paintRect(x, y, b, s.nice, niceColour, &painter);

        x += b + 1;
        y = h - s.used; paintRect(x, y, b, s.used, usedColour, &painter);
        y -= s.buffers; paintRect(x, y, b, s.buffers, buffersColour, &painter);
        y -= s.cached; paintRect(x, y, b, s.cached, cachedColour, &painter);

        x += b + 1;
        y = h - s.sused; paintRect(x, y, b, s.sused, swapColour, &painter);

    } else {			// extended mode

        y = h - s.pout; paintRect(x, y, b, s.pout, kernelColour, &painter);
        y -= s.pin; paintRect(x, y, b, s.pin, niceColour, &painter);

        x += b + 1;
        y = h - s.swout; paintRect(x, y, b, s.swout, cachedColour, &painter);
        y -= s.swin; paintRect(x, y, b, s.swin, usedColour, &painter);

        x += b + 1;
        y = h - s.cswitches; paintRect(x, y, b, s.cswitches, swapColour, &painter);
    }

    painter.end();

    bitBlt(this, 0, 0, &pixmap);
}

// -----------------------------------------------------------------------------
// Draw part of a bar, depending on the bar orientation.

void KTimeMon::paintRect(int x, int y, int w, int h, QColor c, QPainter *p)
{
    if (vertical)
        p->fillRect(x, y, w, h, c);
    else
        p->fillRect(width() - y - h, x, h, w, c);
}

// Show a tool-tip with some status information.
void KTimeMon::maybeTip(const QPoint& p)
{
    if (!tooltip) return;		// user doesn't want tool tips
    if (sample == 0) return;	// no associated sample...
    if(!rect().contains(p)) return;

    QString str;

    KSample::Sample s = sample->getSample(100); // scale to 100(%)
    str.sprintf(i18n("cpu: %lu%% idle\nmem: %luMB %lu%% free\nswap: %luMB %lu%% free"),
                100-s.kernel-s.user-s.nice, s.used,
		100-s.used, s.stotal, 100-s.sused);

    tip(rect(), str);
}

// -- KTimeMon definition ------------------------------------------------

// Initialise the member variables, read the configuration data base,
// set up the widget, and start the timer.
KTimeMon::KTimeMon()
    : KPanelApplet(0, "KTimeMon"), QToolTip(this),
    configDialog(0), bgProcess(0),
    kernelColour("red1"), userColour("blue"),
    niceColour("yellow"), cachedColour("darkgreen"),
    usedColour("blue1"), buffersColour("yellow"),
    swapColour("cyan3"), bgColour(colorGroup().background())
{
    mouseAction[0] = SWITCH;
    mouseAction[1] = NOTHING;
    mouseAction[2] = MENU;

    KConfig* conf = KGlobal::config();


    conf->setGroup("Parameters");
    interval = conf->readUnsignedNumEntry("Interval", 500);
    autoScale = conf->readBoolEntry("AutoScale", true);

    pageScale = conf->readUnsignedNumEntry("PageScale", 10);
    swapScale = conf->readUnsignedNumEntry("SwapScale", 5);
    ctxScale = conf->readUnsignedNumEntry("ContextScale", 300);
    for (int i = 0; i < MAX_MOUSE_ACTIONS; i++) {
        QString n;
        n.setNum(i);

        mouseAction[i] = (MouseAction)
            conf->readUnsignedNumEntry(QString("MouseAction")+n, mouseAction[i]);
        mouseActionCommand[i] = conf->readEntry(QString("MouseActionCommand")+n,
                                                "");
    }

    conf->setGroup("Interface");
    kernelColour = conf->readColorEntry("KernelColour", &kernelColour);
    userColour = conf->readColorEntry("UserColour", &userColour);
    niceColour = conf->readColorEntry("NiceColour", &niceColour);
    cachedColour = conf->readColorEntry("CachedColour", &cachedColour);
    usedColour = conf->readColorEntry("UsedColour", &usedColour);
    buffersColour = conf->readColorEntry("BuffersColour", &buffersColour);
    swapColour = conf->readColorEntry("SwapColour", &swapColour);
    bgColour = conf->readColorEntry("BgColour", &bgColour);

    vertical = conf->readBoolEntry("Vertical", vertical);
    tooltip = conf->readBoolEntry("Tooltip", true);

    setBackgroundMode(NoBackground); // to avoid flicker

    sample = new KSample(this, autoScale, pageScale, swapScale, ctxScale);

    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(timeout()));
    timer->start(interval);

    QString aboutmsg;
    aboutmsg.sprintf(i18n("ktimemon for kdeutils\n"
                          "maintained by Dirk A. Mueller <dmuell@gmx.net>\n"
                          "written by M. Maierhofer (m.maierhofer@tees.ac.uk)\n"
                          "Based on timemon by H. Maierhofer"));

    hmenu = new KHelpMenu(this, aboutmsg);
    menu = new QPopupMenu(this);

    menu->insertItem(i18n("Help"), hmenu->menu(), 1);
    menu->insertItem(i18n("Settings..."), 2);
    menu->insertItem(i18n("Horizontal bars"), 4);
    menu->insertSeparator();
    menu->insertItem(i18n("Quit"), 5);

    menu->connectItem(2, this, SLOT(configure()));
    menu->connectItem(4, this, SLOT(orientation()));
    menu->connectItem(5, qApp, SLOT(quit()));

    menu->setCheckable(true);

    QSize size(32, 32);
    resize(conf->readSizeEntry("WidgetSize", &size));

    vertical = !vertical;		// and similar for orientation
    orientation();
}

// -----------------------------------------------------------------------------

// Kill the timer and delete the member variables
KTimeMon::~KTimeMon()
{
    stop();
    delete hmenu;
    delete sample;
    delete configDialog;
    delete bgProcess;
}


// Apply the settings from the configuration dialog and save them.
void KTimeMon::apply()
{
    stop();
    interval = configDialog->getInterval();
    cont();

    updateConfig(configDialog);

    sample->setScaling(configDialog->getAutoScale(),
                       configDialog->getPageScale(),
                       configDialog->getSwapScale(),
                       configDialog->getCtxScale());

    for (int i = 0; i < MAX_MOUSE_ACTIONS; i++) {
        mouseAction[i] = (MouseAction) configDialog->getMouseAction(i);
        mouseActionCommand[i] = configDialog->getMouseActionCommand(i);
    }

    update();
    writeConfiguration();
}

void KTimeMon::stop()
{
    timer->stop();
}

void KTimeMon::cont()
{
    timer->start(interval);
}

// Dump the current configuration entries to the data base.
void KTimeMon::writeConfiguration()
{
    KConfig* conf = KGlobal::config();

    conf->setGroup("Interface");
    conf->writeEntry("KernelColour", kernelColour);
    conf->writeEntry("UserColour", userColour);
    conf->writeEntry("NiceColour", niceColour);
    conf->writeEntry("CachedColour", cachedColour);
    conf->writeEntry("UsedColour", usedColour);
    conf->writeEntry("BuffersColour", buffersColour);
    conf->writeEntry("SwapColour", swapColour);
    conf->writeEntry("BgColour", bgColour);
    conf->writeEntry("Mode", true);
    conf->writeEntry("Vertical", vertical);
    conf->writeEntry("Tooltip", tooltip);

    conf->setGroup("Parameters");
    conf->writeEntry("Interval", interval);
    conf->writeEntry("AutoScale", autoScale);
    conf->writeEntry("PageScale", pageScale);
    conf->writeEntry("SwapScale", swapScale);
    conf->writeEntry("ContextScale", ctxScale);
    conf->writeEntry("WidgetSize", size());
    for (int i = 0; i < MAX_MOUSE_ACTIONS; i++) {
        QString n;
        n.setNum(i);

        conf->writeEntry(QString("MouseAction")+n, (unsigned)mouseAction[i]);
        conf->writeEntry(QString("MouseActionCommand")+n, mouseActionCommand[i]);
    }
}

// Make the KSample object update its internal sample and repaint the
// object.
void KTimeMon::timeout()
{
    sample->updateSample();
    update();
}

// This is called when the session management strikes, and also when the
// main program exits with a code of 0 (i.e. there was no error).
void KTimeMon::save()
{
    writeConfiguration();
}

// -----------------------------------------------------------------------------
// Update the configuration dialog with the current values and show it.

void KTimeMon::configure()
{
    if (configDialog == 0) configDialog = new KConfDialog(this);
    configDialog->update();
    configDialog->show();
}

// -----------------------------------------------------------------------------
// Change the orientation of the status bars

void KTimeMon::orientation()
{
    vertical = !vertical;

    menu->setItemChecked(4, !vertical);

    update();
}

// Pop up the menu when the appropriate button has been pressed.
void KTimeMon::mousePressEvent(QMouseEvent *event)
{
    if (event == 0) return;

    int index = -1;
    if (event->button() == LeftButton) index = 0;
    else if (event->button() == MidButton) index = 1;
    else if (event->button() == RightButton) index = 2;

    if (index == -1) return;

    switch (mouseAction[index]) {
    case NOTHING:
        break;
    case SWITCH:
        break;
    case MENU:
        menu->popup(mapToGlobal(event->pos()));
    break;
    case COMMAND:
        runCommand(index);
        break;
    }
}

// Start the given command
void KTimeMon::runCommand(int index)
{
    // just in case it still hangs around
    if (bgProcess != 0) delete bgProcess;

    bgProcess = new KShellProcess;
    *bgProcess << mouseActionCommand[index];
    connect(bgProcess, SIGNAL(receivedStderr(KProcess *, char *, int)),
            this, SLOT(commandStderr(KProcess *, char *, int)));
    bgProcess->start(KProcess::DontCare, KProcess::Stderr);
}

// -----------------------------------------------------------------------------
// Check if there is any diagnostic output (command not found or such)

void KTimeMon::commandStderr(KProcess */*proc*/, char *buffer, int /*length*/)
{
    QString msgbuf;

    msgbuf  = i18n("Got diagnostic output from child command:\n\n");
    msgbuf += QString::fromLocal8Bit(buffer);

    KMessageBox::information(this, msgbuf);
}


// -----------------------------------------------------------------------------
