diff --git a/src/common/utils.cpp b/src/common/utils.cpp index c228f34..8b4032b 100644 --- a/src/common/utils.cpp +++ b/src/common/utils.cpp @@ -1,323 +1,322 @@ /* This file is part of KNemo Copyright (C) 2009, 2010 John Stamp KNemo is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. KNemo 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Portions taken from FreeSWITCH Copyright (c) 2007-2008, Thomas BERNARD Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. */ #include #include #include #include #include #include #include -#include #include #include "data.h" #include "utils.h" #ifdef __linux__ #include #include #else #include #include #include #define NEXTADDR(w, u) \ if (rtm_addrs & (w)) {\ l = sizeof(struct sockaddr); memmove(cp, &(u), l); cp += l;\ } #define rtm m_rtmsg.m_rtm #endif #ifdef __linux__ QString ipv4gwi; QString ipv6gwi; QString ipv4gw; QString ipv6gw; void parseNetlinkRoute( struct nl_object *object, void * ) { struct rtnl_route *const route = reinterpret_cast(object); int rtfamily = rtnl_route_get_family( route ); if ( rtfamily == AF_INET || rtfamily == AF_INET6 ) { struct rtnl_nexthop *nh = NULL; struct nl_addr *addr = NULL; if ( rtnl_route_get_nnexthops( route ) > 0 ) { nh = rtnl_route_nexthop_n ( route, 0 ); addr = rtnl_route_nh_get_gateway( nh ); } if ( addr ) { char gwaddr[ INET6_ADDRSTRLEN ]; char gwname[ IFNAMSIZ ]; memset( gwaddr, 0, sizeof( gwaddr ) ); struct in_addr * inad = reinterpret_cast(nl_addr_get_binary_addr( addr )); nl_addr2str( addr, gwaddr, sizeof( gwaddr ) ); inet_ntop( rtfamily, &inad->s_addr, gwaddr, sizeof( gwaddr ) ); int oif = rtnl_route_nh_get_ifindex( nh ); if_indextoname( oif, gwname ); if ( rtfamily == AF_INET ) { ipv4gw = QLatin1String(gwaddr); ipv4gwi = QLatin1String(gwname); } else if ( rtfamily == AF_INET6 ) { ipv6gw = QLatin1String(gwaddr); ipv6gwi = QLatin1String(gwname); } } } } QString getNetlinkRoute( int afType, QString *defaultGateway, void *data ) { if ( !data ) return QString(); struct nl_cache* rtlcache = static_cast(data); if ( afType == AF_INET ) { ipv4gw.clear(); ipv4gwi.clear(); } else if ( afType == AF_INET6 ) { ipv6gw.clear(); ipv6gwi.clear(); } nl_cache_foreach( rtlcache, parseNetlinkRoute, NULL); if ( afType == AF_INET ) { if ( defaultGateway ) *defaultGateway = ipv4gw; return ipv4gwi; } else { if ( defaultGateway ) *defaultGateway = ipv6gw; return ipv6gwi; } } #else QString getSocketRoute( int afType, QString *defaultGateway ) { struct { struct rt_msghdr m_rtm; char m_space[ 512 ]; } m_rtmsg; int s, seq, l, rtm_addrs, i; pid_t pid; struct sockaddr so_dst, so_mask; char *cp = m_rtmsg.m_space; struct sockaddr *gate = NULL, *sa; struct rt_msghdr *msg_hdr; char outBuf[ INET6_ADDRSTRLEN ]; memset( &outBuf, 0, sizeof( outBuf ) ); void *tempAddrPtr = NULL; QString ifname; pid = getpid(); seq = 0; rtm_addrs = RTA_DST | RTA_NETMASK; memset( &so_dst, 0, sizeof( so_dst ) ); memset( &so_mask, 0, sizeof( so_mask ) ); memset( &rtm, 0, sizeof( struct rt_msghdr ) ); rtm.rtm_type = RTM_GET; rtm.rtm_flags = RTF_UP | RTF_GATEWAY; rtm.rtm_version = RTM_VERSION; rtm.rtm_seq = ++seq; rtm.rtm_addrs = rtm_addrs; if ( afType == AF_INET ) { so_dst.sa_family = AF_INET; so_mask.sa_family = AF_INET; } else { so_dst.sa_family = AF_INET6; so_mask.sa_family = AF_INET6; } NEXTADDR( RTA_DST, so_dst ); NEXTADDR( RTA_NETMASK, so_mask ); rtm.rtm_msglen = l = cp - reinterpret_cast(&m_rtmsg); s = socket(PF_ROUTE, SOCK_RAW, 0); if ( write( s, reinterpret_cast(&m_rtmsg), l ) < 0 ) { close( s ); return ifname; } do { l = read(s, reinterpret_cast(&m_rtmsg), sizeof( m_rtmsg ) ); } while ( l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid) ); close( s ); msg_hdr = &rtm; cp = reinterpret_cast(msg_hdr + 1); if ( msg_hdr->rtm_addrs ) { for ( i = 1; i; i <<= 1 ) if ( i & msg_hdr->rtm_addrs ) { sa = reinterpret_cast(cp); if ( i == RTA_GATEWAY ) { gate = sa; char tempname[ IFNAMSIZ ]; if_indextoname( msg_hdr->rtm_index, tempname ); ifname = tempname; } cp += SA_SIZE( sa ); } } else return ifname; if ( AF_INET == afType ) tempAddrPtr = & reinterpret_cast(gate)->sin_addr; else tempAddrPtr = & reinterpret_cast(gate)->sin6_addr; inet_ntop( gate->sa_family, tempAddrPtr, outBuf, sizeof( outBuf ) ); if ( defaultGateway && strncmp( outBuf, "0.0.0.0", 7 ) != 0 ) *defaultGateway = outBuf; return ifname; } #endif QString getDefaultRoute( int afType, QString *defaultGateway, void *data ) { #ifdef __linux__ return getNetlinkRoute( afType, defaultGateway, data ); #else return getSocketRoute( afType, defaultGateway ); #endif } QList findThemes() { const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("knemo/themes"), QStandardPaths::LocateDirectory); QStringList themelist; Q_FOREACH (const QString& dir, dirs) { const QStringList fileNames = QDir(dir).entryList(QStringList() << QLatin1String("*.desktop")); Q_FOREACH (const QString& file, fileNames) { themelist.append(dir + QLatin1Char('/') + file); } } QList iconThemes; foreach ( QString themeFile, themelist ) { - KSharedConfigPtr conf = KSharedConfig::openConfig( themeFile ); + KSharedConfig::Ptr conf = KSharedConfig::openConfig( themeFile ); KConfigGroup cfg( conf, QLatin1String("Desktop Entry") ); KNemoTheme theme; theme.name = cfg.readEntry(QLatin1String("Name")); theme.comment = cfg.readEntry(QLatin1String("Comment")); theme.internalName = cfg.readEntry( QLatin1String("X-KNemo-Theme") ); iconThemes << theme; } return iconThemes; } QFont setIconFont( const QString& text, const QFont& font, int iconWidth ) { // Is there a better way to do this? QFont f( font ); qreal pointSize = f.pointSizeF(); QFontMetricsF fm( f ); qreal w = fm.width( text ); if ( w != iconWidth ) { pointSize *= qreal( iconWidth ) / w; if ( pointSize < 0.5 ) pointSize = 0.5; f.setPointSizeF( pointSize ); fm = QFontMetricsF( f ); while ( pointSize > 0.5 && fm.width( text ) > iconWidth ) { pointSize -= 0.5; f.setPointSizeF( pointSize ); fm = QFontMetricsF( f ); } } // Don't want decender()...space too tight if ( fm.ascent() > iconWidth/2.0 ) { pointSize *= iconWidth / 2.0 / fm.ascent(); if ( pointSize < 0.5 ) pointSize = 0.5; f.setPointSizeF( pointSize ); fm = QFontMetricsF( f ); while ( pointSize > 0.5 && fm.ascent() > iconWidth/2.0 ) { pointSize -= 0.5; f.setPointSizeF( pointSize ); fm = QFontMetricsF( f ); } } return f; } double validatePoll( double val ) { int siz = sizeof(pollIntervals)/sizeof(double); for ( int i = 0; i < siz; i++ ) { if ( val <= pollIntervals[i] ) { val = pollIntervals[i]; return val; } } return GeneralSettings().pollInterval; } diff --git a/src/kcm/configdialog.h b/src/kcm/configdialog.h index a5f4ebd..1af4f4b 100644 --- a/src/kcm/configdialog.h +++ b/src/kcm/configdialog.h @@ -1,146 +1,147 @@ /* This file is part of KNemo Copyright (C) 2004, 2005, 2006 Percy Leonhardt Copyright (C) 2009, 2010 John Stamp KNemo is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. KNemo 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef CONFIGDIALOG_H #define CONFIGDIALOG_H #include #include "data.h" #include "ui_configdlg.h" #include +#include class QTreeWidgetItem; class KCalendarSystem; /** * This is the configuration dialog for KNemo * It is implemented as a control center module so that it is still * possible to configure KNemo even when there is no icon visible * in the system tray. * * @short Configuration dialog for KNemo * @author Percy Leonhardt */ class StatsRuleModel : public QStandardItemModel { Q_OBJECT public: StatsRuleModel( QObject *parent = 0 ) : QStandardItemModel( parent ) {} virtual ~StatsRuleModel() {} void setCalendar( const KCalendarSystem *cal ); QModelIndex addRule( const StatsRule &s ); void modifyRule( const QModelIndex &index, const StatsRule &s ); QList getRules(); private: QString dateText( const StatsRule &s ); const KCalendarSystem *mCalendar; }; class WarnModel : public QStandardItemModel { Q_OBJECT public: WarnModel( QObject *parent = 0 ) : QStandardItemModel( parent ) {} virtual ~WarnModel() {} QModelIndex addWarn( const WarnRule &w ); void modifyWarn( const QModelIndex &index, const WarnRule &warn ); QList getRules(); private: QString ruleText( const WarnRule &warn ); }; class ConfigDialog : public KCModule { Q_OBJECT public: /** * Default Constructor */ ConfigDialog( QWidget *parent, const QVariantList &args ); /** * Default Destructor */ virtual ~ConfigDialog(); void load(); void save(); void defaults(); private Q_SLOTS: void buttonNewSelected(); void buttonAllSelected(); void buttonDeleteSelected(); void buttonAddCommandSelected(); void buttonRemoveCommandSelected(); void setUpDownButtons( QTreeWidgetItem* item ); void buttonCommandUpSelected(); void buttonCommandDownSelected(); void buttonAddToolTipSelected(); void buttonRemoveToolTipSelected(); void buttonNotificationsSelected(); void interfaceSelected( int row ); void aliasChanged( const QString& text ); void iconThemeChanged( int set ); void comboHidingChanged( int val ); void checkBoxStatisticsToggled( bool on ); void checkBoxStartKNemoToggled( bool on ); void colorButtonChanged(); void iconFontChanged( const QFont &font ); void advancedButtonClicked(); void addStatsClicked(); void modifyStatsClicked(); void removeStatsClicked(); void addWarnClicked(); void modifyWarnClicked(); void removeWarnClicked(); void listViewCommandsSelectionChanged( QTreeWidgetItem *current, QTreeWidgetItem *previous ); void listViewCommandsChanged( QTreeWidgetItem* item, int column ); void moveTips( QListWidget *from, QListWidget *to ); private: void setupToolTipTab(); void setupToolTipMap(); void updateControls( InterfaceSettings *settings ); InterfaceSettings * getItemSettings(); int findIndexFromName( const QString& internalName ); QString findNameFromIndex( int index ); QPixmap textIcon( QString incomingText, QString outgoingText, int status ); QPixmap barIcon( int status ); void updateWarnText( int oldCount ); int mToolTipContent; bool mLock; Ui::ConfigDlg* mDlg; const KCalendarSystem* mCalendar; int mMaxDay; StatsRuleModel *statsModel; WarnModel *warnModel; - KSharedConfigPtr mConfig; + KSharedConfig::Ptr mConfig; QMap mSettingsMap; QMap mToolTips; QList mDeletedIfaces; }; #endif // CONFIGDIALOG_H diff --git a/src/knemod/global.cpp b/src/knemod/global.cpp index f8f6c45..9344c29 100644 --- a/src/knemod/global.cpp +++ b/src/knemod/global.cpp @@ -1,62 +1,61 @@ /* This file is part of KNemo Copyright (C) 2010 John Stamp KNemo is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. KNemo 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include -#include #include #include #include #include "global.h" QString formattedRate( quint64 data, bool useBits ) { if ( !useBits ) return KIO::convertSize( data ) + i18n( "/s" ); QString fmtString; double bits = data; // bit/s typically uses SI notation int units = 0; while ( bits >= 1000.0 && units < 3 ) { bits /= 1000.0; units++; } int precision = 0; if ( units ) precision = 1; QLocale locale; QString formattedNum = locale.toString( bits, 'g', precision ); switch (units) { case 0: fmtString = i18n( "%1 bit/s", formattedNum ); break; case 1: fmtString = i18n( "%1 kbit/s", formattedNum ); break; case 2: fmtString = i18n( "%1 Mbit/s", formattedNum ); break; case 3: fmtString = i18n( "%1 Gbit/s", formattedNum ); break; } return fmtString; } diff --git a/src/knemod/interface.cpp b/src/knemod/interface.cpp index 8358408..24916a9 100644 --- a/src/knemod/interface.cpp +++ b/src/knemod/interface.cpp @@ -1,480 +1,479 @@ /* This file is part of KNemo Copyright (C) 2004, 2006 Percy Leonhardt Copyright (C) 2009, 2010 John Stamp KNemo is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. KNemo 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include -#include #include #include "backends/backendbase.h" #include "global.h" #include "utils.h" #include "interface.h" #include "interfaceplotterdialog.h" #include "interfacestatistics.h" #include "interfacestatusdialog.h" #include "interfacestatisticsdialog.h" Interface::Interface( const QString &ifname, const BackendData* data ) : QObject(), mIfaceState( KNemoIface::UnknownState ), mPreviousIfaceState( KNemoIface::UnknownState ), mIfaceName( ifname ), mRealSec( 0.0 ), mUptime( 0 ), mUptimeString( QStringLiteral("00:00:00") ), mRxRate( 0 ), mTxRate( 0 ), mIcon( this ), mIfaceStatistics( 0 ), mStatusDialog( 0 ), mStatisticsDialog( 0 ), mPlotterDialog( 0 ), mBackendData( data ) { mPlotterDialog = new InterfacePlotterDialog( mIfaceName ); connect( &mIcon, SIGNAL( statisticsSelected() ), this, SLOT( showStatisticsDialog() ) ); } Interface::~Interface() { delete mStatusDialog; delete mPlotterDialog; delete mStatisticsDialog; delete mIfaceStatistics; } void Interface::configChanged() { - KSharedConfigPtr config = KSharedConfig::openConfig(); + KSharedConfig::Ptr config = KSharedConfig::openConfig(); QString group( confg_interface ); group += mIfaceName; KConfigGroup interfaceGroup( config, group ); InterfaceSettings s; mSettings.alias = interfaceGroup.readEntry( conf_alias ).trimmed(); mSettings.iconTheme = interfaceGroup.readEntry( conf_iconTheme, s.iconTheme ); QStringList themeNames; QList themes = findThemes(); // Let's check that it's available foreach( KNemoTheme theme, themes ) themeNames << theme.internalName; themeNames << NETLOAD_THEME; if ( !themeNames.contains( mSettings.iconTheme ) ) mSettings.iconTheme = TEXT_THEME; mSettings.colorIncoming = interfaceGroup.readEntry( conf_colorIncoming, s.colorIncoming ); mSettings.colorOutgoing = interfaceGroup.readEntry( conf_colorOutgoing, s.colorOutgoing ); KColorScheme scheme(QPalette::Active, KColorScheme::View); mSettings.colorDisabled = interfaceGroup.readEntry( conf_colorDisabled, scheme.foreground( KColorScheme::InactiveText ).color() ); mSettings.colorUnavailable = interfaceGroup.readEntry( conf_colorUnavailable, scheme.foreground( KColorScheme::InactiveText ).color() ); mSettings.colorBackground = scheme.foreground( KColorScheme::InactiveText ).color(); mSettings.iconFont = interfaceGroup.readEntry( conf_iconFont, s.iconFont ); mSettings.dynamicColor = interfaceGroup.readEntry( conf_dynamicColor, s.dynamicColor ); mSettings.colorIncomingMax = interfaceGroup.readEntry( conf_colorIncomingMax, s.colorIncomingMax ); mSettings.colorOutgoingMax = interfaceGroup.readEntry( conf_colorOutgoingMax, s.colorOutgoingMax ); mSettings.barScale = interfaceGroup.readEntry( conf_barScale, s.barScale ); mSettings.inMaxRate = interfaceGroup.readEntry( conf_inMaxRate, s.inMaxRate )*1024; mSettings.outMaxRate = interfaceGroup.readEntry( conf_outMaxRate, s.outMaxRate )*1024; mSettings.hideWhenDisconnected = interfaceGroup.readEntry( conf_hideWhenNotAvail, s.hideWhenDisconnected ); mSettings.hideWhenUnavailable = interfaceGroup.readEntry( conf_hideWhenNotExist, s.hideWhenUnavailable ); mSettings.activateStatistics = interfaceGroup.readEntry( conf_activateStatistics, s.activateStatistics ); mSettings.trafficThreshold = clamp(interfaceGroup.readEntry( conf_trafficThreshold, s.trafficThreshold ), 0, 1000 ); mSettings.warnRules.clear(); int warnRuleCount = interfaceGroup.readEntry( conf_warnRules, 0 ); for ( int i = 0; i < warnRuleCount; ++i ) { group = QString::fromLatin1( "%1%2 #%3" ).arg( confg_warnRule ).arg( mIfaceName ).arg( i ); if ( config->hasGroup( group ) ) { KConfigGroup warnGroup( config, group ); WarnRule warn; warn.periodUnits = clamp(warnGroup.readEntry( conf_warnPeriodUnits, warn.periodUnits ), KNemoStats::Hour, KNemoStats::Year ); warn.periodCount = clamp(warnGroup.readEntry( conf_warnPeriodCount, warn.periodUnits ), 1, 1000 ); warn.trafficType = clamp(warnGroup.readEntry( conf_warnTrafficType, warn.trafficType ), KNemoStats::Peak, KNemoStats::PeakOffpeak ); warn.trafficDirection = clamp(warnGroup.readEntry( conf_warnTrafficDirection, warn.trafficDirection ), KNemoStats::TrafficIn, KNemoStats::TrafficTotal ); warn.trafficUnits = clamp(warnGroup.readEntry( conf_warnTrafficUnits, warn.trafficUnits ), KNemoStats::UnitB, KNemoStats::UnitG ); warn.threshold = clamp(warnGroup.readEntry( conf_warnThreshold, warn.threshold ), 0.0, 9999.0 ); warn.customText = warnGroup.readEntry( conf_warnCustomText, warn.customText ).trimmed(); mSettings.warnRules << warn; } } if ( interfaceGroup.hasKey( conf_calendar ) ) { QString oldSetting = interfaceGroup.readEntry( conf_calendar ); // FIXME //mSettings.calendarSystem = KCalendarSystem::calendarSystem( oldSetting ); interfaceGroup.writeEntry( conf_calendarSystem, static_cast(mSettings.calendarSystem) ); interfaceGroup.deleteEntry( conf_calendar ); config->sync(); } else mSettings.calendarSystem = static_cast(interfaceGroup.readEntry( conf_calendarSystem, static_cast(KLocale::QDateCalendar) )); mSettings.statsRules.clear(); int statsRuleCount = interfaceGroup.readEntry( conf_statsRules, 0 ); KCalendarSystem *testCal = KCalendarSystem::create( mSettings.calendarSystem ); for ( int i = 0; i < statsRuleCount; ++i ) { group = QString::fromLatin1( "%1%2 #%3" ).arg( confg_statsRule ).arg( mIfaceName ).arg( i ); if ( config->hasGroup( group ) ) { KConfigGroup statsGroup( config, group ); StatsRule rule; rule.startDate = statsGroup.readEntry( conf_statsStartDate, QDate() ); rule.periodUnits = clamp(statsGroup.readEntry( conf_statsPeriodUnits, rule.periodUnits ), KNemoStats::Day, KNemoStats::Year ); rule.periodCount = clamp(statsGroup.readEntry( conf_statsPeriodCount, rule.periodCount ), 1, 1000 ); rule.logOffpeak = statsGroup.readEntry( conf_logOffpeak,rule.logOffpeak ); rule.offpeakStartTime = QTime::fromString( statsGroup.readEntry( conf_offpeakStartTime, rule.offpeakStartTime.toString( Qt::ISODate ) ), Qt::ISODate ); rule.offpeakEndTime = QTime::fromString( statsGroup.readEntry( conf_offpeakEndTime, rule.offpeakEndTime.toString( Qt::ISODate ) ), Qt::ISODate ); rule.weekendIsOffpeak = statsGroup.readEntry( conf_weekendIsOffpeak, rule.weekendIsOffpeak ); rule.weekendDayStart = clamp(statsGroup.readEntry( conf_weekendDayStart, rule.weekendDayStart ), 1, testCal->daysInWeek( QDate::currentDate() ) ); rule.weekendDayEnd = clamp(statsGroup.readEntry( conf_weekendDayEnd, rule.weekendDayEnd ), 1, testCal->daysInWeek( QDate::currentDate() ) ); rule.weekendTimeStart = QTime::fromString( statsGroup.readEntry( conf_weekendTimeStart, rule.weekendTimeStart.toString( Qt::ISODate ) ), Qt::ISODate ); rule.weekendTimeEnd = QTime::fromString( statsGroup.readEntry( conf_weekendTimeEnd, rule.weekendTimeEnd.toString( Qt::ISODate ) ), Qt::ISODate ); if ( rule.isValid( testCal ) ) { mSettings.statsRules << rule; } } } mSettings.commands.clear(); int numCommands = interfaceGroup.readEntry( conf_numCommands, s.numCommands ); for ( int i = 0; i < numCommands; i++ ) { QString entry; InterfaceCommand cmd; entry = QString::fromLatin1( "%1%2" ).arg( conf_runAsRoot ).arg( i + 1 ); cmd.runAsRoot = interfaceGroup.readEntry( entry, false ); entry = QString::fromLatin1( "%1%2" ).arg( conf_command ).arg( i + 1 ); cmd.command = interfaceGroup.readEntry( entry ); entry = QString::fromLatin1( "%1%2" ).arg( conf_menuText ).arg( i + 1 ); cmd.menuText = interfaceGroup.readEntry( entry ); mSettings.commands.append( cmd ); } // This prevents needless regeneration of icon when first shown in tray if ( mIfaceState == KNemoIface::UnknownState ) { mIfaceState = mBackendData->status; mPreviousIfaceState = mIfaceState; } mIcon.configChanged(); if ( mIfaceStatistics ) { mIfaceStatistics->configChanged(); if ( !mSettings.activateStatistics ) stopStatistics(); } else if ( mSettings.activateStatistics ) { startStatistics(); } if ( mStatusDialog ) mStatusDialog->configChanged(); if ( mStatisticsDialog != 0 ) mStatisticsDialog->configChanged(); if ( mPlotterDialog ) mPlotterDialog->useBitrate( generalSettings->useBitrate ); } void Interface::processUpdate() { mPreviousIfaceState = mIfaceState; unsigned int trafficThreshold = mSettings.trafficThreshold; mIfaceState = mBackendData->status; int units = 1; if ( generalSettings->useBitrate ) units = 8; mRxRate = mBackendData->incomingBytes * units / generalSettings->pollInterval; mTxRate = mBackendData->outgoingBytes * units / generalSettings->pollInterval; mRxRateStr = formattedRate( mRxRate, generalSettings->useBitrate ); mTxRateStr = formattedRate( mTxRate, generalSettings->useBitrate ); QString title = mSettings.alias; if ( title.isEmpty() ) title = mIfaceName; if ( mIfaceState & KNemoIface::Connected ) { // the interface is connected, look for traffic if ( ( mBackendData->rxPackets - mBackendData->prevRxPackets ) > trafficThreshold ) mIfaceState |= KNemoIface::RxTraffic; if ( ( mBackendData->txPackets - mBackendData->prevTxPackets ) > trafficThreshold ) mIfaceState |= KNemoIface::TxTraffic; if ( mIfaceStatistics ) { // We only check once an hour if we need to create a new stats entry. // However, the timer will be out of sync if we're resuming from suspend, // so we just check if we need to readjust when an interface becomes connected. if ( mPreviousIfaceState < KNemoIface::Connected ) mIfaceStatistics->checkValidEntry(); mIfaceStatistics->addRxBytes( mBackendData->incomingBytes ); mIfaceStatistics->addTxBytes( mBackendData->outgoingBytes ); } updateTime(); if ( mPreviousIfaceState < KNemoIface::Connected ) { QString connectedStr; if ( mBackendData->isWireless ) connectedStr = i18n( "%1 is connected to %2", title, mBackendData->essid ); else connectedStr = i18n( "%1 is connected", title ); if ( mPreviousIfaceState != KNemoIface::UnknownState ) KNotification::event( QLatin1String("connected"), connectedStr ); } } else if ( mIfaceState & KNemoIface::Available ) { if ( mPreviousIfaceState & KNemoIface::Connected ) { KNotification::event( QLatin1String("disconnected"), i18n( "%1 has disconnected", title ) ); if ( mBackendData->interfaceType == KNemoIface::PPP ) backend->clearTraffic( mIfaceName ); resetUptime(); } else if ( mPreviousIfaceState < KNemoIface::Available ) { if ( mPreviousIfaceState != KNemoIface::UnknownState ) KNotification::event( QLatin1String("available"), i18n( "%1 is available", title ) ); } } else if ( mIfaceState == KNemoIface::Unavailable && mPreviousIfaceState > KNemoIface::Unavailable ) { KNotification::event( QLatin1String("unavailable"), i18n( "%1 is unavailable", title ) ); backend->clearTraffic( mIfaceName ); resetUptime(); } if ( mPreviousIfaceState != mIfaceState ) mIcon.updateTrayStatus(); if ( mPlotterDialog ) mPlotterDialog->updatePlotter( mRxRate, mTxRate ); mIcon.updateToolTip(); if ( mStatusDialog ) mStatusDialog->updateDialog(); } void Interface::resetUptime() { mUptime = 0; mRealSec = 0.0; mUptimeString = QStringLiteral("00:00:00"); mRxRate = 0; mTxRate = 0; mRxRateStr = formattedRate( mRxRate, generalSettings->useBitrate ); mTxRateStr = formattedRate( mTxRate, generalSettings->useBitrate ); } void Interface::showStatusDialog( bool fromContextMenu ) { // Toggle the status dialog. // First click will show the status dialog, second will hide it. if ( mStatusDialog == 0L ) { mStatusDialog = new InterfaceStatusDialog( this ); if ( mIfaceStatistics != 0 ) { connect( mIfaceStatistics, SIGNAL( currentEntryChanged() ), mStatusDialog, SLOT( statisticsChanged() ) ); mStatusDialog->statisticsChanged(); } } activateOrHide( mStatusDialog, fromContextMenu ); } void Interface::showSignalPlotter( bool fromContextMenu ) { // Toggle the signal plotter. activateOrHide( mPlotterDialog, fromContextMenu ); } void Interface::showStatisticsDialog() { if ( mStatisticsDialog == 0 ) { mStatisticsDialog = new InterfaceStatisticsDialog( this ); if ( mIfaceStatistics == 0 ) { // should never happen but you never know... startStatistics(); } connect( mStatisticsDialog, SIGNAL( clearStatistics() ), mIfaceStatistics, SLOT( clearStatistics() ) ); } mStatisticsDialog->show(); } void Interface::updateTime() { mRealSec += generalSettings->pollInterval; if ( mRealSec < 1.0 ) return; mUptime += trunc( mRealSec ); mRealSec -= trunc( mRealSec ); time_t updays = mUptime / 86400; mUptimeString = i18np("1 day, ","%1 days, ",updays); mUptime -= 86400 * updays; // we only want the seconds of today int hrs = mUptime / 3600; int mins = ( mUptime - hrs * 3600 ) / 60; int secs = mUptime - hrs * 3600 - mins * 60; QString time; time.sprintf( "%02d:%02d:%02d", hrs, mins, secs ); mUptimeString += time; } void Interface::startStatistics() { mIfaceStatistics = new InterfaceStatistics( this ); connect( mIfaceStatistics, SIGNAL( warnTraffic( QString, quint64, quint64 ) ), this, SLOT( warnTraffic( QString, quint64, quint64 ) ) ); if ( mStatusDialog != 0 ) { connect( mIfaceStatistics, SIGNAL( currentEntryChanged() ), mStatusDialog, SLOT( statisticsChanged() ) ); mStatusDialog->statisticsChanged(); } } void Interface::stopStatistics() { // this will close an open statistics dialog delete mStatisticsDialog; mStatisticsDialog = 0; delete mIfaceStatistics; mIfaceStatistics = 0; } void Interface::warnTraffic( QString warnText, quint64 threshold, quint64 current ) { if ( !warnText.isEmpty() ) { warnText = warnText.replace( QRegExp(QLatin1String("%i")), mIfaceName ); warnText = warnText.replace( QRegExp(QLatin1String("%a")), mSettings.alias ); warnText = warnText.replace( QRegExp(QLatin1String("%t")), KIO::convertSize( threshold ) ); warnText = warnText.replace( QRegExp(QLatin1String("%c")), KIO::convertSize( threshold ) ); } else { warnText = i18n( "" "
%1:Exceeded traffic limit of %2\n" "(currently %3)
", mIfaceName, KIO::convertSize( threshold ), KIO::convertSize( current ) ); } KNotification::event( QLatin1String("exceededTraffic"), warnText ); } void Interface::toggleSignalPlotter( bool show ) { if ( !mPlotterDialog ) return; if ( show ) mPlotterDialog->show(); else mPlotterDialog->hide(); } bool Interface::plotterVisible() { if ( !mPlotterDialog || !mPlotterDialog->isVisible() ) return false; return true; } // taken from ksystemtray.cpp void Interface::activateOrHide( QWidget* widget, bool onlyActivate ) { if ( !widget ) return; KWindowInfo info1 = KWindowSystem::windowInfo( widget->winId(), NET::XAWMState | NET::WMState ); // mapped = visible (but possibly obscured) bool mapped = (info1.mappingState() == NET::Visible) && !info1.isMinimized(); // - not mapped -> show, raise, focus // - mapped // - obscured -> raise, focus // - not obscured -> hide if( !mapped ) { KWindowSystem::setOnDesktop( widget->winId(), KWindowSystem::currentDesktop() ); widget->show(); widget->raise(); } else { QListIterator< WId > it (KWindowSystem::stackingOrder()); it.toBack(); while( it.hasPrevious() ) { WId id = it.previous(); if( id == widget->winId() ) break; KWindowInfo info2 = KWindowSystem::windowInfo( id, NET::WMGeometry | NET::XAWMState | NET::WMState | NET::WMWindowType ); if( info2.mappingState() != NET::Visible ) continue; // not visible on current desktop -> ignore if( !info2.geometry().intersects( widget->geometry())) continue; // not obscuring the window -> ignore if( !info1.hasState( NET::KeepAbove ) && info2.hasState( NET::KeepAbove )) continue; // obscured by window kept above -> ignore NET::WindowType type = info2.windowType( NET::NormalMask | NET::DesktopMask | NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask | NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask ); if( type == NET::Dock || type == NET::TopMenu ) continue; // obscured by dock or topmenu -> ignore widget->raise(); KWindowSystem::activateWindow( widget->winId()); return; } if ( !onlyActivate ) { widget->hide(); } } } #include "moc_interface.cpp" diff --git a/src/knemod/interfaceplotterdialog.h b/src/knemod/interfaceplotterdialog.h index 6b28024..88f3278 100644 --- a/src/knemod/interfaceplotterdialog.h +++ b/src/knemod/interfaceplotterdialog.h @@ -1,82 +1,82 @@ /* This file is part of KNemo Copyright (C) 2004, 2006 Percy Leonhardt Copyright (C) 2009, 2010 John Stamp KNemo is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. KNemo 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef INTERFACEPLOTTERDIALOG_H #define INTERFACEPLOTTERDIALOG_H #include #include #include "plotterconfigdialog.h" class FancyPlotterLabel; class KSignalPlotter; class QBoxLayout; class InterfacePlotterDialog : public QDialog { Q_OBJECT public: InterfacePlotterDialog( QString ); virtual ~InterfacePlotterDialog(); /** * Update the signal plotter with new data */ void updatePlotter( const double, const double ); void useBitrate( bool ); protected: bool event( QEvent *e ); void resizeEvent( QResizeEvent* ); private Q_SLOTS: void configFinished(); void saveConfig(); void setPlotterUnits(); private: void showContextMenu( const QPoint& ); void loadConfig(); void configChanged(); void configPlotter(); void addBeams(); - KSharedConfigPtr mConfig; + KSharedConfig::Ptr mConfig; PlotterConfigDialog *mConfigDlg; QWidget *mLabelsWidget; bool mSetPos; bool mWasShown; bool mUseBitrate; int mMultiplier; bool mOutgoingVisible; bool mIncomingVisible; PlotterSettings mSettings; QString mName; KSignalPlotter *mPlotter; FancyPlotterLabel *mReceivedLabel; FancyPlotterLabel *mSentLabel; QBoxLayout *mLabelLayout; QChar mIndicatorSymbol; QList mByteUnits; QList mBitUnits; }; #endif diff --git a/src/knemod/interfacestatistics.cpp b/src/knemod/interfacestatistics.cpp index 5148bcb..d041331 100644 --- a/src/knemod/interfacestatistics.cpp +++ b/src/knemod/interfacestatistics.cpp @@ -1,1123 +1,1122 @@ /* This file is part of KNemo Copyright (C) 2005, 2006 Percy Leonhardt Copyright (C) 2009, 2010 John Stamp KNemo is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. KNemo 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include -#include #include #include #include "global.h" #include "interface.h" #include "interfacestatistics.h" #include "statisticsmodel.h" #include "syncstats/statsfactory.h" #include "storage/sqlstorage.h" #include "storage/xmlstorage.h" static bool statsLessThan( const StatsRule& s1, const StatsRule& s2 ) { if ( s1.startDate < s2.startDate ) return true; else return false; } InterfaceStatistics::InterfaceStatistics( Interface* interface ) : QObject(), mInterface( interface ), mSaveTimer( new QTimer() ), mWarnTimer( new QTimer() ), mEntryTimer( new QTimer() ), mTrafficChanged( false ) { StatisticsModel * s = new StatisticsModel( KNemoStats::Hour, this ); mModels.insert( KNemoStats::Hour, s ); s = new StatisticsModel( KNemoStats::Day, this ); mModels.insert( KNemoStats::Day, s ); s = new StatisticsModel( KNemoStats::Week, this ); mModels.insert( KNemoStats::Week, s ); s = new StatisticsModel( KNemoStats::Month, this ); mModels.insert( KNemoStats::Month, s ); s = new StatisticsModel( KNemoStats::Year, this ); mModels.insert( KNemoStats::Year, s ); s = new StatisticsModel( KNemoStats::BillPeriod, this ); mModels.insert( KNemoStats::BillPeriod, s ); s = new StatisticsModel( KNemoStats::HourArchive, this ); mModels.insert( KNemoStats::HourArchive, s ); foreach ( StatisticsModel *s, mModels ) { mStorageData.saveFromId.insert( s->periodType(), 0 ); } connect( mSaveTimer, SIGNAL( timeout() ), this, SLOT( saveStatistics() ) ); connect( mWarnTimer, SIGNAL( timeout() ), this, SLOT( checkWarnings() ) ); connect( mEntryTimer, SIGNAL( timeout() ), this, SLOT( checkValidEntry() ) ); QUrl dir( generalSettings->statisticsDir ); sql = new SqlStorage( mInterface->ifaceName() ); loadStats(); syncWithExternal( mStorageData.lastSaved ); configChanged(); } InterfaceStatistics::~InterfaceStatistics() { mSaveTimer->stop(); mWarnTimer->stop(); mEntryTimer->stop(); delete mSaveTimer; delete mWarnTimer; delete mEntryTimer; saveStatistics(); delete sql; QSqlDatabase::removeDatabase( mInterface->ifaceName() ); } void InterfaceStatistics::saveStatistics( bool fullSave ) { sql->saveStats( &mStorageData, &mModels, &mStatsRules, fullSave ); } bool InterfaceStatistics::loadStats() { QUrl dir( generalSettings->statisticsDir ); if ( !dir.isLocalFile() ) return 0; bool loaded = false; if ( sql->dbExists() ) { loaded = sql->loadStats( &mStorageData, &mModels, &mStatsRules ); qSort( mStatsRules.begin(), mStatsRules.end(), statsLessThan ); } else { XmlStorage xml; loaded = xml.loadStats( mInterface->ifaceName(), &mStorageData, &mModels ); sql->createDb(); if ( loaded ) { hoursToArchive( QDateTime::currentDateTime() ); checkRebuild( mStorageData.calendar->calendarSystem(), true ); } } if ( !mStorageData.calendar ) { mStorageData.calendar = KCalendarSystem::create( mInterface->settings().calendarSystem ); foreach( StatisticsModel * s, mModels ) { s->setCalendar( mStorageData.calendar ); } } return loaded; } /********************************** * Stats Entry Generators * **********************************/ void InterfaceStatistics::resetWarnings( int modelType ) { for ( int i = 0; i < mInterface->settings().warnRules.count(); ++i ) { if ( modelType == mInterface->settings().warnRules[i].periodUnits ) mInterface->settings().warnRules[i].warnDone = false; } } void InterfaceStatistics::hoursToArchive( const QDateTime &dateTime ) { bool removedRow = false; StatisticsModel* hours = mModels.value( KNemoStats::Hour ); StatisticsModel* hourArchives = mModels.value( KNemoStats::HourArchive ); // Only 24 hours while ( hours->rowCount() ) { if ( hours->dateTime( 0 ) <= dateTime.addDays( -1 ) ) { QList row = hours->takeRow( 0 ); hourArchives->appendRow( row ); hourArchives->setId( mStorageData.nextHourId ); mStorageData.nextHourId++; removedRow = true; } else break; } if ( removedRow ) { for ( int i = 0; i < hours->rowCount(); ++i ) { hours->setId( i, i ); } mStorageData.saveFromId.insert( hours->periodType(), 0 ); mStorageData.saveFromId.insert( hourArchives->periodType(), hourArchives->id( 0 ) ); } } void InterfaceStatistics::genNewHour( const QDateTime &dateTime ) { hoursToArchive( dateTime ); StatisticsModel* hours = mModels.value( KNemoStats::Hour ); if ( hours->dateTime() == dateTime ) return; int ruleIndex = ruleForDate( dateTime.date() ); hours->createEntry( dateTime ); if ( ruleIndex >= 0 && isOffpeak( mStatsRules[ruleIndex], dateTime ) ) { hours->addTrafficType( KNemoStats::OffpeakTraffic ); } resetWarnings( hours->periodType() ); } bool InterfaceStatistics::genNewCalendarType( const QDate &date, const KNemoStats::PeriodUnits stype ) { if ( stype < KNemoStats::Day || stype > KNemoStats::Year ) return false; StatisticsModel * model = mModels.value( stype ); if ( model->rowCount() && model->date().addDays( model->days() ) > date ) return false; QDate newDate; int dayOf; int weekStartDay = mStorageData.calendar->weekStartDay(); switch ( stype ) { case KNemoStats::Day: newDate = date; break; case KNemoStats::Week: dayOf = mStorageData.calendar->dayOfWeek( date ); if ( dayOf >= weekStartDay ) newDate = date.addDays( weekStartDay - dayOf ); else newDate = date.addDays( weekStartDay - mStorageData.calendar->daysInWeek( date ) - dayOf ); break; case KNemoStats::Month: dayOf = mStorageData.calendar->day( date ); newDate = date.addDays( 1 - dayOf ); break; case KNemoStats::Year: dayOf = mStorageData.calendar->dayOfYear( date ); newDate = date.addDays( 1 - dayOf ); break; default: return false; } mModels.value( stype )->createEntry( QDateTime( newDate, QTime() ) ); resetWarnings( stype ); return true; } // Return true if at least one daily statistic entry is in a span of days bool InterfaceStatistics::daysInSpan( const QDate& date, int days ) { StatisticsModel *model = mModels.value( KNemoStats::Day ); if ( !model->rowCount() ) return false; QDate nextRuleStart = date.addDays( days ); for ( int i = model->rowCount() - 1; i >= 0; --i ) { // No others will be valid after this; stop early if ( model->date( i ) < date ) return false; if ( model->date( i ) < nextRuleStart && model->date( i ) >= date ) return true; } return false; } QDate InterfaceStatistics::nextBillPeriodStart( const StatsRule &rules, const QDate &date ) { QDate nextDate; QDate refDay; int modelType = rules.periodUnits; switch ( modelType ) { case KNemoStats::Day: nextDate = date.addDays( rules.periodCount ); break; case KNemoStats::Week: nextDate = date; for ( int i = 0; i < rules.periodCount; ++i ) nextDate = nextDate.addDays( mStorageData.calendar->daysInWeek( nextDate ) ); break; default:// KNemoStats::Month: nextDate = mStorageData.calendar->addMonths( date, rules.periodCount ); // Example: one month starting Jan 31 = Jan 31 -> Mar 1 // This seems the most common way to handle late start dates if ( mStorageData.calendar->day( nextDate ) < mStorageData.calendar->day( date ) ) nextDate = nextDate.addDays( 1 ); break; } return nextDate; } void InterfaceStatistics::genNewBillPeriod( const QDate &date ) { int ruleIndex = ruleForDate( date ); if ( ruleIndex < 0 ) return; StatisticsModel * billing = mModels.value( KNemoStats::BillPeriod ); QDate nextRuleStart; if ( mStatsRules.count() > ruleIndex+1 ) nextRuleStart = mStatsRules.at( ruleIndex+1 ).startDate; // Harder to find whether we should skip generating a new billing entry if ( nextRuleStart.isValid() && billing->rowCount() && billing->date().addDays( billing->days() ) >= nextRuleStart ) return; int days; // Given a calendar day and a billing period start date, find a // billing period that the day belongs in. QDate newDate; QDate nextStartDate; if ( !billing->rowCount() || billing->date() < mStatsRules.at( ruleIndex ).startDate ) { nextStartDate = mStatsRules.at( ruleIndex ).startDate; } else { nextStartDate = billing->date(); } do { newDate = nextStartDate; nextStartDate = nextBillPeriodStart( mStatsRules.at( ruleIndex ), newDate ); days = newDate.daysTo( nextStartDate ); } while ( nextStartDate <= date || !daysInSpan( newDate, days ) ); // Truncate a billing period if necessary if ( nextRuleStart.isValid() && nextRuleStart < nextStartDate ) days = newDate.daysTo( nextRuleStart ); if ( billing->rowCount() && newDate == billing->date() ) return; billing->createEntry( QDateTime( newDate, QTime() ), billing->rowCount(), days ); resetWarnings( KNemoStats::BillPeriod ); } // END STATS ENTRY GENERATORS void InterfaceStatistics::configChanged() { mSaveTimer->stop(); mWarnTimer->stop(); KLocale::CalendarSystem origCalendarSystem = KLocale::QDateCalendar; if ( mStorageData.calendar ) origCalendarSystem = mStorageData.calendar->calendarSystem(); if ( mInterface->settings().calendarSystem != origCalendarSystem ) { mStorageData.calendar = KCalendarSystem::create( mInterface->settings().calendarSystem ); foreach( StatisticsModel * s, mModels ) { s->setCalendar( mStorageData.calendar ); } if ( mStorageData.calendar ) { StatisticsModel *hours = mModels.value( KNemoStats::Hour ); StatisticsModel *days = mModels.value( KNemoStats::Day ); for ( int i = 0; i < days->rowCount(); ++i ) { days->updateDateText( i ); } for ( int i = 0; i < hours->rowCount(); ++i ) { hours->updateDateText( i ); } } } checkRebuild( origCalendarSystem ); if ( generalSettings->saveInterval > 0 ) { mSaveTimer->setInterval( generalSettings->saveInterval * 1000 ); mSaveTimer->start(); } foreach ( StatisticsModel * s, mModels ) { resetWarnings( s->periodType() ); } checkValidEntry(); mWarnTimer->setInterval( 2000 ); mWarnTimer->start(); } int InterfaceStatistics::ruleForDate( const QDate &date ) { for( int i = mStatsRules.count() - 1; i >= 0; --i ) { if ( date >= mStatsRules[i].startDate ) return i; } return -1; } void InterfaceStatistics::syncWithExternal( uint updated ) { ExternalStats *v = StatsFactory::stats( mInterface, mStorageData.calendar ); if ( !v ) return; v->importIfaceStats(); const StatisticsModel *syncDays = v->days(); const StatisticsModel *syncHours = v->hours(); StatisticsModel *days = mModels.value( KNemoStats::Day ); StatisticsModel *hours = mModels.value( KNemoStats::Hour ); QDateTime curDateTime = QDateTime( QDate::currentDate(), QTime( QDateTime::currentDateTime().time().hour(), 0 ) ); for ( int i = 0; i < syncHours->rowCount(); ++i ) { QDateTime syncDateTime = syncHours->dateTime( i ); if ( hours->rowCount() && hours->dateTime() > syncDateTime ) continue; if ( !hours->rowCount() || hours->dateTime() < syncDateTime ) genNewHour( syncDateTime ); foreach ( KNemoStats::TrafficType t, hours->trafficTypes() ) { hours->addRxBytes( syncHours->rxBytes( i ), t ); hours->addTxBytes( syncHours->txBytes( i ), t ); } } for ( int i = 0; i < syncDays->rowCount(); ++i ) { QDate syncDate = syncDays->date( i ); if ( days->rowCount() && days->date() > syncDate ) continue; if ( !days->rowCount() || days->date() < syncDate ) { genNewCalendarType( syncDate, KNemoStats::Day ); genNewCalendarType( syncDate, KNemoStats::Week ); genNewCalendarType( syncDate, KNemoStats::Month ); genNewCalendarType( syncDate, KNemoStats::Year ); genNewBillPeriod( syncDate ); } foreach( StatisticsModel * s, mModels ) { if ( s->periodType() == KNemoStats::Hour || s->periodType() == KNemoStats::HourArchive ) continue; s->addRxBytes( v->addBytes( s->rxBytes(), syncDays->rxBytes( i ) ) ); s->addTxBytes( v->addBytes( s->txBytes(), syncDays->txBytes( i ) ) ); for ( int j = hours->rowCount() - 1; j >= 0; --j ) { if ( hours->date( j ) == syncDate ) { foreach( KNemoStats::TrafficType t, hours->trafficTypes( j ) ) { if ( t == KNemoStats::AllTraffic ) continue; s->addRxBytes( hours->rxBytes( j, t ), t ); s->addTxBytes( hours->txBytes( j, t ), t ); } } else if ( hours->date( j ) < syncDate ) break; } } } StatsPair lag = v->addLagged( updated, days ); if ( lag.rxBytes > 0 || lag.txBytes > 0 ) { if ( lag.rxBytes || lag.txBytes ) { genNewHour( curDateTime ); genNewCalendarType( curDateTime.date(), KNemoStats::Day ); genNewCalendarType( curDateTime.date(), KNemoStats::Week ); genNewCalendarType( curDateTime.date(), KNemoStats::Month ); genNewCalendarType( curDateTime.date(), KNemoStats::Year ); genNewBillPeriod( curDateTime.date() ); foreach ( StatisticsModel * s, mModels ) { if ( s->periodType() == KNemoStats::HourArchive ) continue; foreach ( KNemoStats::TrafficType t, hours->trafficTypes() ) { s->addRxBytes( lag.rxBytes, t ); s->addTxBytes( lag.txBytes, t ); } } } } delete v; } bool InterfaceStatistics::isOffpeak( const StatsRule &rules, const QDateTime &curDT ) { if ( !rules.logOffpeak ) return false; bool isOffpeak = false; QTime curHour = QTime( curDT.time().hour(), 0 ); // This block just tests weekly hours if ( rules.offpeakStartTime < rules.offpeakEndTime && curHour >= rules.offpeakStartTime && curHour < rules.offpeakEndTime ) { isOffpeak = true; } else if ( rules.offpeakStartTime > rules.offpeakEndTime && ( curHour >= rules.offpeakStartTime || curHour < rules.offpeakEndTime ) ) { isOffpeak = true; } if ( rules.weekendIsOffpeak ) { int dow = mStorageData.calendar->dayOfWeek( curDT.date() ); if ( rules.weekendDayStart <= rules.weekendDayEnd && rules.weekendDayStart <= dow ) { QDateTime dayBegin = curDT.addDays( dow - rules.weekendDayStart ); dayBegin = QDateTime( dayBegin.date(), rules.weekendTimeStart ); QDateTime end = curDT.addDays( rules.weekendDayEnd - dow ); end = QDateTime( end.date(), rules.weekendTimeEnd ); if ( dayBegin <= curDT && curDT < end ) isOffpeak = true; } else if ( rules.weekendDayStart > rules.weekendDayEnd && ( dow >= rules.weekendDayStart || dow <= rules.weekendDayEnd ) ) { QDateTime dayBegin = curDT.addDays( rules.weekendDayStart - dow ); dayBegin = QDateTime( dayBegin.date(), rules.weekendTimeStart ); QDateTime end = curDT.addDays( mStorageData.calendar->daysInWeek( curDT.date() ) - dow + rules.weekendDayEnd ); end = QDateTime( end.date(), rules.weekendTimeEnd ); if ( dayBegin <= curDT && curDT < end ) isOffpeak = true; } } return isOffpeak; } /************************************** * Rebuilding Statistics * **************************************/ int InterfaceStatistics::rebuildHours( StatisticsModel *s, const StatsRule &rules, const QDate &start, const QDate &nextRuleStart ) { if ( !s->rowCount() ) return 0; int i = s->rowCount(); while ( i > 0 && s->date( i - 1 ) >= start ) { i--; if ( nextRuleStart.isValid() && s->date( i ) >= nextRuleStart ) continue; s->resetTrafficTypes( i ); if ( isOffpeak( rules, s->dateTime( i ) ) ) { s->setTraffic( i, s->rxBytes( i ), s->txBytes( i ), KNemoStats::OffpeakTraffic ); s->addTrafficType( KNemoStats::OffpeakTraffic, i ); } } if ( mStorageData.saveFromId.value( s->periodType() ) > s->id( i ) ) { mStorageData.saveFromId.insert( s->periodType(), s->id( i ) ); } return i; } int InterfaceStatistics::rebuildDay( int dayIndex, int hourIndex, StatisticsModel *hours ) { QMap > dayTraffic; StatisticsModel *days = mModels.value( KNemoStats::Day ); while ( hourIndex >= 0 && hours->date( hourIndex ) > days->date( dayIndex ).addDays( 1 ) ) { --hourIndex; } while ( hourIndex >= 0 && hours->date( hourIndex ) == days->date( dayIndex ) ) { foreach ( KNemoStats::TrafficType t, hours->trafficTypes( hourIndex ) ) { if ( t == KNemoStats::AllTraffic ) continue; quint64 rx = hours->rxBytes( hourIndex, t ) + dayTraffic.value( t ).first; quint64 tx = hours->txBytes( hourIndex, t ) + dayTraffic.value( t ).second; dayTraffic.insert( t, QPair( rx, tx ) ); } --hourIndex; } foreach (KNemoStats::TrafficType t, dayTraffic.keys() ) { days->setTraffic( dayIndex, dayTraffic.value( t ).first, dayTraffic.value( t ).second, t ); days->addTrafficType( t, dayIndex ); } return hourIndex; } // A rebuild of hours and days never changes the number of entries // We just change what bytes count as off-peak void InterfaceStatistics::rebuildBaseUnits( const StatsRule &rules, const QDate &start, const QDate &nextRuleStart ) { int hIndex = 0; int haIndex = 0; StatisticsModel *hours = mModels.value( KNemoStats::Hour ); StatisticsModel *hourArchives = mModels.value( KNemoStats::HourArchive ); StatisticsModel *days = mModels.value( KNemoStats::Day ); sql->loadHourArchives( hourArchives, start, nextRuleStart ); if ( hourArchives->rowCount() ) mStorageData.saveFromId.insert( hourArchives->periodType(), hourArchives->id( 0 ) ); rebuildHours( hourArchives, rules, start, nextRuleStart ); rebuildHours( hours, rules, start, nextRuleStart ); if ( hours->rowCount() ) hIndex = hours->rowCount() - 1; if ( hourArchives->rowCount() ) haIndex = hourArchives->rowCount() - 1; if ( !days->rowCount() ) return; int dayIndex = days->rowCount(); while ( dayIndex > 0 && days->date( dayIndex - 1 ) >= start ) { dayIndex--; if ( nextRuleStart.isValid() && days->date( dayIndex ) >= nextRuleStart ) continue; days->resetTrafficTypes( dayIndex ); if ( rules.logOffpeak ) { haIndex = rebuildDay( dayIndex, haIndex, hourArchives ); hIndex = rebuildDay( dayIndex, hIndex, hours ); } } if ( mStorageData.saveFromId.value( days->periodType() ) > days->id( dayIndex ) ) { mStorageData.saveFromId.insert( days->periodType(), days->id( dayIndex ) ); } } /** * Given a model with statistics of a certain unit (year, month, week, etc.) * and a requested rebuild date, how far back to we actually need to go * to accuratly rebuild statistics from the daily stats. */ QDate InterfaceStatistics::prepareRebuild( StatisticsModel* statistics, const QDate &startDate ) { QDate newStartDate = startDate; if ( statistics->periodType() <= KNemoStats::Day || statistics->periodType() > KNemoStats::Year ) return newStartDate; for ( int i = 0; i < statistics->rowCount(); ++i ) { int days = statistics->days( i ); QDate nextPeriodStart = statistics->date( i ).addDays( days ); if ( statistics->periodType() == KNemoStats::BillPeriod ) { // Have to check if a billing period's truncation changed int ruleIndex = ruleForDate( statistics->date( i ) ); if ( ruleIndex < 0 ) break; QDate nextFullPeriodStart = nextBillPeriodStart( mStatsRules.at( ruleIndex ), statistics->date( i ) ); if ( nextFullPeriodStart > nextPeriodStart ) { if ( mStatsRules.count() == ruleIndex+1 || mStatsRules.at( ruleIndex + 1 ).startDate != nextPeriodStart ) { // Truncation changed // This will make sure the entry gets rebuilt nextPeriodStart = nextFullPeriodStart; } } } if ( nextPeriodStart > startDate ) { if ( statistics->date( i ) < startDate ) { newStartDate = statistics->date( i ); } if ( statistics->rowCount() && mStorageData.saveFromId.value( statistics->periodType() ) > statistics->id( i ) ) { mStorageData.saveFromId.insert( statistics->periodType(), statistics->id( i ) ); } statistics->removeRows( i, statistics->rowCount() - i ); break; } } return newStartDate; } void InterfaceStatistics::amendStats( int i, const StatisticsModel *source, StatisticsModel* dest ) { foreach ( KNemoStats::TrafficType t, source->trafficTypes( i ) ) { dest->addRxBytes( source->rxBytes( i, t ), t ); dest->addTxBytes( source->txBytes( i, t ), t ); dest->addTrafficType( t ); } } void InterfaceStatistics::rebuildCalendarPeriods( const QDate &requestedStart, bool weekOnly ) { QDate weekStart; QDate monthStart; QDate walkbackDate; QList s; weekStart = prepareRebuild( mModels.value( KNemoStats::Week), requestedStart ); s.append( weekStart ); if ( !weekOnly ) { monthStart = prepareRebuild( mModels.value( KNemoStats::Month), requestedStart ); s.append( monthStart ); } // Now find how far back we'll need to go qSort( s ); walkbackDate = s.first(); StatisticsModel *days = mModels.value( KNemoStats::Day ); for ( int i = 0; i < days->rowCount(); ++i ) { QDate day = days->date( i ); if ( day < walkbackDate ) continue; if ( day >= weekStart ) { genNewCalendarType( day, KNemoStats::Week ); amendStats( i, mModels.value( KNemoStats::Day ), mModels.value( KNemoStats::Week ) ); } if ( !weekOnly && day >= monthStart ) { genNewCalendarType( day, KNemoStats::Month ); amendStats( i, mModels.value( KNemoStats::Day ), mModels.value( KNemoStats::Month ) ); } } if ( weekOnly ) return; // Build years from months...save time QDate yearStart = prepareRebuild( mModels.value( KNemoStats::Year ), requestedStart ); StatisticsModel *months = mModels.value( KNemoStats::Month ); for ( int i = 0; i < months->rowCount(); ++i ) { QDate day = months->date( i ); if ( day < yearStart ) continue; genNewCalendarType( day, KNemoStats::Year ); amendStats( i, mModels.value( KNemoStats::Month ), mModels.value( KNemoStats::Year ) ); } } void InterfaceStatistics::rebuildBillPeriods( const QDate &requestedStart ) { QDate walkbackDate; StatisticsModel *days = mModels.value( KNemoStats::Day ); StatisticsModel *billPeriods = mModels.value( KNemoStats::BillPeriod ); if ( billPeriods->rowCount() ) walkbackDate = prepareRebuild( mModels.value( KNemoStats::BillPeriod), requestedStart ); else walkbackDate = days->date( 0 ); for ( int i = 0; i < days->rowCount(); ++i ) { QDate day = days->date( i ); if ( day >= walkbackDate ) { genNewBillPeriod( day ); amendStats( i, mModels.value( KNemoStats::Day ), mModels.value( KNemoStats::BillPeriod ) ); } } } void InterfaceStatistics::prependStatsRule( QList &rules ) { qSort( rules.begin(), rules.end(), statsLessThan ); StatisticsModel * days = mModels.value( KNemoStats::Day ); if ( rules.count() == 0 || ( days->rowCount() > 0 && rules[0].startDate > days->date( 0 ) ) ) { QDate date; if ( days->rowCount() ) date = days->date( 0 ); else date = QDate::currentDate(); StatsRule s; s.startDate = date.addDays( 1 - mStorageData.calendar->day( date ) ); rules.prepend( s ); } } void InterfaceStatistics::checkRebuild( const KLocale::CalendarSystem oldCalendar, bool force ) { QList newRules = mInterface->settings().statsRules; bool forceWeek = false; if ( oldCalendar != mInterface->settings().calendarSystem ) { StatisticsModel *hours = mModels.value( KNemoStats::Hour ); StatisticsModel *days = mModels.value( KNemoStats::Day ); for ( int i = 0; i < days->rowCount(); ++i ) { days->updateDateText( i ); } for ( int i = 0; i < hours->rowCount(); ++i ) { hours->updateDateText( i ); } force = true; } if ( mModels.value( KNemoStats::Week )->rowCount() ) { QDate testDate = mModels.value( KNemoStats::Week )->date( 0 ); if ( mStorageData.calendar->dayOfWeek( testDate ) != mStorageData.calendar->weekStartDay() ) forceWeek = true; } bool doBilling = newRules.count(); int oldRuleCount = mStatsRules.count(); QDate bpBeginDate; if ( !doBilling ) { mModels.value( KNemoStats::BillPeriod )->clearRows(); mStorageData.saveFromId.insert( KNemoStats::BillPeriod, 0 ); } // This is just a dummy for calculation prependStatsRule( newRules ); prependStatsRule( mStatsRules ); if ( !oldRuleCount && mStatsRules[0] == newRules[0] && newRules.count() > mStatsRules.count() ) bpBeginDate = mModels.value( KNemoStats::Day )->date( 0 ); int j = 0; QDate recalcPos; for ( int i = 0; i < newRules.count(); ++i ) { bool rulesMatch = ( newRules[i] == mStatsRules[j] ); QDate nextRuleStart; if ( !rulesMatch ) { if ( newRules.count() > i + 1 ) nextRuleStart = newRules[i+1].startDate; if ( !recalcPos.isValid() ) recalcPos = newRules[i].startDate; rebuildBaseUnits( newRules[i], newRules[i].startDate, nextRuleStart ); } else { // rules match, now scan forward to see if we need to extend new rule if ( newRules.count() > i + 1 ) { int first = -1; int k; // Here we want to skip over any intermediary old rules that will // get taken care of when we recalculate this section. for ( k = 0; k < mStatsRules.count(); ++k ) { if ( mStatsRules[k].startDate > newRules[i].startDate && mStatsRules[k].startDate < newRules[i+1].startDate ) { if ( first < 0 ) first = k; j = k; if ( !recalcPos.isValid() ) recalcPos = mStatsRules[j].startDate; } } if ( first >= 0 ) { rebuildBaseUnits( newRules[i], mStatsRules[first].startDate, newRules[i+1].startDate ); } } // We're out of new rules but there's more old ones // so rebuild from next old rule's date using final new rule. else if ( mStatsRules.count() > j + 1 ) { if ( !recalcPos.isValid() ) recalcPos = mStatsRules[j+1].startDate; rebuildBaseUnits( newRules[i], recalcPos, nextRuleStart ); } if ( mStatsRules.count() > j + 1 ) ++j; } } /* now do the rest */ mStatsRules = newRules; if ( force ) recalcPos = mModels.value( KNemoStats::Day )->date( 0 ); if ( recalcPos.isValid() ) { rebuildCalendarPeriods( recalcPos ); if ( doBilling ) { rebuildBillPeriods( recalcPos ); } } else if ( forceWeek ) { rebuildCalendarPeriods( mModels.value( KNemoStats::Day )->date( 0 ), true ); } mStatsRules = mInterface->settings().statsRules; if ( mStatsRules.count() ) prependStatsRule( mStatsRules ); if ( recalcPos.isValid() ) { saveStatistics( true ); } mTrafficChanged = true; emit currentEntryChanged(); } // END REBUILDING STATISTICS void InterfaceStatistics::checkValidEntry() { mEntryTimer->stop(); QDateTime curDateTime = QDateTime::currentDateTime(); QDate curDate = curDateTime.date(); StatisticsModel *days = mModels.value( KNemoStats::Day ); StatisticsModel *hours = mModels.value( KNemoStats::Hour ); if ( !hours->rowCount() || hours->dateTime().addSecs( 3600 ) <= curDateTime ) { genNewHour( QDateTime( curDate, QTime( curDateTime.time().hour(), 0 ) ) ); } if ( !days->rowCount() || days->date() < curDate ) { genNewCalendarType( curDate, KNemoStats::Day ); genNewCalendarType( curDate, KNemoStats::Week ); genNewCalendarType( curDate, KNemoStats::Month ); genNewCalendarType( curDate, KNemoStats::Year ); genNewBillPeriod( curDate ); // The fancy short date may need updating for ( int i = 0; i < hours->rowCount(); ++i ) hours->updateDateText( i ); } foreach ( StatisticsModel * s, mModels ) { if ( s->periodType() == KNemoStats::HourArchive || s->periodType() == KNemoStats::Hour ) continue; foreach ( KNemoStats::TrafficType t, hours->trafficTypes() ) { s->addTrafficType( t ); } } QDateTime ndt = curDateTime.addSecs( 3600 - curDateTime.time().minute()*60 - curDateTime.time().second() ); int secs = curDateTime.secsTo( ndt ); mEntryTimer->setInterval( secs * 1000 ); mEntryTimer->start(); } void InterfaceStatistics::checkWarnings() { if ( !mTrafficChanged ) return; mTrafficChanged = false; QList warn = mInterface->settings().warnRules; for ( int wi=0; wi < warn.count(); ++wi ) { if ( warn[wi].warnDone || !warn[wi].threshold > 0.0 ) continue; quint64 total = 0; StatisticsModel *model = 0; model = mModels.value( warn[wi].periodUnits ); if ( !model ) return; int lowerIndex = model->rowCount() - warn[wi].periodCount; for ( int i = model->rowCount() - 1; i >= 0; --i ) { if ( i >= lowerIndex ) { switch ( warn[wi].trafficDirection ) { case KNemoStats::TrafficIn: if ( warn[wi].trafficType == KNemoStats::PeakOffpeak ) total += model->rxBytes( i ); else if ( warn[wi].trafficType == KNemoStats::Offpeak ) total += model->rxBytes( i, KNemoStats::OffpeakTraffic ); else total += model->rxBytes( i ) - model->rxBytes( i, KNemoStats::OffpeakTraffic ); break; case KNemoStats::TrafficOut: if ( warn[wi].trafficType == KNemoStats::PeakOffpeak ) total += model->txBytes( i ); else if ( warn[wi].trafficType == KNemoStats::Offpeak ) total += model->txBytes( i, KNemoStats::OffpeakTraffic ); else total += model->txBytes( i ) - model->txBytes( i, KNemoStats::OffpeakTraffic ); break; default: if ( warn[wi].trafficType == KNemoStats::PeakOffpeak ) total += model->totalBytes( i ); else if ( warn[wi].trafficType == KNemoStats::Offpeak ) total += model->totalBytes( i, KNemoStats::OffpeakTraffic ); else total += model->totalBytes( i ) - model->totalBytes( i, KNemoStats::OffpeakTraffic ); } } else break; } int warnMult = pow( 1024, warn[wi].trafficUnits ); quint64 thresholdBytes = warn[wi].threshold * warnMult; if ( total > thresholdBytes ) { emit warnTraffic( warn[wi].customText, thresholdBytes, total ); mInterface->settings().warnRules[wi].warnDone = true; } } } /****************************** * Public Interface * ******************************/ void InterfaceStatistics::clearStatistics() { foreach( StatisticsModel * s, mModels ) s->clearRows(); mStorageData.nextHourId = 0; foreach ( StatisticsModel *s, mModels ) { mStorageData.saveFromId.insert( s->periodType(), 0 ); } sql->clearStats( &mStorageData ); checkValidEntry(); mTrafficChanged = true; emit currentEntryChanged(); } void InterfaceStatistics::addRxBytes( unsigned long bytes ) { if ( bytes == 0 ) return; foreach( StatisticsModel * s, mModels ) { if ( s->periodType() == KNemoStats::HourArchive ) continue; foreach ( KNemoStats::TrafficType t, mModels.value( KNemoStats::Hour )->trafficTypes() ) { s->addRxBytes( bytes, t ); } } mTrafficChanged = true; emit currentEntryChanged(); } void InterfaceStatistics::addTxBytes( unsigned long bytes ) { if ( bytes == 0 ) return; foreach( StatisticsModel * s, mModels ) { if ( s->periodType() == KNemoStats::HourArchive ) continue; foreach ( KNemoStats::TrafficType t, mModels.value( KNemoStats::Hour )->trafficTypes() ) { s->addTxBytes( bytes, t ); } } mTrafficChanged = true; emit currentEntryChanged(); } #include "moc_interfacestatistics.cpp" diff --git a/src/knemod/interfacestatusdialog.h b/src/knemod/interfacestatusdialog.h index 5b298da..f2dbc1b 100644 --- a/src/knemod/interfacestatusdialog.h +++ b/src/knemod/interfacestatusdialog.h @@ -1,81 +1,82 @@ /* This file is part of KNemo Copyright (C) 2004, 2006 Percy Leonhardt Copyright (C) 2009, 2010 John Stamp KNemo is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. KNemo 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef INTERFACESTATUSDIALOG_H #define INTERFACESTATUSDIALOG_H #include +#include #include "ui_interfacestatusdlg.h" class Interface; /** * This class serves as the main window for KNemo. It handles the * menus, toolbars, and status bars. * * @short Main window class * @author Percy Leonhardt */ class InterfaceStatusDialog : public QDialog { Q_OBJECT public: /** * Default Constructor */ InterfaceStatusDialog( Interface* interface, QWidget* parent = 0L ); /** * Default Destructor */ virtual ~InterfaceStatusDialog(); public Q_SLOTS: /** * Update the statistics tab when data changed */ void statisticsChanged(); void updateDialog(); void configChanged(); protected: bool event( QEvent *e ); private: void doAvailable( const BackendData* data ); void doConnected( const BackendData *data ); void doUp( const BackendData *data ); void doDisconnected( const BackendData *data ); void doDown(); void doUnavailable(); Ui::InterfaceStatusDlg ui; bool mWasShown; bool mSetPos; KSharedConfig::Ptr mConfig; Interface* mInterface; }; #endif // INTERFACESTATUSDIALOG_H diff --git a/src/knemod/interfacetray.cpp b/src/knemod/interfacetray.cpp index 9b69966..8c6e8d7 100644 --- a/src/knemod/interfacetray.cpp +++ b/src/knemod/interfacetray.cpp @@ -1,255 +1,256 @@ /* This file is part of KNemo Copyright (C) 2004, 2005 Percy Leonhardt Copyright (C) 2009, 2010 John Stamp KNemo is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. KNemo 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "global.h" #include "interfacetray.h" #ifdef __linux__ #include #endif #include #include #include #include #include #include #include #include +#include #include #include #include InterfaceTray::InterfaceTray( Interface* interface, const QString &id, QWidget* parent ) : KStatusNotifierItem( id, parent ) { mInterface = interface; setToolTipIconByName( QLatin1String("knemo") ); setCategory(Hardware); setStatus(Active); connect(this, SIGNAL(secondaryActivateRequested(QPoint)), this, SLOT(togglePlotter())); setupMappings(); QAction *quitAction = new QAction(this); quitAction->setText(KStatusNotifierItem::tr("Quit")); quitAction->setIcon(QIcon::fromTheme(QLatin1String("application-exit"))); QObject::connect(quitAction, SIGNAL(triggered()), this, SLOT(slotQuit())); // Replace the standard quit action addAction(QLatin1String("quit"), quitAction); } InterfaceTray::~InterfaceTray() { } void InterfaceTray::updateToolTip() { QString currentTip; QString title = mInterface->settings().alias; if ( title.isEmpty() ) title = mInterface->ifaceName(); title = i18n( "KNemo - %1", title ); if ( toolTipTitle() != title ) setToolTipTitle( title ); currentTip = toolTipData(); if ( currentTip != toolTipSubTitle() ) setToolTipSubTitle( currentTip ); } void InterfaceTray::slotQuit() { int autoStart = KMessageBox::questionYesNoCancel(0, i18n("Should KNemo start automatically when you login?"), i18n("Automatically Start KNemo?"), KGuiItem(i18n("Start")), KGuiItem(i18n("Do Not Start")), KStandardGuiItem::cancel(), QLatin1String("StartAutomatically")); - KSharedConfigPtr config = KSharedConfig::openConfig(); + KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup generalGroup( config, confg_general ); if ( autoStart == KMessageBox::Yes ) { generalGroup.writeEntry( conf_autoStart, true ); } else if ( autoStart == KMessageBox::No) { generalGroup.writeEntry( conf_autoStart, false ); } else // cancel chosen; don't quit return; config->sync(); qApp->quit(); } void InterfaceTray::activate(const QPoint&) { mInterface->showStatusDialog( false ); } void InterfaceTray::togglePlotter() { mInterface->showSignalPlotter( false ); } QString InterfaceTray::toolTipData() { QString tipData; int toolTipContent = generalSettings->toolTipContent; const BackendData * data = mInterface->backendData(); if ( !data ) return QString(); QString leftTags = QStringLiteral(""); QString centerTags = QStringLiteral(""); QString rightTags = QStringLiteral(""); tipData = QStringLiteral(""); if ( toolTipContent & INTERFACE ) tipData += leftTags + i18n( "Interface" ) + centerTags + mInterface->ifaceName() + rightTags; if ( toolTipContent & STATUS ) { tipData += leftTags + i18n( "Status" ) + centerTags; if ( data->status & KNemoIface::Connected ) tipData += i18n( "Connected" ); else if ( data->status & KNemoIface::Up ) tipData += i18n( "Disconnected" ); else if ( data->status & KNemoIface::Available ) tipData += i18n( "Down" ); else tipData += i18n( "Unavailable" ); tipData += rightTags; } if ( data->status & KNemoIface::Connected && toolTipContent & UPTIME ) { tipData += leftTags + i18n( "Connection time" ) + centerTags + mInterface->uptimeString() + rightTags ; } if ( data->status & KNemoIface::Up ) { QStringList keys = data->addrData.keys(); QString ip4Tip; QString ip6Tip; QString ptpaddress = i18n( "PtP Address" ); QString scope = i18n( "Scope & Flags" ); foreach ( QString key, keys ) { AddrData addrData = data->addrData.value( key ); if ( addrData.afType == AF_INET ) { if ( toolTipContent & IP_ADDRESS ) ip4Tip += leftTags + i18n( "IPv4 Address" ) + centerTags + key + rightTags; if ( toolTipContent & SCOPE ) ip4Tip += leftTags + scope + centerTags + mScope.value( addrData.scope ) + addrData.ipv6Flags + rightTags; if ( toolTipContent & BCAST_ADDRESS && !addrData.hasPeer ) ip4Tip += leftTags + i18n( "Broadcast Address" ) + centerTags + addrData.broadcastAddress + rightTags; else if ( toolTipContent & PTP_ADDRESS && addrData.hasPeer ) ip4Tip += leftTags + ptpaddress + centerTags + addrData.broadcastAddress + rightTags; } else { if ( toolTipContent & IP_ADDRESS ) ip6Tip += leftTags + i18n( "IPv6 Address" ) + centerTags + key + rightTags; if ( toolTipContent & SCOPE ) ip6Tip += leftTags + scope + centerTags + mScope.value( addrData.scope ) + rightTags; if ( toolTipContent & PTP_ADDRESS && addrData.hasPeer ) ip6Tip += leftTags + ptpaddress + centerTags + addrData.broadcastAddress + rightTags; } } tipData += ip4Tip + ip6Tip; if ( KNemoIface::Ethernet == data->interfaceType ) { if ( toolTipContent & GATEWAY ) { if ( !data->ip4DefaultGateway.isEmpty() ) tipData += leftTags + i18n( "IPv4 Default Gateway" ) + centerTags + data->ip4DefaultGateway + rightTags; if ( !data->ip6DefaultGateway.isEmpty() ) tipData += leftTags + i18n( "IPv6 Default Gateway" ) + centerTags + data->ip6DefaultGateway + rightTags; } } } if ( data->status & KNemoIface::Available ) { if ( toolTipContent & HW_ADDRESS ) tipData += leftTags + i18n( "MAC Address" ) + centerTags + data->hwAddress + rightTags; if ( toolTipContent & RX_PACKETS ) tipData += leftTags + i18n( "Packets Received" ) + centerTags + QString::number( data->rxPackets ) + rightTags; if ( toolTipContent & TX_PACKETS ) tipData += leftTags + i18n( "Packets Sent" ) + centerTags + QString::number( data->txPackets ) + rightTags; if ( toolTipContent & RX_BYTES ) tipData += leftTags + i18n( "Bytes Received" ) + centerTags + data->rxString + rightTags; if ( toolTipContent & TX_BYTES ) tipData += leftTags + i18n( "Bytes Sent" ) + centerTags + data->txString + rightTags; } if ( data->status & KNemoIface::Connected ) { if ( toolTipContent & DOWNLOAD_SPEED ) tipData += leftTags + i18n( "Download Speed" ) + centerTags + mInterface->rxRateStr() + rightTags; if ( toolTipContent & UPLOAD_SPEED ) tipData += leftTags + i18n( "Upload Speed" ) + centerTags + mInterface->txRateStr() + rightTags; } if ( data->status & KNemoIface::Connected && data->isWireless ) { if ( toolTipContent & ESSID ) tipData += leftTags + i18n( "ESSID" ) + centerTags + data->essid + rightTags; if ( toolTipContent & MODE ) tipData += leftTags + i18n( "Mode" ) + centerTags + data->mode + rightTags; if ( toolTipContent & FREQUENCY ) tipData += leftTags + i18n( "Frequency" ) + centerTags + data->frequency + rightTags; if ( toolTipContent & BIT_RATE ) tipData += leftTags + i18n( "Bit Rate" ) + centerTags + data->bitRate + rightTags; if ( toolTipContent & ACCESS_POINT ) tipData += leftTags + i18n( "Access Point" ) + centerTags + data->accessPoint + rightTags; if ( toolTipContent & LINK_QUALITY ) tipData += leftTags + i18n( "Link Quality" ) + centerTags + data->linkQuality + rightTags; #ifdef __linux__ if ( toolTipContent & NICK_NAME ) tipData += leftTags + i18n( "Nickname" ) + centerTags + data->nickName + rightTags; #endif if ( toolTipContent & ENCRYPTION ) { QString encryption = i18n( "Encryption" ); if ( data->isEncrypted == true ) { tipData += leftTags + encryption + centerTags + i18n( "active" ) + rightTags; } else { tipData += leftTags + encryption + centerTags + i18n( "off" ) + rightTags; } } } tipData += QLatin1String("
"); return tipData; } void InterfaceTray::setupMappings() { // Cannot make this data static as the i18n macro doesn't seem // to work when called to early i.e. before setting the catalogue. mScope.insert( RT_SCOPE_NOWHERE, i18nc( "ipv6 address scope", "none" ) ); mScope.insert( RT_SCOPE_HOST, i18nc( "ipv6 address scope", "host" ) ); mScope.insert( RT_SCOPE_LINK, i18nc( "ipv6 address scope", "link" ) ); mScope.insert( RT_SCOPE_SITE, i18nc( "ipv6 address scope", "site" ) ); mScope.insert( RT_SCOPE_UNIVERSE, i18nc( "ipv6 address scope", "global" ) ); } #include "moc_interfacetray.cpp" diff --git a/src/knemod/interfacetray.h b/src/knemod/interfacetray.h index f50349f..5ebb292 100644 --- a/src/knemod/interfacetray.h +++ b/src/knemod/interfacetray.h @@ -1,61 +1,60 @@ /* This file is part of KNemo Copyright (C) 2004, 2005 Percy Leonhardt Copyright (C) 2009, 2010 John Stamp KNemo is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. KNemo 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef INTERFACETRAY_H #define INTERFACETRAY_H #include "config-knemo.h" -#include #include #include "interface.h" class InterfaceTray : public KStatusNotifierItem { Q_OBJECT public: /** * Default Constructor */ InterfaceTray( Interface* interface, const QString &id, QWidget* parent = 0 ); /** * Default Destructor */ virtual ~InterfaceTray(); void updateToolTip(); public Q_SLOTS: void activate(const QPoint &pos); private: Interface* mInterface; QMap mScope; QString toolTipData(); void setupMappings(); private Q_SLOTS: void togglePlotter(); void slotQuit(); }; #endif // INTERFACETRAY_H diff --git a/src/knemod/statisticsview.cpp b/src/knemod/statisticsview.cpp index 9e4c492..f0a2e95 100644 --- a/src/knemod/statisticsview.cpp +++ b/src/knemod/statisticsview.cpp @@ -1,260 +1,262 @@ /* This file is part of KNemo Copyright (C) 2010 John Stamp KNemo is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. KNemo 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "statisticsview.h" #include "statisticsmodel.h" #include #include #include #include #include #include #include #include #include +#include + class StatsTip : public QLabel { public: StatsTip(); void showText( const bool followMouse, const QString &, QWidget * ); private: QTimer statTimer; void placeTip( const QPoint & ); void timeout(); protected: void paintEvent(QPaintEvent *e); void resizeEvent(QResizeEvent *e); }; StatsTip::StatsTip() : QLabel( 0, Qt::ToolTip ) { statTimer.setSingleShot( true ); connect ( &statTimer, SIGNAL( timeout() ), this, SLOT( hide() ) ); setForegroundRole(QPalette::ToolTipText); setBackgroundRole(QPalette::ToolTipBase); setStyleSheet( qApp->styleSheet() ); setPalette( qApp->palette() ); ensurePolished(); setMargin( 1 + style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth, 0, this ) ); } void StatsTip::showText( const bool followMouse, const QString & tip, QWidget * w ) { if ( tip != text() ) { setText( tip ); resize( sizeHint() ); } show(); if ( followMouse ) { placeTip( QCursor::pos() + QPoint( 2, 16 ) ); } else { QPoint center = w->rect().center(); center.setY( w->rect().height() * 0.4 ); QPoint half = QPoint( sizeHint().width()/2, sizeHint().height()/2 ); placeTip( w->mapToGlobal( center - half ) ); } } void StatsTip::placeTip( const QPoint & point ) { int screenNum; if ( QApplication::desktop()->isVirtualDesktop() ) screenNum = QApplication::desktop()->screenNumber( point ); else screenNum = QApplication::desktop()->screenNumber( static_cast(parent()) ); QRect screen = QApplication::desktop()->screenGeometry( screenNum ); QPoint p = point; if ( point.x() + width() > screen.width() ) p.setX( screen.width() - width() ); if ( point.x() < 0 ) p.setX( 0 ); if ( point.y() + height() > screen.height() ) p.setY( screen.height() - height() ); if ( p.y() < 0 ) p.setY( 0 ); move( p ); timeout(); } void StatsTip::paintEvent( QPaintEvent *e ) { QStylePainter p( this ); QStyleOptionFrame opt; opt.init( this ); p.drawPrimitive( QStyle::PE_PanelTipLabel, opt ); p.end(); QLabel::paintEvent( e ); } void StatsTip::resizeEvent( QResizeEvent *e ) { QStyleHintReturnMask frameMask; QStyleOption option; option.init( this ); if ( style()->styleHint( QStyle::SH_ToolTip_Mask, &option, this, &frameMask ) ) setMask( frameMask.region ); QLabel::resizeEvent( e ); } void StatsTip::timeout() { statTimer.start( 2000 ); } static StatsTip * statsTip = NULL; StatisticsView::StatisticsView( QWidget * parent ) : QTableView( parent ), mFollow( false ), mOffpeak( false ) { if ( !statsTip ) statsTip = new StatsTip(); } StatisticsView::~StatisticsView() { } void StatisticsView::setModel( QAbstractItemModel *m ) { QTableView::setModel( m ); - horizontalHeader()->setMovable( true ); + horizontalHeader()->setSectionsMovable( true ); connect( selectionModel(), SIGNAL( selectionChanged ( const QItemSelection &, const QItemSelection & ) ), this, SLOT( updateSum() ) ); } void StatisticsView::updateSum() { quint64 total = 0; foreach( QModelIndex i, selectionModel()->selectedIndexes() ) total += selectionModel()->model()->data( i, StatisticsModel::DataRole ).toULongLong(); totalString = KIO::convertSize( total ); quint64 offpeak = 0; quint64 peak = 0; if ( mOffpeak ) { foreach( QModelIndex i, selectionModel()->selectedIndexes() ) offpeak += selectionModel()->model()->data( i, StatisticsModel::DataRole + KNemoStats::OffpeakTraffic ).toULongLong(); offpeakString = KIO::convertSize( offpeak ); if ( total > offpeak ) peak = total - offpeak; peakString = KIO::convertSize( peak ); } } void StatisticsView::showSum( const QPoint &p ) { QString sumString; QString pStr = i18n( "Peak:" ); QString opStr = i18n( "Off-Peak:" ); QString tStr = i18n( "Total:" ); if ( mOffpeak ) sumString = QStringLiteral("
%1%2
%3%4
%5%6
"); else sumString = QStringLiteral("
%1%2
"); if ( selectionModel()->selectedIndexes().count() > 0 && selectionModel()->isSelected( indexAt( p ) ) ) { if ( mOffpeak ) statsTip->showText( mFollow, sumString.arg( pStr ).arg( peakString ) .arg( opStr ).arg( offpeakString ) .arg( tStr ).arg( totalString ), this ); else statsTip->showText( mFollow, sumString.arg( tStr ).arg( totalString ), this ); } else if ( indexAt( p ).isValid() ) { quint64 totalBytes = model()->data( indexAt( p ), StatisticsModel::DataRole ).toULongLong(); if ( mOffpeak ) { quint64 offpeakBytes = model()->data( indexAt( p ), StatisticsModel::DataRole + KNemoStats::OffpeakTraffic ).toULongLong(); quint64 peakBytes = 0; if ( totalBytes > offpeakBytes ) peakBytes = totalBytes - offpeakBytes; statsTip->showText( mFollow, sumString.arg( pStr ).arg( KIO::convertSize( peakBytes ) ) .arg( opStr ).arg( KIO::convertSize( offpeakBytes ) ) .arg( tStr ).arg( KIO::convertSize( totalBytes ) ), this ); } else { statsTip->showText( mFollow, sumString.arg( tStr ).arg( KIO::convertSize( totalBytes ) ), this ); } } else { statsTip->hide(); } } void StatisticsView::hideEvent( QHideEvent * e ) { statsTip->hide(); QTableView::hideEvent( e ); } void StatisticsView::mousePressEvent( QMouseEvent * e ) { mFollow = true; QTableView::mousePressEvent( e ); } void StatisticsView::keyPressEvent( QKeyEvent * e ) { mFollow = false; QTableView::keyPressEvent( e ); } bool StatisticsView::viewportEvent( QEvent * e ) { switch ( e->type() ) { case QEvent::HoverEnter: case QEvent::HoverMove: mFollow = true; showSum( static_cast(e)->pos() ); break; case QEvent::HoverLeave: statsTip->hide(); default: ;; } return QTableView::viewportEvent( e ); } #include "moc_statisticsview.cpp" diff --git a/src/knemod/storage/sqlstorage.cpp b/src/knemod/storage/sqlstorage.cpp index b2e35e5..9110689 100644 --- a/src/knemod/storage/sqlstorage.cpp +++ b/src/knemod/storage/sqlstorage.cpp @@ -1,571 +1,573 @@ /* This file is part of KNemo Copyright (C) 2010 John Stamp KNemo is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. KNemo 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "global.h" #include "statisticsmodel.h" #include "sqlstorage.h" #include "commonstorage.h" #include #include #include #include + +#include #include static const QString time_format( QLatin1String("hh:mm:ss") ); static const int current_db_version = 2; SqlStorage::SqlStorage( QString ifaceName ) : mValidDbVer( true ) , mIfaceName( ifaceName ) { QUrl dir( generalSettings->statisticsDir ); mDbPath = QString::fromLatin1( "%1%2%3.db" ).arg( dir.path() ).arg( statistics_prefix ).arg( mIfaceName ); QStringList drivers = QSqlDatabase::drivers(); if ( drivers.contains( QLatin1String("QSQLITE") ) ) db = QSqlDatabase::addDatabase( QLatin1String("QSQLITE"), mIfaceName ); mTypeMap.insert( KNemoStats::AllTraffic, QLatin1String("") ); mTypeMap.insert( KNemoStats::OffpeakTraffic, QLatin1String("_offpeak") ); if ( dbExists() && open() ) { // KNemo 0.7.4 didn't create tables on a new db. This lets us fix it // without forcing the user to intervene. if ( db.tables().isEmpty() ) createDb(); else migrateDb(); } } SqlStorage::~SqlStorage() { db.close(); } bool SqlStorage::dbExists() { QFile dbfile( mDbPath ); return dbfile.exists(); } bool SqlStorage::createDb() { bool ok = false; if ( !open() ) return ok; QSqlDatabase::database( mIfaceName ).transaction(); QSqlQuery qry( db ); QString qryStr = QLatin1String("CREATE TABLE IF NOT EXISTS general (id INTEGER PRIMARY KEY, version INTEGER,") + QLatin1String(" last_saved BIGINT, calendar TEXT, next_hour_id INTEGER );"); qry.exec( qryStr ); qryStr = QLatin1String("CREATE TABLE IF NOT EXISTS stats_rules (id INTEGER PRIMARY KEY, start_date DATETIME,") + QLatin1String(" period_units INTEGER, period_count INTEGER );"); qry.exec( qryStr ); qryStr = QLatin1String("CREATE TABLE IF NOT EXISTS stats_rules_offpeak (id INTEGER PRIMARY KEY,") + QLatin1String(" offpeak_start_time TEXT, offpeak_end_time TEXT,") + QLatin1String(" weekend_is_offpeak BOOLEAN, weekend_start_time TEXT, weekend_end_time TEXT,") + QLatin1String(" weekend_start_day INTEGER, weekend_end_day INTEGER );"); qry.exec( qryStr ); for ( int i = KNemoStats::Hour; i <= KNemoStats::HourArchive; ++i ) { foreach ( KNemoStats::TrafficType j, mTypeMap.keys() ) { QString dateTimeStr; qryStr = QLatin1String("CREATE TABLE IF NOT EXISTS %1s%2 (id INTEGER PRIMARY KEY,%3") + QLatin1String(" rx BIGINT, tx BIGINT );"); if ( j == KNemoStats::AllTraffic ) { dateTimeStr = QLatin1String(" datetime DATETIME,"); if ( i == KNemoStats::BillPeriod ) dateTimeStr += QLatin1String(" days INTEGER,"); } qryStr = qryStr.arg( periods.at( i ) ).arg( mTypeMap.value( j ) ).arg( dateTimeStr ); qry.exec( qryStr ); } } ok = QSqlDatabase::database( mIfaceName ).commit(); db.close(); return ok; } bool SqlStorage::loadHourArchives( StatisticsModel *hourArchive, const QDate &startDate, const QDate &nextStartDate ) { bool ok = false; if ( !open() ) return ok; QDateTime startDateTime = QDateTime( startDate, QTime() ); QDateTime nextStartDateTime = QDateTime( nextStartDate, QTime() ); QSqlDatabase::database( mIfaceName ).transaction(); QSqlQuery qry( db ); QString searchCol; QString startVal; QString endVal; foreach ( KNemoStats::TrafficType trafficType, mTypeMap.keys() ) { if ( trafficType == KNemoStats::AllTraffic ) { searchCol = QLatin1String("datetime"); startVal = startDateTime.toString( Qt::ISODate ); endVal = nextStartDateTime.toString( Qt::ISODate ); } else { searchCol = QLatin1String("id"); startVal = QString::number( hourArchive->id( 0 ) ); endVal = QString::number( hourArchive->id()+1 ); } QString qryStr = QLatin1String("SELECT * FROM %1s%2 WHERE %3 >= '%4'"); if ( nextStartDate.isValid() ) { qryStr += QLatin1String(" AND datetime < '%5'"); qryStr = qryStr.arg( periods.at( KNemoStats::HourArchive ) ) .arg( mTypeMap.value( trafficType ) ) .arg( searchCol ) .arg( startVal ) .arg( endVal ); } else { qryStr = qryStr.arg( periods.at( KNemoStats::HourArchive ) ) .arg( mTypeMap.value( trafficType ) ) .arg( searchCol ) .arg( startVal ); } qryStr += QLatin1String(" ORDER BY id;"); qry.exec( qryStr ); int cId = qry.record().indexOf( QLatin1String("id") ); int cRx = qry.record().indexOf( QLatin1String("rx") ); int cTx = qry.record().indexOf( QLatin1String("tx") ); int cDt = 0; if ( trafficType == KNemoStats::AllTraffic ) cDt = qry.record().indexOf( QLatin1String("datetime") ); while ( qry.next() ) { int id = qry.value( cId ).toInt(); if ( trafficType == KNemoStats::AllTraffic ) { hourArchive->createEntry( QDateTime::fromString( qry.value( cDt ).toString(), Qt::ISODate ), id ); } hourArchive->setTraffic( hourArchive->indexOfId( id ), qry.value( cRx ).toULongLong(), qry.value( cTx ).toULongLong(), trafficType ); hourArchive->addTrafficType( trafficType, hourArchive->indexOfId( id ) ); } } ok = QSqlDatabase::database( mIfaceName ).commit(); db.close(); return ok; } bool SqlStorage::migrateDb() { bool ok = false; if ( !open() ) return ok; QSqlDatabase::database( mIfaceName ).transaction(); QSqlQuery qry( db ); qry.exec( QLatin1String("SELECT * FROM general;") ); if ( qry.next() ) { int dbVersion = qry.value( qry.record().indexOf( QLatin1String("version") ) ).toInt(); if ( dbVersion > current_db_version ) { mValidDbVer = false; QSqlDatabase::database( mIfaceName ).commit(); db.close(); KMessageBox::error( NULL, i18n( "The statistics database for interface \"%1\" is incompatible with this version of KNemo.\n\nPlease upgrade to a more recent KNemo release.", mIfaceName ) ); return false; } if ( dbVersion < 2 ) { int lastSaved = qry.value( qry.record().indexOf( QLatin1String("last_saved") ) ).toInt(); int nextHourId = qry.value( qry.record().indexOf( QLatin1String("next_hour_id") ) ).toInt(); QString qryStr = QLatin1String("REPLACE INTO general (id, version, last_saved, calendar, next_hour_id )") + QLatin1String(" VALUES (?, ?, ?, ?, ? );"); qry.prepare( qryStr ); qry.addBindValue( 1 ); qry.addBindValue( current_db_version ); qry.addBindValue( lastSaved ); // FIXME //qry.addBindValue( QVariant( KCalendarSystem::calendarSystem( calendarType ) ).toString() ); qry.addBindValue( nextHourId ); qry.exec(); } } ok = QSqlDatabase::database( mIfaceName ).commit(); db.close(); return ok; } bool SqlStorage::loadStats( StorageData *sd, QHash *models, QList *rules ) { bool ok = false; if ( !open() ) return ok; QSqlDatabase::database( mIfaceName ).transaction(); QSqlQuery qry( db ); QDateTime curDateTime = QDateTime::currentDateTime(); KLocale::CalendarSystem calSystem = KLocale::QDateCalendar; qry.exec( QLatin1String("SELECT * FROM general;") ); if ( qry.next() ) { int cLastSaved = qry.record().indexOf( QLatin1String("last_saved") ); int cCalendarSystem = qry.record().indexOf( QLatin1String("calendar") ); int cNextHourId = qry.record().indexOf( QLatin1String("next_hour_id") ); sd->lastSaved = qry.value( cLastSaved ).toUInt(); calSystem = static_cast(qry.value( cCalendarSystem ).toInt()); sd->nextHourId = qry.value( cNextHourId ).toInt(); } sd->calendar = KCalendarSystem::create( calSystem ); if ( models ) { foreach( StatisticsModel * s, *models ) s->setCalendar( sd->calendar ); foreach ( StatisticsModel * s, *models ) { if ( s->periodType() == KNemoStats::HourArchive ) continue; foreach ( KNemoStats::TrafficType trafficType, mTypeMap.keys() ) { qry.exec( QString::fromLatin1( "SELECT * FROM %1s%2 ORDER BY id;" ) .arg( periods.at( s->periodType() ) ) .arg( mTypeMap.value( trafficType ) ) ); int cId = qry.record().indexOf( QLatin1String("id") ); int cRx = qry.record().indexOf( QLatin1String("rx") ); int cTx = qry.record().indexOf( QLatin1String("tx") ); int cDt = 0; int cDays = 0; if ( trafficType == KNemoStats::AllTraffic ) { cDt = qry.record().indexOf( QLatin1String("datetime") ); if ( s->periodType() == KNemoStats::BillPeriod ) { cDays = qry.record().indexOf( QLatin1String("days") ); } } while ( qry.next() ) { int id = qry.value( cId ).toInt(); if ( trafficType == KNemoStats::AllTraffic ) { int days = -1; if ( s->periodType() == KNemoStats::BillPeriod ) { days = qry.value( cDays ).toInt(); } s->createEntry( QDateTime::fromString( qry.value( cDt ).toString(), Qt::ISODate ), id, days ); } s->setTraffic( id, qry.value( cRx ).toULongLong(), qry.value( cTx ).toULongLong(), trafficType ); s->addTrafficType( trafficType, id ); } if ( trafficType == KNemoStats::AllTraffic && s->rowCount() ) { sd->saveFromId.insert( s->periodType(), s->id() ); } } } } if ( rules ) { qry.exec( QLatin1String("SELECT * FROM stats_rules ORDER BY id;") ); int cDt = qry.record().indexOf( QLatin1String("start_date") ); int cType = qry.record().indexOf( QLatin1String("period_units") ); int cUnits = qry.record().indexOf( QLatin1String("period_count") ); while ( qry.next() ) { StatsRule entry; entry.startDate = QDate::fromString( qry.value( cDt ).toString(), Qt::ISODate ); entry.periodUnits = qry.value( cType ).toInt(); entry.periodCount = qry.value( cUnits ).toInt(); *rules << entry; } qry.exec( QLatin1String("SELECT * FROM stats_rules_offpeak ORDER BY id;") ); int cId = qry.record().indexOf( QLatin1String("id") ); int cOpStartTime = qry.record().indexOf( QLatin1String("offpeak_start_time") ); int cOpEndTime = qry.record().indexOf( QLatin1String("offpeak_end_time") ); int cWeekendIsOffpeak = qry.record().indexOf( QLatin1String("weekend_is_offpeak") ); int cWStartTime = qry.record().indexOf( QLatin1String("weekend_start_time") ); int cWEndTime = qry.record().indexOf( QLatin1String("weekend_end_time") ); int cWStartDay = qry.record().indexOf( QLatin1String("weekend_start_day") ); int cWEndDay = qry.record().indexOf( QLatin1String("weekend_end_day") ); while ( qry.next() ) { int id = qry.value( cId ).toInt(); if ( id < rules->count() ) { (*rules)[ id ].logOffpeak = true; (*rules)[ id ].offpeakStartTime = QTime::fromString( qry.value( cOpStartTime ).toString(), time_format ); (*rules)[ id ].offpeakEndTime = QTime::fromString( qry.value( cOpEndTime ).toString(), time_format ); (*rules)[ id ].weekendIsOffpeak = qry.value( cWeekendIsOffpeak ).toBool(); (*rules)[ id ].weekendDayStart = qry.value( cWStartDay ).toInt(); (*rules)[ id ].weekendDayEnd = qry.value( cWEndDay ).toInt(); (*rules)[ id ].weekendTimeStart = QTime::fromString( qry.value( cWStartTime ).toString(), time_format ); (*rules)[ id ].weekendTimeEnd = QTime::fromString( qry.value( cWEndTime ).toString(), time_format ); } } } ok = QSqlDatabase::database( mIfaceName ).commit(); qry.exec( QLatin1String("VACUUM;") ); db.close(); return ok; } bool SqlStorage::saveStats( StorageData *sd, QHash *models, QList *rules, bool fullSave ) { bool ok = false; if ( !open() ) return ok; QSqlDatabase::database( mIfaceName ).transaction(); save( sd, models, rules, fullSave ); ok = QSqlDatabase::database( mIfaceName ).commit(); if ( fullSave ) { QSqlQuery qry( db ); qry.exec( QLatin1String("VACUUM;") ); } db.close(); return ok; } bool SqlStorage::clearStats( StorageData *sd ) { bool ok = false; if ( !open() ) return ok; QSqlDatabase::database( mIfaceName ).transaction(); QSqlQuery qry( db ); foreach ( QString period, periods ) { foreach ( KNemoStats::TrafficType i, mTypeMap.keys() ) { if ( i == KNemoStats::AllTraffic && ( period == periods.at( KNemoStats::Hour ) || period == periods.at( KNemoStats::HourArchive ) ) ) continue; qry.exec( QString::fromLatin1( "DELETE FROM %1s%2;" ).arg( period ).arg( mTypeMap.value( i ) ) ); } } save( sd ); ok = QSqlDatabase::database( mIfaceName ).commit(); qry.exec( QLatin1String("VACUUM;") ); db.close(); return ok; } bool SqlStorage::open() { if ( !mValidDbVer ) return false; if ( !db.isValid() ) return false; if ( db.isOpen() ) return true; db.setDatabaseName( mDbPath ); return db.open(); } void SqlStorage::save( StorageData *sd, QHash *models, QList *rules, bool fullSave ) { QSqlQuery qry( db ); QString qryStr = QLatin1String("REPLACE INTO general (id, version, last_saved, calendar, next_hour_id )") + QLatin1String(" VALUES (?, ?, ?, ?, ? );"); qry.prepare( qryStr ); qry.addBindValue( 1 ); qry.addBindValue( current_db_version ); qry.addBindValue( QDateTime::currentDateTime().toTime_t() ); qry.addBindValue( QVariant( sd->calendar->calendarSystem() ).toString() ); qry.addBindValue( sd->nextHourId ); qry.exec(); if ( models ) { foreach ( StatisticsModel * s, *models ) { foreach ( KNemoStats::TrafficType trafficType, mTypeMap.keys() ) { /* Always do deletes for: hour* Even on a full save, don't delete anything from: days hour_archives hour_archives_* if the model is empty */ if ( s->periodType() == KNemoStats::Hour || ( fullSave && !( ( trafficType == KNemoStats::AllTraffic && ( s->periodType() == KNemoStats::Day || s->periodType() == KNemoStats::HourArchive ) ) || ( s->periodType() == KNemoStats::HourArchive && !s->rowCount() ) ) ) ) { int deleteFrom = sd->saveFromId.value( s->periodType() ); qryStr = QString::fromLatin1( "DELETE FROM %1s%2 WHERE id >= '%3';" ) .arg( periods.at( s->periodType() ) ) .arg( mTypeMap.value( trafficType ) ) .arg( deleteFrom ); qry.exec( qryStr ); } if ( !s->rowCount() ) { continue; } QString dateTimeStr; QString dateTimeStr2; if ( trafficType == KNemoStats::AllTraffic ) { dateTimeStr = QLatin1String(" datetime,"); dateTimeStr2 = QLatin1String(" ?,"); if ( s->periodType() == KNemoStats::BillPeriod ) { dateTimeStr += QLatin1String(" days,"); dateTimeStr2 += QLatin1String(" ?,"); } } qryStr = QLatin1String("REPLACE INTO %1s%2 (id,%3 rx, tx )") + QLatin1String(" VALUES (?,%4 ?, ? );"); qryStr = qryStr .arg( periods.at( s->periodType() ) ) .arg( mTypeMap.value( trafficType ) ) .arg( dateTimeStr ) .arg( dateTimeStr2 ); qry.prepare( qryStr ); int j = sd->saveFromId.value( s->periodType() ); for ( j = s->indexOfId( j ); j < s->rowCount(); ++j ) { if ( s->trafficTypes( j ).contains( trafficType ) ) { qry.addBindValue( s->id( j ) ); if ( trafficType == KNemoStats::AllTraffic ) { qry.addBindValue( s->dateTime( j ).toString( Qt::ISODate ) ); if ( s->periodType() == KNemoStats::BillPeriod ) { qry.addBindValue( s->days( j ) ); } } qry.addBindValue( s->rxBytes( j, trafficType ) ); qry.addBindValue( s->txBytes( j, trafficType ) ); qry.exec(); } } } if ( s->rowCount() ) { sd->saveFromId.insert( s->periodType(), s->id() ); if ( s->periodType() == KNemoStats::HourArchive ) s->clearRows(); } } } if ( fullSave && rules ) { qryStr = QString::fromLatin1( "DELETE FROM stats_rules WHERE id >= '%1';" ).arg( rules->count() ); qry.exec( qryStr ); qryStr = QString::fromLatin1( "DELETE FROM stats_rules_offpeak WHERE id >= '%1';" ).arg( rules->count() ); qry.exec( qryStr ); if ( rules->count() ) { qryStr = QLatin1String("REPLACE INTO stats_rules (id, start_date, period_units, period_count )") + QLatin1String(" VALUES( ?, ?, ?, ? );"); qry.prepare( qryStr ); for ( int i = 0; i < rules->count(); ++i ) { qry.addBindValue( i ); qry.addBindValue( rules->at(i).startDate.toString( Qt::ISODate ) ); qry.addBindValue( rules->at(i).periodUnits ); qry.addBindValue( rules->at(i).periodCount ); qry.exec(); } qryStr = QLatin1String("REPLACE INTO stats_rules_offpeak (id,") + QLatin1String(" offpeak_start_time, offpeak_end_time, weekend_is_offpeak,") + QLatin1String(" weekend_start_time, weekend_end_time, weekend_start_day, weekend_end_day )") + QLatin1String(" VALUES( ?, ?, ?, ?, ?, ?, ?, ? );"); qry.prepare( qryStr ); for ( int i = 0; i < rules->count(); ++i ) { QVariant startTime = QVariant::String; QVariant stopTime = QVariant::String; QVariant weekendIsOffpeak = QVariant::Bool; QVariant wStartTime = QVariant::String; QVariant wEndTime = QVariant::String; QVariant wStartDay = QVariant::Int; QVariant wEndDay = QVariant::Int; if ( !rules->at(i).logOffpeak ) continue; startTime = rules->at(i).offpeakStartTime.toString( time_format ); stopTime = rules->at(i).offpeakEndTime.toString( time_format ); weekendIsOffpeak = rules->at(i).weekendIsOffpeak; if ( rules->at(i).weekendIsOffpeak ) { wStartTime = rules->at(i).weekendTimeStart.toString( time_format ); wEndTime = rules->at(i).weekendTimeEnd.toString( time_format ); wStartDay = rules->at(i).weekendDayStart; wEndDay = rules->at(i).weekendDayEnd; } qry.addBindValue( i ); qry.addBindValue( startTime ); qry.addBindValue( stopTime ); qry.addBindValue( weekendIsOffpeak ); qry.addBindValue( wStartTime ); qry.addBindValue( wEndTime ); qry.addBindValue( wStartDay ); qry.addBindValue( wEndDay ); qry.exec(); } } } }