You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kima/src/kima.cpp

433 lines
15 KiB

/***************************************************************************
* Copyright (C) 2006 by Ken Werner *
* ken.werner@web.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <list>
// Qt
#include <qlabel.h>
#include <qfile.h>
#include <qspinbox.h>
#include <qcombobox.h>
#include <qtextedit.h>
#include <qtimer.h>
#include <qcursor.h>
#include <klistview.h>
#include <qlistview.h>
#include <qwidgetstack.h>
// KDE
#include <kmessagebox.h>
#include <kaboutapplication.h>
#include <kpopupmenu.h>
#include <kstdaction.h>
#include <kaction.h>
#include <kactioncollection.h>
#include <kactionclasses.h>
#include <kapplication.h>
#include <kdialogbase.h>
#include <kconfig.h>
//#include <kglobal.h>
#include <kiconloader.h>
#include <klocale.h>
// Kima
#include "kima.h"
#include "flowlayout.h"
#include "sourcelistitem.h"
#include "prefs.h"
// Kima Soures
#include "sources/acpithermalsrc.h"
#include "sources/ibmacpithermalsrc.h"
#include "sources/ibmacpifansrc.h"
#include "sources/ibmhdaps.h"
#include "sources/omnibookthermalsrc.h"
#include "sources/ibookg4thermalsrc.h"
#include "sources/hwmonthermalsrc.h"
#include "sources/hwmonfansrc.h"
#include "sources/sysfreqsrc.h"
#include "sources/cpuinfofreqsrc.h"
#include "sources/i8ksrc.h"
#include "sources/nvidiathermalsrc.h"
#include "sources/hddtempsrc.h"
#include "sources/uptimesrc.h"
#include "sources/batterysrc.h"
//#include "kdebug.h"
extern "C" {
KPanelApplet* init( QWidget* inParent, const QString& inConfigFile) {
KGlobal::locale()->insertCatalogue("kima");
return new Kima(inConfigFile, KPanelApplet::Normal,
//KPanelApplet::About | KPanelApplet::Help | KPanelApplet::Preferences,
KPanelApplet::About | KPanelApplet::Preferences,
inParent, "kima");
}
}
Kima::Kima(const QString& inConfigFile, Type inType, int inActions, QWidget* inParent, const char* inName):
KPanelApplet(inConfigFile, inType, inActions, inParent, inName),
QToolTip(this),
mCachedWFH(0),
mCachedHeight(0),
mDraggedSourceItem(NULL){
mAboutDialog = 0; // aboutData is created in the about() method
mPrefsDlg = 0; // the prefs dialog is created in the preferences() method
mPrefs = 0; // the prefs ui is created in the preferences() method
// Get the current application configuration handle
mKConfig = config();
mKConfig->setGroup("Kima");
// automatically delete pointers
mSources.setAutoDelete(TRUE);
// create layout
mLayout = new FlowLayout(this, orientation() );
mLayout->setSpacing(8);
// add the sources into the sources list
addSources(NVidiaThermalSrc::createInstances(this));
addSources(ACPIThermalSrc::createInstances(this));
addSources(IBMACPIThermalSrc::createInstances(this));
addSources(IBMACPIFanSrc::createInstances(this));
addSources(IBMHDAPSSrc::createInstances(this));
addSources(OmnibookThermalSrc::createInstances(this));
addSources(IbookG4ThermalSrc::createInstances(this));
addSources(HwMonThermalSrc::createInstances(this));
addSources(SysFreqSrc::createInstances(this));
addSources(CpuinfoFreqSrc::createInstances(this));
addSources(I8kSrc::createInstances(this));
addSources(HDDTempSrc::createInstances(this));
addSources(HwMonFanSrc::createInstances(this));
addSources(UptimeSrc::createInstances(this));
addSources(BatterySrc::createInstances(this));
QPtrListIterator<Source> itSync(mSources);
Source* source;
while((source = itSync.current()) != 0){
++itSync;
registerSource(source);
}
mLayout->updatePositions(mKConfig);
// create the menu
mMenu = new KPopupMenu(this);
mMenu->insertTitle(SmallIcon("hwinfo"), i18n("Kima"));
if (mCpufreqd.enabled()) {
mMenu->insertItem(i18n("&Performance Profiles"), mCpufreqd.menu());
}
KActionCollection* actionCollection = new KActionCollection(this, "actionCollection", kapp);
KAction* action = KStdAction::preferences(this, SLOT(preferences()), actionCollection);
action->setText(i18n("&Preferences"));
action->plug(mMenu);
action = KStdAction::aboutApp(this, SLOT(about()), actionCollection);
action->setText(i18n("&About Kima"));
action->plug(mMenu);
//menu->insertSeparator();
//KStdAction::quit( kapp, SLOT( quit() ), actionCollection )->plug( menu );
}
Kima::~Kima() {
// super class deletes the widgets
}
void Kima::addSources(const std::list<Source*>& inList){
for(std::list<Source*>::const_iterator it = inList.begin(); it != inList.end(); ++it){
mSources.append(*it);
}
}
void Kima::displaySource(bool inDisplay, Source* inSource){
if(inDisplay){
//kdDebug() << "Kima::displaySource mLayout->add: " << inSource->getName() << endl;
mLayout->addSource(inSource); // add the source
//kdDebug() << "Pos of " << inSource->getID() << ": " << inSource->getPosition() << endl;
}else{
//kdDebug() << "Kima::displaySource mLayout->remove: " << inSource->getName() << endl;
mLayout->remove(inSource->getWidget());
}
}
void Kima::about() {
if(!mAboutDialog){
KAboutData* aboutData = new KAboutData("libkima",
"Kima",
"0.7.3.2",
I18N_NOOP("Kicker monitoring applet.\n\n"
"This applet monitors various temperature, frequency and fan sources.\n"
"Make sure you have enabled a supported kernel module.\n"),
KAboutData::License_GPL,
"(c) 2004-2007, Ken Werner");
aboutData->addAuthor("Ken Werner", 0, "ken.werner@web.de");
aboutData->addAuthor("Johannes Schaub", 0, "schaub-johannes@web.de");
aboutData->addAuthor("Valentine Sinitsyn", I18N_NOOP("cpufreqd control module"), "e_val@inbox.ru");
aboutData->addCredit("Franziska Simmank");
aboutData->addCredit("Manfred Paul");
aboutData->addCredit("Rainer Dorsch");
aboutData->addCredit("Flavio Castelli");
aboutData->addCredit("Jocke Andersson");
aboutData->addCredit("Raoul Martin");
aboutData->addCredit("Donnie Bhayangkara");
aboutData->addCredit("Gonzalo Nemmi");
aboutData->addCredit("Mariusz Ciesla");
aboutData->addCredit("Mark Rosenstand");
aboutData->addCredit("Santiago Bruno");
aboutData->addCredit("Dark Apostrophe");
aboutData->addCredit("Sascha Hoogen");
aboutData->addCredit("Peter Avramucz");
aboutData->addCredit("Oskar Ellström");
aboutData->addCredit("Uğur Çetin");
mAboutDialog = new KAboutApplication(aboutData, this, "aboutApp", false);
}
mAboutDialog->show();
}
void Kima::help() {
KMessageBox::information(0, i18n("This is a help box"));
}
void Kima::preferences() {
//KMessageBox::information(0, i18n("This is a preferences box"));
if(!mPrefsDlg){
//create the prefs dialog
mPrefsDlg = new KDialogBase( this, "prefsDlg", false, i18n("Configuration"), KDialogBase::Ok|KDialogBase::Apply|KDialogBase::Cancel, KDialogBase::Ok, false );
//create the prefs ui
mPrefs = new Prefs( mPrefsDlg, "prefsui" ); //the uic generated class
//setup the dialog
//mPrefsDlg->setFixedSize(mPrefs->size());
mPrefsDlg->setMainWidget(mPrefs); //embed the uic generated class into the kde dialog
connect(mPrefsDlg, SIGNAL(applyClicked()), this, SLOT(savePreferences()));
connect(mPrefsDlg, SIGNAL(okClicked()), this, SLOT(savePreferences()));
connect(mPrefsDlg, SIGNAL(cancelClicked()), this, SLOT(cancelPreferences()));
// create new list items and the widgetStack widgets
QPtrListIterator<Source> it(mSources);
Source* source;
while((source = it.current()) != 0){
++it;
// create the specific source prefs and add them to the widgetStack
mPrefs->widgetStack->addWidget(source->createPrefs(mPrefs->widgetStack));
// create the SourceListItem to switch and to enable/disable the widgetstack item (the source)
// and connect the apply/ok signals to the item, so it can change it's text to a potentially
// new source name.
SourceListItem * item = new SourceListItem(source, mPrefs->sourceListView, QCheckListItem::CheckBox);
connect(mPrefsDlg, SIGNAL(applyClicked()), item, SLOT(updateText()));
connect(mPrefsDlg, SIGNAL(okClicked()), item, SLOT(updateText()));
}
if(mPrefs->sourceListView->firstChild()){
mPrefs->sourceListView->setSelected(mPrefs->sourceListView->firstChild(), true); // select the first list item
raiseSourcePrefsWidget(mPrefs->sourceListView->firstChild()); // raise that item
}
connect(mPrefs->sourceListView, SIGNAL(selectionChanged(QListViewItem*)), this, SLOT(raiseSourcePrefsWidget(QListViewItem*)));
}
// update prefs gui
QPtrListIterator<Source> srcIt(mSources);
Source* source;
while((source = srcIt.current()) != 0){
++srcIt;
source->updatePrefsGUI();
}
// update the sourcelist checkbox
QPtrList<QListViewItem> lst;
QListViewItemIterator lvIt(mPrefs->sourceListView);
while(lvIt.current()){
SourceListItem* sli = static_cast<SourceListItem*>(lvIt.current());
sli->setOn(sli->getSource()->isEnabled());
++lvIt;
}
//show the dialog
mPrefsDlg->show();
}
void Kima::raiseSourcePrefsWidget(QListViewItem* inListViewItem){
mPrefs->widgetStack->raiseWidget(static_cast<SourceListItem*>(inListViewItem)->getSource()->getPrefs());
}
void Kima::cancelPreferences(){
// update prefs gui
QPtrListIterator<Source> it(mSources);
Source* source;
while((source = it.current()) != 0){
++it;
source->updatePrefsGUI();
}
}
void Kima::savePreferences(){
// save prefs
QPtrListIterator<Source> it(mSources);
Source* source;
while((source = it.current()) != 0){
++it;
source->applyPrefs();
source->savePrefs(mKConfig);
}
// save the position of all sources because they might have changed.
mLayout->updatePositions(mKConfig);
// update the source widgets
updateSourceWidgets();
// write config
mKConfig->sync();
// reset cached witdh for height to force recalculation of the applets width
mCachedWFH = 0;
}
int Kima::widthForHeight(int inHeight) const{
//kdDebug() << "widthForHeight: " << height << endl;
mLayout->setOrientation(Qt::Horizontal);
if(mCachedHeight != inHeight){
mCachedHeight = inHeight;
mCachedWFH = 0;
}
mCachedWFH = QMAX(mLayout->widthForHeight(inHeight), mCachedWFH);
return mCachedWFH;
}
int Kima::heightForWidth(int inWidth) const{
//kdDebug() << "heightForWidth: " << width << endl;
mLayout->setOrientation(Qt::Vertical);
return mLayout->heightForWidth(inWidth);
//return sizeHint().height();
}
void Kima::mousePressEvent(QMouseEvent* inEvent ){
if(inEvent->button() == QMouseEvent::RightButton){
mMenu->popup( inEvent->globalPos() );
if(mDraggedSourceItem)
mDraggedSourceItem->widget()->unsetCursor(); // unset drag cursor
}
else if(inEvent->button() == QMouseEvent::LeftButton){
QLayoutIterator it = mLayout->iterator();
while(it.current()){
QWidget * c = it.current()->widget();
if(c->rect().contains(c->mapFromGlobal(inEvent->globalPos()))){
mDraggedSourceItem = it.current(); // remenber the clicked source
c->setCursor(Qt::SizeAllCursor); // set drag cursor
mDragFactor = (c->rect().height()/2.0) / (double)c->mapFromGlobal(inEvent->globalPos()).y();
break;
}
++it;
}
}
}
void Kima::mouseReleaseEvent(QMouseEvent* inEvent){
//if(inEvent->button() == QMouseEvent::LeftButton && mDraggedSourceItem){
if(mDraggedSourceItem){
mCachedWFH = 0; // reset cached witdh for height to force recalculation of the applets width
mDraggedSourceItem->widget()->unsetCursor(); // unset drag cursor
mDraggedSourceItem = NULL;
}
}
void Kima::mouseMoveEvent( QMouseEvent* inEvent ) {
if(!mDraggedSourceItem)
return;
QLayoutIterator it = mLayout->iterator();
while(it.current()){
QWidget * c = it.current()->widget();
if(c->rect().contains(c->mapFromGlobal(inEvent->globalPos()))){
if(it.current() == mDraggedSourceItem)
break;
// we are over a source-widget.
// move the dragged widget above / below that
// widget, depending where the cursor is.
QRect crect = c->rect();
double relPos = c->mapFromGlobal(inEvent->globalPos()).y() * mDragFactor;
if(mLayout->moveItem(mDraggedSourceItem, it.current(), crect.height()/2.0 > relPos ? FlowLayout::ABOVE : FlowLayout::BELOW)){
mLayout->updatePositions(mKConfig);
updateGeometry();
mKConfig->sync(); // write config
updateSourceWidgets();
}
break;
}
++it;
}
// outside kima?
if(!rect().contains(mapToParent(inEvent->pos())))
mDraggedSourceItem->widget()->setCursor(Qt::ForbiddenCursor);
else
mDraggedSourceItem->widget()->setCursor(Qt::SizeAllCursor);
}
void Kima::paintEvent(QPaintEvent* inEvent){
KPanelApplet::paintEvent(inEvent);
updateSourceWidgets();
}
void Kima::updateSourceWidgets(){
// repaint the source widgets
for(Source* source = mSources.first(); source; source = mSources.next())
if(source->showOnApplet())
source->getWidget()->update();
}
void Kima::registerSource(Source* source) {
// then, tell the source to set up its widget
source->realizeWidget();
// enable transparency
source->getWidget()->setBackgroundMode(X11ParentRelative);
// load prefs from the configuration
// this call also emits enabledChanged
source->loadPrefs(mKConfig);
// add the source to the layout if necessary
displaySource(source->isEnabled() && source->showOnApplet(), source);
// connection to add and remove sources from mLayout
connect(source, SIGNAL(displaySource(bool, Source*)), this, SLOT(displaySource(bool, Source*)));
}
void Kima::maybeTip(const QPoint& inPos){
if(!rect().contains(inPos))
return;
QString text = "<b>" + i18n("Sources:") + "</b><br><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">";
QPtrListIterator<Source> it(mSources);
Source* source;
while((source = it.current()) != 0){
++it;
if(source->isEnabled() && source->isToolTipEnabled())
text.append("<tr><td>" +
source->getName() + "</td><td>" +
source->getValue() + "</td><td>");
}
text.append("</table>");
tip(rect(), text);
}