diff --git a/.gitignore b/.gitignore index 25de1c5..ac256df 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ /build-* *.pro.user /build_64_release/ +/TrackYourTime.app/ +/build_64_debug/ diff --git a/BUILD_README.md b/BUILD_README.md index 850302b..d68fce8 100644 --- a/BUILD_README.md +++ b/BUILD_README.md @@ -1,27 +1,45 @@ -For building this application, Qt 5 is required +For building this application, Qt 5 is required -You can get it here: https://www.qt.io/download/ +You can get it here: https://www.qt.io/download/ -First build TrackYourTime.pro with Qt Creator - it is a typical Qt project +First build TrackYourTime.pro with Qt Creator - it is a typical Qt project -After building do the following: +After building do the following: #Windows -Place TrackYourTime.exe in build folder, copy data folder, -copy platforms plugin with qwindows, copy necessary qt libs -Pack in compressed folder TrackYourTime_Windows.zip +Place TrackYourTime.exe in build folder, copy data folder, +copy platforms plugin with qwindows, copy necessary qt libs +Pack in compressed folder TrackYourTime_Windows.zip #Mac OS X -Copy data into TrackYourTime.app/Contents/MacOS +Copy data into TrackYourTime.app/Contents/MacOS copy platforms/libqcocoa.dylib into TrackYourTime.app/Contents/PlugIns/platforms add key LSUIElement with value 1 into TrackYourTime.app/Contents/Info.plist -execute macdeployqt with -dmg flag +execute macdeployqt with -dmg flag() Rename package to TrackYourTime_MacOSX.dmg #Linux Place TrackYourTime in build folder, copy data folder, copy checksystem Pack into TrackYourTime_Linux.tar.gz + + +#Localization +its possible to make this work from console without QtCreator. +But QtCreator is simple and powerfull tool and i prefer to use it. + +Open project in QtCreator +Go to menu Tools->External->Linguist->Update Translations(lupdate) +Launch Qt Linguist() +Open *.ts file for edit +Edit file(edit item and press Ctrl+Enter) +Save file +Go to menu Tools->External->Linguist->Release Translations(lrelease) +Move *.qm file into data/languages + +If you create new language - create file with name data/languages/lang__name.utf8 +Open this file in utf8 text editor +And place only one line in utd8 encoding - name of language in native format diff --git a/TrackYourTime/TrackYourTime.pro b/TrackYourTime/TrackYourTime.pro index 1f29796..f2f4175 100644 --- a/TrackYourTime/TrackYourTime.pro +++ b/TrackYourTime/TrackYourTime.pro @@ -10,16 +10,19 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets mac:LIBS += -framework CoreGraphics mac:LIBS += -framework AppKit +mac: QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.8 TARGET = TrackYourTime TEMPLATE = app CONFIG+=address_sanitizer +CONFIG+=C++11 TRANSLATIONS = lang_en.ts lang_ru.ts QMAKE_CXXFLAGS += -DQT_COMPILING_QSTRING_COMPAT_CPP unix:!mac:QMAKE_CXXFLAGS += -std=c++0x +unix:!mac: LIBS += -rdynamic win32:QMAKE_LFLAGS_WINDOWS = /SUBSYSTEM:WINDOWS,5.01 @@ -29,7 +32,7 @@ mac:ICON = main.icns win32:LIBS += -luser32 unix:!mac:LIBS += -lX11 -INCLUDEPATH += "ui" +INCLUDEPATH += ui data tools SOURCES += \ main.cpp \ @@ -47,7 +50,11 @@ SOURCES += \ data/cscriptsmanager.cpp \ ui/app_settingswindow.cpp \ data/capppredefinedinfo.cpp \ - tools/tools.cpp + tools/tools.cpp \ + data/cschedule.cpp \ + ui/schedulewindow.cpp \ + ui/notification_dummy.cpp \ + ui/notificationwindow.cpp HEADERS += \ ui/settingswindow.h \ @@ -64,7 +71,11 @@ HEADERS += \ data/cscriptsmanager.h \ ui/app_settingswindow.h \ data/capppredefinedinfo.h \ - tools/tools.h + tools/tools.h \ + data/cschedule.h \ + ui/schedulewindow.h \ + ui/notification_dummy.h \ + ui/notificationwindow.h FORMS += \ ui/settingswindow.ui \ @@ -72,4 +83,7 @@ FORMS += \ ui/applicationswindow.ui \ ui/profileswindow.ui \ ui/aboutwindow.ui \ - ui/app_settingswindow.ui + ui/app_settingswindow.ui \ + ui/schedulewindow.ui \ + ui/notification_dummy.ui \ + ui/notificationwindow.ui diff --git a/TrackYourTime/data/cdatamanager.cpp b/TrackYourTime/data/cdatamanager.cpp index 0f0a5dd..5efc0ce 100644 --- a/TrackYourTime/data/cdatamanager.cpp +++ b/TrackYourTime/data/cdatamanager.cpp @@ -21,7 +21,7 @@ #include #include #include -#include +#include "../tools/tools.h" #include "../tools/os_api.h" #include "../tools/cfilebin.h" #include "cdbversionconverter.h" @@ -33,12 +33,20 @@ const QString cDataManager::CONF_AUTOSAVE_DELAY_ID = "AUTOSAVE_DELAY"; const QString cDataManager::CONF_STORAGE_FILENAME_ID = "STORAGE_FILENAME"; const QString cDataManager::CONF_LANGUAGE_ID = "LANGUAGE"; const QString cDataManager::CONF_FIRST_LAUNCH_ID = "FIRST_LAUNCH"; -const QString cDataManager::CONF_SHOW_BALOONS_ID = "SHOW_BALOONS"; +const QString cDataManager::CONF_NOTIFICATION_TYPE_ID = "NOTIFICATION_TYPE"; +const QString cDataManager::CONF_NOTIFICATION_MESSAGE_ID = "NOTIFICATION_MESSAGE"; +const QString cDataManager::CONF_NOTIFICATION_HIDE_SECONDS_ID = "NOTIFICATION_HIDE_SECONDS"; +const QString cDataManager::CONF_NOTIFICATION_HIDE_MOVES_ID = "NOTIFICATION_HIDE_MOVES"; +const QString cDataManager::CONF_NOTIFICATION_POSITION_ID = "NOTIFICATION_POSITION"; +const QString cDataManager::CONF_NOTIFICATION_SIZE_ID = "NOTIFICATION_SIZE"; +const QString cDataManager::CONF_NOTIFICATION_OPACITY_ID = "NOTIFICATION_OPACITY"; const QString cDataManager::CONF_AUTORUN_ID = "AUTORUN_ENABLED"; +const QString cDataManager::CONF_CLIENT_MODE_ID = "CLIENT_MODE"; +const QString cDataManager::CONF_CLIENT_MODE_HOST_ID = "CLIENT_MODE_HOST"; cDataManager::cDataManager():QObject() { - m_ShowBaloons = true; + m_NotificationType = NT_SYSTEM; m_UpdateCounter = 0; m_UpdateDelay = DEFAULT_SECONDS_UPDATE_DELAY; @@ -64,10 +72,12 @@ cDataManager::cDataManager():QObject() #endif loadPreferences(); - QDir storagePath(QFileInfo(m_StorageFileName).absolutePath()); - if (!storagePath.exists()) - storagePath.mkpath("."); - loadDB(); + if (!m_StorageFileName.isEmpty()){ + QDir storagePath(QFileInfo(m_StorageFileName).absolutePath()); + if (!storagePath.exists()) + storagePath.mkpath("."); + loadDB(); + } if (m_Profiles.size()==0){ sProfile defaultProfile; @@ -87,6 +97,13 @@ cDataManager::~cDataManager() delete m_Applications[i]; } +const sProfile *cDataManager::profiles(int index) +{ + if (index<0 || index>=m_Profiles.size()) + return NULL; + return &m_Profiles[index]; +} + void cDataManager::addNewProfile(const QString &Name, int CloneProfileIndex) { sProfile profile; @@ -187,11 +204,34 @@ void cDataManager::process() m_CurrentMousePos = mousePos; } + if (isUserActive) + m_LastLocalActivity = 0; + else + m_LastLocalActivity+=m_UpdateDelay; + int hostActivity = m_LastLocalActivity+1; + sOverrideTrackerInfo* info = m_ExternalTrackers.getOverrideTracker(); + if (info) + hostActivity = info->IdleTime-2; + + //Update application bool isAppChanged = false; sSysInfo currentAppInfo = getCurrentApplication(); int appIndex = getAppIndex(currentAppInfo); int activityIndex = appIndex>-1?getActivityIndex(appIndex,currentAppInfo):0; + + if (m_LastLocalActivity>hostActivity){ + if (info){ + sSysInfo remoteInfo; + remoteInfo.fileName = info->AppFileName; + remoteInfo.path = ""; + remoteInfo.title = ""; + appIndex = getAppIndex(remoteInfo); + activityIndex = appIndex>-1?getActivityIndexDirect(appIndex,info->State):0; + isUserActive = true; + } + } + if (appIndex!=m_CurrentApplicationIndex || activityIndex!=m_CurrentApplicationActivityIndex){ isUserActive = true; isAppChanged = true; @@ -199,11 +239,24 @@ void cDataManager::process() m_CurrentApplicationActivityIndex = activityIndex; if (m_CurrentApplicationIndex>-1){ int activityCategory = m_Applications[m_CurrentApplicationIndex]->activities[m_CurrentApplicationActivityIndex].categories[m_CurrentProfile]; - if (m_CurrentApplicationActivityCategory!=activityCategory){ + if (m_CurrentApplicationActivityCategory!=activityCategory || activityCategory==-1){ m_CurrentApplicationActivityCategory = activityCategory; - QString hint = m_Profiles[m_CurrentProfile].name+":"+(m_CurrentApplicationActivityCategory==-1?tr("Uncategorized"):m_Categories[m_CurrentApplicationActivityCategory].name); - if (m_ShowBaloons) - emit trayShowHint(hint); + + switch(m_NotificationType){ + case NT_NONE:{ + + }; + break; + case NT_SYSTEM:{ + QString hint = m_Profiles[m_CurrentProfile].name+":"+(m_CurrentApplicationActivityCategory==-1?tr("Uncategorized"):m_Categories[m_CurrentApplicationActivityCategory].name); + emit trayShowHint(hint); + }; + break; + case NT_BUILTIN:{ + emit showNotification(); + }; + break; + } } } } @@ -239,6 +292,18 @@ void cDataManager::process() m_AutoSaveCounter = 0; saveDB(); } + + if (!m_Idle && m_ClientMode){ + if (m_CurrentApplicationIndex>-1){ + m_ExternalTrackers.sendOverrideTracker(m_Applications[m_CurrentApplicationIndex]->activities[0].name, + m_Applications[m_CurrentApplicationIndex]->activities[m_CurrentApplicationActivityIndex].name, + m_IdleCounter==m_UpdateDelay?0:m_IdleCounter, + m_ClientModeHost); + } + else{ + m_ExternalTrackers.sendOverrideTracker("","",m_IdleCounter==m_UpdateDelay?0:m_IdleCounter,m_ClientModeHost); + } + } } void cDataManager::onPreferencesChanged() @@ -283,12 +348,10 @@ int cDataManager::getActivityIndex(int appIndex,const sSysInfo &FileInfo) emit debugScriptResult(m_ScriptsManager.evalute(FileInfo,m_DebugScript),FileInfo); } - if (appInfo->trackerType==sAppInfo::eTrackerType::TT_EXECUTABLE_DETECTOR) - return 0; - QString activity; switch(appInfo->trackerType){ + case sAppInfo::eTrackerType::TT_EXECUTABLE_DETECTOR: case sAppInfo::eTrackerType::TT_EXTERNAL_DETECTOR:{ if (!m_ExternalTrackers.getExternalTrackerState(appInfo->activities[0].name,activity)) activity=""; @@ -304,22 +367,26 @@ int cDataManager::getActivityIndex(int appIndex,const sSysInfo &FileInfo) break; } + return getActivityIndexDirect(appIndex,activity); +} - if (activity.isEmpty()) +int cDataManager::getActivityIndexDirect(int appIndex, QString activityName) +{ + if (activityName.isEmpty()) return 0; for (int i = 0; iactivities.size(); i++){ - if (m_Applications[appIndex]->activities[i].name==activity){ + if (m_Applications[appIndex]->activities[i].name==activityName){ return i; } } sActivityInfo ainfo; ainfo.visible = true; - ainfo.name = activity; + ainfo.name = activityName; ainfo.categories.resize(m_Profiles.size()); for (int i = 0; iactivities[0].categories[i]; + ainfo.categories[i] = -1; m_Applications[appIndex]->activities.push_back(ainfo); emit applicationsChanged(); return m_Applications[appIndex]->activities.size()-1; @@ -329,6 +396,8 @@ const int FILE_FORMAT_VERSION = 2; void cDataManager::saveDB() { + if (m_StorageFileName.isEmpty()) + return; cFileBin file( m_StorageFileName+".new" ); if ( file.open(QIODevice::WriteOnly) ) { @@ -390,6 +459,9 @@ void cDataManager::saveDB() void cDataManager::loadDB() { + if (m_StorageFileName.isEmpty()) + return; + qDebug() << "cDataManager: start DB loading\n"; for (int i = 0; ivalue(CONF_UPDATE_DELAY_ID,m_UpdateDelay).toInt(); + m_IdleDelay = settings.db()->value(CONF_IDLE_DELAY_ID,m_IdleDelay).toInt(); + m_AutoSaveDelay = settings.db()->value(CONF_AUTOSAVE_DELAY_ID,m_AutoSaveDelay).toInt(); + m_StorageFileName = settings.db()->value(CONF_STORAGE_FILENAME_ID,m_StorageFileName).toString(); + m_NotificationType = (eNotificationType)settings.db()->value(CONF_NOTIFICATION_TYPE_ID,m_NotificationType).toInt(); + m_ClientMode = settings.db()->value(CONF_CLIENT_MODE_ID,m_ClientMode).toBool(); + m_ClientModeHost = settings.db()->value(CONF_CLIENT_MODE_HOST_ID,m_ClientModeHost).toString(); } -void cDataManager::savePreferences() -{ - QSettings settings; - - settings.setValue(CONF_UPDATE_DELAY_ID,m_UpdateDelay); - settings.setValue(CONF_IDLE_DELAY_ID,m_IdleDelay); - settings.setValue(CONF_AUTOSAVE_DELAY_ID,m_AutoSaveDelay); - settings.setValue(CONF_STORAGE_FILENAME_ID,m_StorageFileName); - settings.sync(); -} - - void sActivityInfo::incTime(bool FirstTime, int CurrentProfile, int UpdateDelay) diff --git a/TrackYourTime/data/cdatamanager.h b/TrackYourTime/data/cdatamanager.h index ed94906..7724949 100644 --- a/TrackYourTime/data/cdatamanager.h +++ b/TrackYourTime/data/cdatamanager.h @@ -79,6 +79,12 @@ struct sCategory{ class cDataManager : public QObject { Q_OBJECT public: + enum eNotificationType{ + NT_NONE, + NT_SYSTEM, + NT_BUILTIN + }; + static const int DEFAULT_SECONDS_UPDATE_DELAY = 1; static const int DEFAULT_SECONDS_IDLE_DELAY = 300; static const int DEFAULT_SECONDS_AUTOSAVE_DELAY = 1500; @@ -89,8 +95,16 @@ class cDataManager : public QObject { static const QString CONF_STORAGE_FILENAME_ID; static const QString CONF_LANGUAGE_ID; static const QString CONF_FIRST_LAUNCH_ID; - static const QString CONF_SHOW_BALOONS_ID; + static const QString CONF_NOTIFICATION_TYPE_ID; + static const QString CONF_NOTIFICATION_MESSAGE_ID; + static const QString CONF_NOTIFICATION_HIDE_SECONDS_ID; + static const QString CONF_NOTIFICATION_HIDE_MOVES_ID; + static const QString CONF_NOTIFICATION_POSITION_ID; + static const QString CONF_NOTIFICATION_SIZE_ID; + static const QString CONF_NOTIFICATION_OPACITY_ID; static const QString CONF_AUTORUN_ID; + static const QString CONF_CLIENT_MODE_ID; + static const QString CONF_CLIENT_MODE_HOST_ID; protected: cExternalTrackers m_ExternalTrackers; cScriptsManager m_ScriptsManager; @@ -100,12 +114,16 @@ class cDataManager : public QObject { QVector m_Applications; QVector m_Profiles; + int m_LastLocalActivity; int m_CurrentProfile; QString m_StorageFileName; QString m_DebugScript; - bool m_ShowBaloons; + eNotificationType m_NotificationType; + + bool m_ClientMode; + QString m_ClientModeHost; int m_UpdateCounter; int m_UpdateDelay; @@ -123,18 +141,23 @@ class cDataManager : public QObject { int m_AutoSaveDelay; int getAppIndex(const sSysInfo& FileInfo); int getActivityIndex(int appIndex,const sSysInfo &FileInfo); + int getActivityIndexDirect(int appIndex, QString activityName); void saveDB(); void loadDB(); void loadPreferences(); - void savePreferences(); public: cDataManager(); virtual ~cDataManager(); int profilesCount(){return m_Profiles.size();} - const sProfile* profiles(int index){return &m_Profiles[index];} + const sProfile* profiles(int index); int getCurrentProfileIndex(){return m_CurrentProfile;} void setCurrentProfileIndex(int ProfileIndex){ m_CurrentProfile = ProfileIndex; emit profilesChanged();} + void setCurrentProfileIndexSafe(int ProfileIndex){ + if (ProfileIndex<0 || ProfileIndex>=m_Profiles.size()) + return; + setCurrentProfileIndex(ProfileIndex); + } void setProfileName(int index, const QString& Name){m_Profiles[index].name = Name; emit profilesChanged();} void addNewProfile(const QString &Name, int CloneProfileIndex = -1); void mergeProfiles(int profile1, int profile2); @@ -151,6 +174,9 @@ class cDataManager : public QObject { sAppInfo* applications(int index){return m_Applications[index];} void setApplicationActivityCategory(int profile, int appIndex, int activityIndex, int category); + int getCurrentAppliction(){return m_CurrentApplicationIndex;} + int getCurrentApplictionActivity(){return m_CurrentApplicationActivityIndex;} + QString getStorageFileName(){return m_StorageFileName;} void setDebugScript(const QString& script){m_DebugScript = script;} public slots: @@ -164,6 +190,7 @@ public slots: void profilesChanged(); void applicationsChanged(); void debugScriptResult(QString result, const sSysInfo& data); + void showNotification(); }; #endif // CDATAMANAGER_H diff --git a/TrackYourTime/data/cdbversionconverter.cpp b/TrackYourTime/data/cdbversionconverter.cpp index 8f70899..d64a2af 100644 --- a/TrackYourTime/data/cdbversionconverter.cpp +++ b/TrackYourTime/data/cdbversionconverter.cpp @@ -51,7 +51,7 @@ bool convertToVersion2(const QString& SrcFileName,const QString& DstFileName, bo char prefix[FILE_FORMAT_PREFIX_SIZE+1]; //add zero for simple convert to string prefix[FILE_FORMAT_PREFIX_SIZE] = 0; file.read(prefix,FILE_FORMAT_PREFIX_SIZE); - int Version = file.readInt(); + file.readInt();//version - its 1. no variants //header out.write(FILE_FORMAT_PREFIX,FILE_FORMAT_PREFIX_SIZE); out.writeInt(2); @@ -110,7 +110,9 @@ bool convertToVersion2(const QString& SrcFileName,const QString& DstFileName, bo if (makeBackup) QFile::rename(DstFileName,DstFileName+".version.2"); QFile::rename(tmpFileName,DstFileName); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)) qInfo() << "db converted from version 1 to version 2"; +#endif } return success; } diff --git a/TrackYourTime/data/cexternaltrackers.cpp b/TrackYourTime/data/cexternaltrackers.cpp index 0c598c2..ecee07a 100644 --- a/TrackYourTime/data/cexternaltrackers.cpp +++ b/TrackYourTime/data/cexternaltrackers.cpp @@ -1,177 +1,244 @@ -/* - * TrackYourTime - cross-platform time tracker - * Copyright (C) 2015-2016 Alexander Basov - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "cexternaltrackers.h" -#include - -const QString EXTERNAL_TRACKER_PREFIX = "TYTET"; -const QString EXTERNAL_TRACKER_FORMAT_VERSION = "1"; - -cExternalTrackers::cExternalTrackers(QObject *parent) : QObject(parent),m_HTTPServer(EXTERNAL_TRACKERS_HTTP_PORT) -{ - m_Server.bind(QHostAddress::LocalHost, EXTERNAL_TRACKERS_UDP_PORT); - connect(&m_Server, SIGNAL(readyRead()), this, SLOT(readyRead())); - - connect(&m_HTTPServer,SIGNAL(dataReady(QString)), this, SLOT(onDataReady(QString))); -} - -void cExternalTrackers::addPair(const QString& AppName, const QString& CurrentState) -{ - for (int i = 0; i pairs; - for (int i = 0; isetSocketDescriptor(handle); - - connect(socket,SIGNAL(readyRead()), this, SLOT(onReadyRead())); - connect(socket,SIGNAL(disconnected()), this, SLOT(onDisconnected())); -} - -void cHTTPTrackerServer::onReadyRead() -{ - QTcpSocket* socket = qobject_cast(sender()); - - QString data = socket->readAll(); - data = data.split("\r")[0]; - int dataPos = data.indexOf("["); - if (dataPos>-1){ - data = data.mid(dataPos+1); - dataPos = data.indexOf("]"); - if (dataPos>-1){ - data = data.mid(0,dataPos); - emit dataReady(data); - } - } - - QString response = "HTTP/1.1 200 OK"; - socket->write(response.toUtf8()); - socket->disconnectFromHost(); -} - -void cHTTPTrackerServer::onDisconnected() -{ - QTcpSocket* socket = qobject_cast(sender()); - socket->close(); - socket->deleteLater(); -} +/* + * TrackYourTime - cross-platform time tracker + * Copyright (C) 2015-2016 Alexander Basov + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "cexternaltrackers.h" +#include + +const QString EXTERNAL_TRACKER_PREFIX = "TYTET"; +const QString OVERRIDE_TRACKER_PREFIX = "TYTOT"; +const QString EXTERNAL_TRACKER_FORMAT_VERSION = "1"; + +cExternalTrackers::cExternalTrackers(QObject *parent) : QObject(parent),m_HTTPServer(EXTERNAL_TRACKERS_HTTP_PORT) +{ + m_Server.bind(QHostAddress::Any, EXTERNAL_TRACKERS_UDP_PORT); + connect(&m_Server, SIGNAL(readyRead()), this, SLOT(readyRead())); + + connect(&m_HTTPServer,SIGNAL(dataReady(QString)), this, SLOT(onDataReady(QString))); +} + +void cExternalTrackers::addPair(const QString& AppName, const QString& CurrentState) +{ + for (int i = 0; i pairs; + for (int i = 0; isetSocketDescriptor(handle); + + connect(socket,SIGNAL(readyRead()), this, SLOT(onReadyRead())); + connect(socket,SIGNAL(disconnected()), this, SLOT(onDisconnected())); +} + +void cHTTPTrackerServer::onReadyRead() +{ + QTcpSocket* socket = qobject_cast(sender()); + + QString data = socket->readAll(); + data = data.split("\r")[0]; + int dataPos = data.indexOf("?"); + if (dataPos>-1){ + data = data.mid(dataPos+1); + dataPos = data.indexOf(" "); + if (dataPos>-1){ + data = data.mid(0,dataPos); + emit dataReady(data); + } + } + + QString response = "HTTP/1.1 200 OK"; + socket->write(response.toUtf8()); + socket->disconnectFromHost(); +} + +void cHTTPTrackerServer::onDisconnected() +{ + QTcpSocket* socket = qobject_cast(sender()); + socket->close(); + socket->deleteLater(); +} diff --git a/TrackYourTime/data/cexternaltrackers.h b/TrackYourTime/data/cexternaltrackers.h index 9f19842..1175b47 100644 --- a/TrackYourTime/data/cexternaltrackers.h +++ b/TrackYourTime/data/cexternaltrackers.h @@ -30,6 +30,13 @@ struct sExternalTrackerPair{ QString HostAppFileName; QString ClientState; + int LifeTime; +}; + +struct sOverrideTrackerInfo{ + QString AppFileName; + QString State; + int IdleTime; int LifeTime; }; @@ -54,18 +61,25 @@ class cExternalTrackers : public QObject static const int EXTERNAL_TRACKERS_UDP_PORT = 25855; static const int EXTERNAL_TRACKERS_HTTP_PORT = 25856; static const int EXTERNAL_TRACKERS_PAIR_LIFE_TIME_SECOND = 5; + static const int OVERRIDE_TRACKERS_PAIR_LIFE_TIME_SECOND = 4; protected: - QUdpSocket m_Server; + QUdpSocket m_Client; + + QUdpSocket m_Server; cHTTPTrackerServer m_HTTPServer; + QVector m_Override; QVector m_Pairs; void addPair(const QString& AppName, const QString& CurrentState); + void addOverride(const QString& AppName, const QString& CurrentState, int idleTime); public: explicit cExternalTrackers(QObject *parent = 0); void update(); bool getExternalTrackerState(const QString &appName, QString& outValue); + sOverrideTrackerInfo* getOverrideTracker(); + void sendOverrideTracker(const QString& AppName, const QString& CurrentState, int idleTime, const QString& host); signals: public slots: diff --git a/TrackYourTime/data/cschedule.cpp b/TrackYourTime/data/cschedule.cpp new file mode 100644 index 0000000..f3487d1 --- /dev/null +++ b/TrackYourTime/data/cschedule.cpp @@ -0,0 +1,142 @@ +#include "cschedule.h" +#include +#include "../tools/tools.h" + +QString cSchedule::getCurrentDateTime() +{ + return QDateTime::currentDateTime().toString("ddd yyyy.mm.dd HH:mm"); +} + +void cSchedule::save() +{ + cSettings settings; + settings.db()->setValue("schedule/count",m_Items.size()); + for (int i = 0; isetValue(settingsKey+"action",m_Items[i]->action()); + settings.db()->setValue(settingsKey+"param",m_Items[i]->param()); + settings.db()->setValue(settingsKey+"regexp",m_Items[i]->condition()); + } + settings.db()->sync(); +} + +void cSchedule::load() +{ + for (int i = 0; ivalue("schedule/count",0).toInt()); + for (int i = 0; ivalue(settingsKey+"action").toInt(); + QString param = settings.db()->value(settingsKey+"param").toString(); + QString regexp = settings.db()->value(settingsKey+"regexp").toString(); + m_Items[i] = new cScheduleItem(action,param,regexp); + } +} + +cSchedule::cSchedule(cDataManager *dataManager, QObject *parent) : QObject(parent) +{ + m_DataManager = dataManager; + m_PreviousDateTime = ""; + + load(); + connect(&m_Timer,SIGNAL(timeout()),this,SLOT(timer())); +} + +cSchedule::~cSchedule() +{ + for (int i = 0; i=m_Items.size()) + return NULL; + return m_Items[index]; +} + +void cSchedule::deleteItem(int index) +{ + if (index<0 || index>=m_Items.size()) + return; + delete m_Items[index]; + m_Items.remove(index); + save(); +} + +void cSchedule::addItem(cScheduleItem::eScheduleAction action, const QString ¶m, const QString ®exp) +{ + m_Items.push_back(new cScheduleItem(action,param,regexp)); + save(); +} + +void cSchedule::timer() +{ + if (m_Items.size()==0) + return; + + QString currentDateTime = getCurrentDateTime(); + if (currentDateTime==m_PreviousDateTime) + return; + m_PreviousDateTime = currentDateTime; + + for (int i = 0; iprocess(currentDateTime, m_DataManager); +} + + + + +cScheduleItem::cScheduleItem(eScheduleAction action, const QString ¶m, QString regexp): + QObject(0), + m_Action(action), + m_Param(param), + m_RegExp(regexp) +{ + +} + +void cScheduleItem::process(const QString ¤tDateTime, cDataManager* dataManager) +{ + if (m_RegExp.exactMatch(currentDateTime)){ + switch(m_Action){ + case SA_SET_PROFILE:{ + dataManager->setCurrentProfileIndexSafe(m_Param.toInt()); + } + break; + case SA_COUNT:{ + //WAAAT??? + } + break; + } + } +} + +QString cScheduleItem::getActionName(cScheduleItem::eScheduleAction action) +{ + switch (action){ + case SA_SET_PROFILE:{ + return tr("Set profile"); + }; + break; + case SA_COUNT:{ + //WAAAT??? + } + break; + } + + return "UNKNOWN_ACTION"; +} diff --git a/TrackYourTime/data/cschedule.h b/TrackYourTime/data/cschedule.h new file mode 100644 index 0000000..ecefdac --- /dev/null +++ b/TrackYourTime/data/cschedule.h @@ -0,0 +1,64 @@ +#ifndef CSCHEDULE_H +#define CSCHEDULE_H + +#include +#include +#include +#include +#include "cdatamanager.h" + +class cScheduleItem: public QObject{ + Q_OBJECT + +public: + enum eScheduleAction{ + SA_SET_PROFILE = 0, + SA_COUNT + }; + +protected: + + + eScheduleAction m_Action; + QString m_Param; + QRegExp m_RegExp; +public: + explicit cScheduleItem(eScheduleAction action, const QString& param, QString regexp); + void process(const QString& currentDateTime, cDataManager* dataManager); + + eScheduleAction action() const{return m_Action;} + QString param() const{return m_Param;} + QString condition() const{return m_RegExp.pattern();} + static QString getActionName(eScheduleAction action); +}; + +class cSchedule : public QObject +{ + Q_OBJECT +protected: + QVector m_Items; + QString m_PreviousDateTime; + QTimer m_Timer; + cDataManager* m_DataManager; + QString getCurrentDateTime(); + void save(); + void load(); +public: + explicit cSchedule(cDataManager* dataManager, QObject *parent = 0); + virtual ~cSchedule(); + + void start(); + + int getItemsCount(); + const cScheduleItem* getItem(int index); + void deleteItem(int index); + void addItem(cScheduleItem::eScheduleAction action, const QString& param, const QString& regexp); + + QString getSample(){return getCurrentDateTime();} +signals: + +protected slots: + void timer(); +}; + +#endif // CSCHEDULE_H diff --git a/TrackYourTime/lang_en.ts b/TrackYourTime/lang_en.ts index 91bb2b1..d8c3400 100644 --- a/TrackYourTime/lang_en.ts +++ b/TrackYourTime/lang_en.ts @@ -4,361 +4,708 @@ AboutWindow - + About - + - + Track Your Time - + - + Version - + - - 0.9.0 beta - + + 0.9.2 beta + - + Time Tracker for Windows/Linux/Mac OS X based on Qt framework - + - + Support/Feedback/Feature request: - + - + <a href='mailto:basovav@gmail.com'>basovav@gmail.com</a> - + - + Source and Downloads location: - + - + <a href='https://github.com/Allexin/TrackYourTime.git'>https://github.com/Allexin/TrackYourTime.git</a> - + - + <html><head/><body><p>License: <a href="https://github.com/Allexin/TrackYourTime/blob/master/LICENSE"><span style=" text-decoration: underline; color:#0000ff;">GNU General Public License, version 3</span></a></p><p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.</p></body></html> - + - + © Alexander Basov, 2015-2016 + + + + + App_SettingsWindow + + + Application settings + + + + + Application: + + + + + Tracking: + Tracker type: + + + + By application name + + + + + By external tracker + + + + + By predefined script + + + + + By custom script + By user script + + + + Warning: do not forget to install external tracker if availble! + + + + + Custom script: + User script: + + + + Apply + + + + + Developer tools: + + + + + Start debuging current script + + + + + Debug data: + + + + + Application Name or Class: + + + + + Application title: + + + + + Script result: + + + + + Place title parser code here. Look predefined scripts for example. ApplicationsWindow - + Applications - + - + Profiles - + - + Edit... - + - + Categories and Applications: - + - + + Show hidden objects + + + + <html><head/><body><p>Drag &amp; press &quot;Control&quot; before Drop to move application into a same category in all profiles.</p><p>Drag &amp; Drop application without &quot;Contol&quot; to move application into a category only in current profile.</p></body></html> - + - + Uncategorized - + + + + + (default) + - + New category - + - + Delete category - + - + Set category color - + + + + + Hide activity + + + + + Show activity + - + + Settings... + + + + New Category - + + + + + NotificationWindow + + + Notification Window + + + + + Category + + + + + Set for all profiles. + Set for all profiles + + + + Set for current profile + + + + + + UNKNOWN + + + + + NONE + + + + + default + + + + + Uncategorized + ProfilesWindow - + Profiles - + - + New profile - + - + Clone profile - + - + Merge profiles - + - + New Profile - + - - + + Incorrect arguments - + - + Please select one and only one profile for cloning - + - + copy - + - + Please select at least two profiles for merging - + - + Data will be lost - + - + Warning! After the merging uniqe difference between profiles will be lost. This operation can't be undone. Proceed? - + - SettingsWindow + ScheduleWindow - - Settings - + + + Schedule + - - How often check system state(seconds): - + + New schedule record: + + + + + Action + + + + + Profile + + + + + Condition(e.g .*15:37 or .*Mon.*12:40 ) + + + + + <html><head/><body><p>Regular Expressions syntax: <a href="https://doc.qt.io/qt-4.8/qregexp.html#introduction"><span style=" text-decoration: underline; color:#0000ff;">https://doc.qt.io/qt-4.8/qregexp.html#introduction</span></a></p></body></html> + + + + + Current date and time: + + + + + Add new record + - + + Delete selected record + + + + + SettingsWindow + + + Settings + + + + Duration of inactivity before falling asleep(seconds): - + - + Autosave: how often save db(seconds): - + - + Language(need restart): - + - + Storage File Name: - + - + Browse... - + + + + + Send data to another host: + Send data to another server: + + + + Notifications + + + + + No notifications + + + + + System notification system + + + + + Built-in notification system: + + + + + Set window position and size + + + + + Reset window position + - + + Hide after(seconds): + + + + + Opacity(percents) + Opacity(percents): + + + + Mouse interactions + + + + + Hide notification on mouse move and never show category selection menu + + + + + Never hide notification on mouse move(hide only by timer) and show category selection menu if category not selected + + + + + Hide notification on some mouse moves and show category selection meny if category not selected(recomended) + + + + + Message format: + + + + + Set default message + + + + Apply - + - + Cancel - + - + Launch on Start up - + - - Show baloon when category changed - + + <center>Current profile: %PROFILE%<br>Application: %APP_NAME%<br>State: %APP_STATE%<br>Category: %APP_CATEGORY%</center> + - + Select DB location - + - + Default DB (db.bin);;All files (*.*) - + StatisticWindow - + Statistic - + - - Set today>> - + + Today + + + + + This week + + + + + This month + + + + + This year + - + + >> + + + + From - + - + to - + - + Update - + - + Export categories to CSV... - + - + Export applications to CSV... - + - + Absolute time - + - + Relative time - + - + Uncategorized - + - + + (default) + + + + Select applications file - + - + Select categories file - + cDataManager - + Default - + - + Uncategorized - + + + + + cScheduleItem + + + Set profile + cStatisticDiagramWidget - + NO DATA - + - + Other categories - + cTrayIcon - + Profiles - + - + Applications... - + - + Statistic... - + - + Settings... - + + + + + Schedule... + - + About... + + + + + Help... - + Exit + + + + + https://github.com/Allexin/TrackYourTime/wiki/User-Manual + + notification_dummy + + + Set position and size + + + + + Category: + + + + + Apply + + + + + Close + + + diff --git a/TrackYourTime/lang_ru.ts b/TrackYourTime/lang_ru.ts index 65aa0e0..86c890f 100644 --- a/TrackYourTime/lang_ru.ts +++ b/TrackYourTime/lang_ru.ts @@ -4,238 +4,526 @@ AboutWindow - + About О Приложении - + Track Your Time Track Your Time - + Version Версия - 0.9.0 beta - 0.9.0 бета + 0.9.0 бета - + + 0.9.2 beta + + + + Time Tracker for Windows/Linux/Mac OS X based on Qt framework Time Tracker для Windows/Linux/Mac OS X на базе фреймворка Qt - + Support/Feedback/Feature request: Техническая поддержка/Обратная связь/Запрос изменений: - + <a href='mailto:basovav@gmail.com'>basovav@gmail.com</a> <a href='mailto:basovav@gmail.com'>basovav@gmail.com</a> - + Source and Downloads location: Исходные коды и ссылки для скачивания: - + <a href='https://github.com/Allexin/TrackYourTime.git'>https://github.com/Allexin/TrackYourTime.git</a> - + <html><head/><body><p>License: <a href="https://github.com/Allexin/TrackYourTime/blob/master/LICENSE"><span style=" text-decoration: underline; color:#0000ff;">GNU General Public License, version 3</span></a></p><p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.</p></body></html> - <html><head/><body><p>Лицензия: <a href="https://github.com/Allexin/TrackYourTime/blob/master/LICENSE"><span style=" text-decoration: underline; color:#0000ff;">GNU General Public License, версия 3</span></a></p><p>Эта программа распространяется в надежде принести пользу, но БЕЗ КАКИХ ЛИБО ГАРАНТИЙ; даже без подразумеваемой гарантии КОММЕРЧЕСКОЙ ЦЕННОСТИ или пригодности ДЛЯ ЛЮБЫХ ЦЕЛЕЙ. Для изучения подробностей смотрите лицензию GNU General Public License.</p></body></html> + <html><head/><body><p>Лицензия: <a href="https://github.com/Allexin/TrackYourTime/blob/master/LICENSE"><span style=" text-decoration: underline; color:#0000ff;">GNU General Public License, версия 3</span></a></p><p>Эта программа распространяется в надежде принести пользу, но БЕЗ КАКИХ ЛИБО ГАРАНТИЙ; даже без подразумеваемой гарантии КОММЕРЧЕСКОЙ ЦЕННОСТИ или пригодности ДЛЯ ЛЮБЫХ ЦЕЛЕЙ. Для изучения подробностей смотрите лицензию GNU General Public License.</p></body></html> - + © Alexander Basov, 2015-2016 © Александр Басов, 2015-2016 + + App_SettingsWindow + + + Application settings + Настройки приложения + + + + Application: + Приложение: + + + + Tracking: + Тип отслеживания: + + + + By application name + По названию приложения + + + + By external tracker + Из внешнего трэкера + + + + By predefined script + Из предустановленного скрипта + + + + By custom script + Из пользовательского скрипта + + + + Warning: do not forget to install external tracker if availble! + Внимание: не забывайте установить внешний трэкер, если он доступен! + + + + Custom script: + Пользовательский скрипт: + + + + Apply + Применить + + + + Developer tools: + Инструменты разработчика: + + + + Start debuging current script + Начать отладку текущего скрипта + + + + Debug data: + Отладочная информация: + + + + Application Name or Class: + Название или класс приложения: + + + + Application title: + Заголовок приложения: + + + + Script result: + Результат работы скрипта: + + + + Place title parser code here. Look predefined scripts for example. + Впишите здесь код для разбора заголовка окна. Посмотрите предустановленные скрипты для примера. + + ApplicationsWindow - + Applications Приложения - + Profiles Профили - + Edit... Редактировать... - + Categories and Applications: Категории и Приложения: - + + Show hidden objects + Показывать скрытые объекты + + + <html><head/><body><p>Drag &amp; press &quot;Control&quot; before Drop to move application into a same category in all profiles.</p><p>Drag &amp; Drop application without &quot;Contol&quot; to move application into a category only in current profile.</p></body></html> <html><head/><body><p>Захватите и зажмите &quot;Control&quot; прежде чем отпустить чтобы переместить приложение в одну и туже категорю во всех профилях.</p><p>Захватите и отпустите приложение без &quot;Contol&quot; чтобы переместить приложение в категорию только в текущем профиле.</p></body></html> - + Uncategorized Без категории - + + (default) + (по умолчанию) + + + New category Новая категория - + Delete category Удалить категорию - + Set category color Установить цвет категории - + + Hide activity + Скрыть активность + + + + Show activity + Показать активность + + + + Settings... + Настройки... + + + New Category Новая категория + + NotificationWindow + + + Notification Window + Окно уведомления + + + + Category + Категория + + + + Set for all profiles. + Установить для всех профилей + + + + Set for current profile + Установить для текущего профиля + + + + + UNKNOWN + НЕИЗВЕСТНО + + + + NONE + НЕТ + + + + default + по умолчанию + + + + Uncategorized + Без категории + + ProfilesWindow - + Profiles Профили - + New profile Новый профиль - + Clone profile Клонировать профиль - + Merge profiles Объединить профили - + New Profile Новый профиль - - + + Incorrect arguments Не корректные аргументы - + Please select one and only one profile for cloning Пожалуйста выберите один и только один профиль для клонирования - + copy копия - + Please select at least two profiles for merging Пожалуйста выберите как минимум два профиля для объединения - + Data will be lost Данные будут потеряны - + Warning! After the merging uniqe difference between profiles will be lost. This operation can't be undone. Proceed? Внимание! После объединения уникальные различия между профилями будут потеряны. Эту операцию невозможно отменить. Продолжить? + + ScheduleWindow + + + + Schedule + Расписание + + + + New schedule record: + Новая запись в расписании: + + + + Action + Действие + + + + Profile + Профиль + + + + Condition(e.g .*15:37 or .*Mon.*12:40 ) + Условие(например .*15:37 или .*Пон.*12:40) + + + + <html><head/><body><p>Regular Expressions syntax: <a href="https://doc.qt.io/qt-4.8/qregexp.html#introduction"><span style=" text-decoration: underline; color:#0000ff;">https://doc.qt.io/qt-4.8/qregexp.html#introduction</span></a></p></body></html> + <html><head/><body><p>Синтаксис регулярных выражений: <a href="https://doc.qt.io/qt-4.8/qregexp.html#introduction"><span style=" text-decoration: underline; color:#0000ff;">https://doc.qt.io/qt-4.8/qregexp.html#introduction</span></a></p></body></html> + + + + Current date and time: + Текущее время и дата: + + + + Add new record + Добавить новую запись + + + + Delete selected record + Удалить текущую запись + + SettingsWindow - + Settings Настройки - How often check system state(seconds): - Как часто считывать состояние системы(в секундах): + Как часто считывать состояние системы(в секундах): - + Duration of inactivity before falling asleep(seconds): Продолжительность бездействия перед переходом в режим сна(в секундах): - + Autosave: how often save db(seconds): Автосохранение: как часто сохранять БД(в секундах): - + Language(need restart): Язык(требуется перезапуск): - + Storage File Name: Имя Файла Хранилища БД: - + Browse... Просмотр... - + + Send data to another host: + Отправлять данные на другой сервер: + + + + Notifications + Уведомления + + + + No notifications + Без уведомлений + + + + System notification system + Системные уведомления + + + + Built-in notification system: + Встроенные уведомления: + + + + Set window position and size + Установить размер и позицию + + + + Reset window position + Сбросить позицию + + + + Hide after(seconds): + Скрывать по таймеру(секунды): + + + + Opacity(percents) + Непрозрачность(в процентах): + + + + Mouse interactions + Реакция на мышь + + + + Hide notification on mouse move and never show category selection menu + Скрывать уведомление при движении мыши и никогда не показывать выбор категории + + + + Never hide notification on mouse move(hide only by timer) and show category selection menu if category not selected + Не скрывать при движении мыши(скрывать по таймеру) и показывать выбор, если категория не указана + + + + Hide notification on some mouse moves and show category selection meny if category not selected(recomended) + Скрывать при нескольких движениях мыши и показывать выбор, если категория не указана(Рекомендуется) + + + + Message format: + Формат сообщения: + + + + Set default message + Установить стандартное сообщение + + + Apply Применить - + Cancel Отменить - + Launch on Start up Запускать при старте системы - Show baloon when category changed - Показывать сообщение в трее, когда меняется категория + Показывать сообщение в трее, когда меняется категория + + + + <center>Current profile: %PROFILE%<br>Application: %APP_NAME%<br>State: %APP_STATE%<br>Category: %APP_CATEGORY%</center> + <center>Текущий профиль: %PROFILE%<br>Приложение: %APP_NAME%<br>Состояние: %APP_STATE%<br>Категория: %APP_CATEGORY%</center> - + Select DB location Выберите местоположение БД - + Default DB (db.bin);;All files (*.*) Стандартая БД (db.bin);;Все файлы(*.*) @@ -243,62 +531,91 @@ StatisticWindow - + Statistic Статистика - Set today>> - Установить сегодняшний день>> + Установить сегодняшний день>> + + + + Today + Сегодня + + + + This week + Эта неделя + + + + This month + Этот месяц + + + + This year + Этот год + + + + >> + >> - + From С - + to до - + Update Обновить - + Export categories to CSV... Экспорт категорий в CSV... - + Export applications to CSV... Экспорт приложений в CSV... - + Absolute time Абсолютное время - + Relative time Относительное время - + Uncategorized Без категории - + + (default) + (по умолчанию) + + + Select applications file Выберите файл приложений - + Select categories file Выберите файл категорий @@ -306,25 +623,33 @@ cDataManager - + Default По умолчанию - + Uncategorized Без категории + + cScheduleItem + + + Set profile + Установить профиль + + cStatisticDiagramWidget - + NO DATA НЕТ ДАННЫХ - + Other categories Остальные категории @@ -332,34 +657,72 @@ cTrayIcon - + Profiles Профили - + Applications... Приложения... - + Statistic... Статистика... - + Settings... Настройки... - + + Schedule... + Расписание... + + + About... О приложении... - + + Help... + Помощь... + + + Exit Выход + + + https://github.com/Allexin/TrackYourTime/wiki/User-Manual + https://github.com/Allexin/TrackYourTime/wiki/%D0%A0%D1%83%D0%BA%D0%BE%D0%B2%D0%BE%D0%B4%D1%81%D1%82%D0%B2%D0%BE-%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8F + + + + notification_dummy + + + Set position and size + Установить размер и позицию + + + + Category: + Категория: + + + + Apply + Применить + + + + Close + Закрыть + diff --git a/TrackYourTime/main.cpp b/TrackYourTime/main.cpp index a3d15e3..05af649 100644 --- a/TrackYourTime/main.cpp +++ b/TrackYourTime/main.cpp @@ -22,16 +22,19 @@ #include "ui/profileswindow.h" #include "ui/aboutwindow.h" #include "ui/app_settingswindow.h" +#include "ui/schedulewindow.h" #include #include #include #include #include -#include +#include "tools/tools.h" #include #include #include "data/cdatamanager.h" +#include "data/cschedule.h" #include "ui/ctrayicon.h" +#include "ui/notificationwindow.h" int main(int argc, char *argv[]) { @@ -56,54 +59,80 @@ int main(int argc, char *argv[]) #endif + qDebug() << "application start\n"; - QSettings settings; + cSettings settings; QString Language = QLocale::system().name(); Language.truncate(Language.lastIndexOf('_')); - Language = settings.value(cDataManager::CONF_LANGUAGE_ID,Language).toString(); - if (settings.value(cDataManager::CONF_FIRST_LAUNCH_ID,true).toBool()){ - settings.setValue(cDataManager::CONF_FIRST_LAUNCH_ID,false); - settings.setValue(cDataManager::CONF_LANGUAGE_ID,Language); - settings.setValue(cDataManager::CONF_AUTORUN_ID,true); + Language = settings.db()->value(cDataManager::CONF_LANGUAGE_ID,Language).toString(); + if (settings.db()->value(cDataManager::CONF_FIRST_LAUNCH_ID,true).toBool()){ + settings.db()->setValue(cDataManager::CONF_FIRST_LAUNCH_ID,false); + settings.db()->setValue(cDataManager::CONF_LANGUAGE_ID,Language); + settings.db()->setValue(cDataManager::CONF_AUTORUN_ID,true); setAutorun(); - settings.sync(); + settings.db()->sync(); } + qDebug() << "laod translation\n"; QTranslator translator; translator.load("lang_" + Language,QDir::currentPath()+"/data/languages"); QApplication::installTranslator(&translator); + qDebug() << "init datamanager\n"; cDataManager datamanager; + qDebug() << "init schedule\n"; + cSchedule schedule(&datamanager); + qDebug() << "init tray icon\n"; cTrayIcon trIcon(&datamanager); QObject::connect(&datamanager, SIGNAL(trayActive()), &trIcon, SLOT(setActive())); QObject::connect(&datamanager, SIGNAL(traySleep()), &trIcon, SLOT(setInactive())); QObject::connect(&datamanager, SIGNAL(trayShowHint(QString)), &trIcon, SLOT(showHint(QString))); QObject::connect(&datamanager, SIGNAL(profilesChanged()), &trIcon, SLOT(onProfilesChange())); + qDebug() << "init applications window\n"; ApplicationsWindow applicationsWindow(&datamanager); QObject::connect(&trIcon, SIGNAL(showApplications()), &applicationsWindow, SLOT(show())); QObject::connect(&datamanager, SIGNAL(profilesChanged()), &applicationsWindow, SLOT(onProfilesChange())); QObject::connect(&datamanager, SIGNAL(applicationsChanged()), &applicationsWindow, SLOT(onApplicationsChange())); + qDebug() << "init profiles window\n"; ProfilesWindow profilesWindow(&datamanager); QObject::connect(&applicationsWindow, SIGNAL(showProfiles()), &profilesWindow, SLOT(show())); + qDebug() << "init app settings window\n"; App_SettingsWindow app_settingsWindow(&datamanager); QObject::connect(&applicationsWindow, SIGNAL(showAppSettings(int)), &app_settingsWindow, SLOT(showApp(int))); QObject::connect(&datamanager, SIGNAL(debugScriptResult(QString,sSysInfo)), &app_settingsWindow, SLOT(onScriptResult(QString,sSysInfo))); + qDebug() << "init settings window\n"; SettingsWindow settingsWindow(&datamanager); QObject::connect(&trIcon, SIGNAL(showSettings()), &settingsWindow, SLOT(show())); QObject::connect(&settingsWindow, SIGNAL(preferencesChange()), &datamanager, SLOT(onPreferencesChanged())); + qDebug() << "init schedule window\n"; + ScheduleWindow scheduleWindow(&datamanager,&schedule); + QObject::connect(&datamanager, SIGNAL(profilesChanged()), &scheduleWindow, SLOT(rebuild())); + QObject::connect(&trIcon, SIGNAL(showSchedule()), &scheduleWindow, SLOT(show())); + + qDebug() << "init statistic window\n"; StatisticWindow statisticWindow(&datamanager); QObject::connect(&trIcon, SIGNAL(showStatistic()), &statisticWindow, SLOT(show())); + qDebug() << "init about window\n"; AboutWindow aboutWindow; QObject::connect(&trIcon, SIGNAL(showAbout()), &aboutWindow, SLOT(show())); - int result = a.exec(); + qDebug() << "init notification window\n"; + NotificationWindow notificationWindow(&datamanager); + QObject::connect(&settingsWindow, SIGNAL(preferencesChange()), ¬ificationWindow, SLOT(onPreferencesChanged())); + QObject::connect(&datamanager, SIGNAL(showNotification()), ¬ificationWindow, SLOT(onShow())); + qDebug() << "start schedule\n"; + schedule.start(); + + qDebug() << "start app loop\n"; + int result = a.exec(); + qDebug() << "application close\n"; return result; } diff --git a/TrackYourTime/tools/os_api.cpp b/TrackYourTime/tools/os_api.cpp index 005824e..2cd013f 100644 --- a/TrackYourTime/tools/os_api.cpp +++ b/TrackYourTime/tools/os_api.cpp @@ -65,6 +65,11 @@ void writeStringListToFile(QStringList& lines, const QString& FileName, const QS #ifdef Q_OS_WIN #include +QString getUserName() +{ + return qgetenv("USERNAME"); +} + typedef BOOL (__stdcall *GetProcessImageFileNamePtr)(HANDLE, char* ,DWORD); class cGetProcessImageFileName{ @@ -94,12 +99,10 @@ class cGetProcessImageFileName{ } }; -QString getWindowApplication(HWND Wnd) +QString GetAppNameFromPID(DWORD pid) { static cGetProcessImageFileName processFileName; - QString appFileName; - DWORD pid; - GetWindowThreadProcessId(Wnd, &pid); + QString appFileName = ""; HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION , FALSE, pid); if (hProcess != 0){ try { @@ -117,14 +120,58 @@ QString getWindowApplication(HWND Wnd) return appFileName; } -sAppFileName getCurrentApplication() +struct sAppPIDs{ + DWORD ownerPID; + DWORD childPID; +}; + +BOOL CALLBACK EnumChildWindowsProc(HWND wnd, LPARAM lp) { - QFileInfo fileInfo(getWindowApplication(GetForegroundWindow())); - sAppFileName fileName; - fileName.fileName = fileInfo.fileName(); - fileName.path = fileInfo.absolutePath(); + sAppPIDs* pids = (sAppPIDs*)lp; + DWORD pid = 0; + GetWindowThreadProcessId(wnd, &pid); + if (pid!=pids->ownerPID) + pids->childPID = pid; + return TRUE; +} - return fileName; +QString getWindowApplicationModernWin(HWND wnd, DWORD pid) +{ + sAppPIDs pids; + pids.childPID = pid; + pids.ownerPID = pid; + EnumChildWindows(wnd,EnumChildWindowsProc,(LPARAM)&pids); + return GetAppNameFromPID(pids.childPID); +} + +QString getWindowApplication(HWND wnd) +{ + QString appFileName; + DWORD pid; + GetWindowThreadProcessId(wnd, &pid); + appFileName = GetAppNameFromPID(pid); + QFileInfo fInfo(appFileName); + QString fName = fInfo.baseName().toUpper(); + if (fName=="WWAHOST" || fName=="APPLICATIONFRAMEHOST"){ + return getWindowApplicationModernWin(wnd,pid); + } + + return appFileName; +} + +sSysInfo getCurrentApplication() +{ + HWND wnd = GetForegroundWindow(); + QFileInfo fileInfo(getWindowApplication(wnd)); + sSysInfo appInfo; + appInfo.fileName = fileInfo.fileName().simplified(); + appInfo.path = fileInfo.absolutePath().simplified(); + char title[256]; + int l = GetWindowTextA(wnd,title,256); + if (l>0) + appInfo.title = title.simplified(); + + return appInfo; } static bool KeyboardState[256]; @@ -170,6 +217,11 @@ void removeAutorun() #include #include +QString getUserName() +{ + return qgetenv("USER"); +} + bool GetActiveWindowClassAndTitle(QString& windowClass,QString& windowTitle) { Display *display = XOpenDisplay(NULL); @@ -228,8 +280,8 @@ sSysInfo getCurrentApplication() QString windowClass; QString windowTitle; if (GetActiveWindowClassAndTitle(windowClass,windowTitle)){ - fileInfo.fileName = windowClass; - fileInfo.title = windowTitle; + fileInfo.fileName = windowClass.simplified(); + fileInfo.title = windowTitle.simplified(); } return fileInfo; @@ -249,18 +301,24 @@ struct sKeyboardState{ }; QVector keyboards; +void initKeyboard(const QString& path, const QString& regexp){ + QStringList keyboardsList = QDir(path).entryList(QStringList() << regexp); + keyboards.resize(keyboardsList.size()); + for (int i = 0; iid = path+keyboardsList[i]; + + } +} bool isKeyboardChanged() { if (firstKeyboardUpdate){ firstKeyboardUpdate = false; - QStringList keyboardsList = QDir("/dev/input/by-id/").entryList(QStringList() << "*keyboard*"); - keyboards.resize(keyboardsList.size()); - for (int i = 0; iid = "/dev/input/by-id/"+keyboardsList[i]; - - } + initKeyboard("/dev/input/by-id/","*keyboard*"); + initKeyboard("/dev/input/by-id/","*kbd*"); + initKeyboard("/dev/input/by-path/","*keyboard*"); + initKeyboard("/dev/input/by-path/","*kbd*"); } bool noAccesToKeyboard = true; @@ -332,6 +390,11 @@ void removeAutorun() #include #include +QString getUserName() +{ + return qgetenv("USER"); +} + QString uniCFStrToQStr(const CFStringRef cfString) { QChar qchar; @@ -346,9 +409,10 @@ QString uniCFStrToQStr(const CFStringRef cfString) } -sAppFileName getCurrentApplication() +sSysInfo getCurrentApplication() { QString appOwner; + QString appTitle; //get visible windows from front to back. first window with layer 0 - current window CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID); @@ -376,20 +440,23 @@ sAppFileName getCurrentApplication() */ dictionary = (CFDictionaryRef) CFArrayGetValueAtIndex(windowList, cfiI); CFStringRef owner = reinterpret_cast(CFDictionaryGetValue(dictionary,kCGWindowOwnerName)); + CFStringRef title = reinterpret_cast(CFDictionaryGetValue(dictionary,kCGWindowName)); CFNumberRef window_layer = reinterpret_cast(CFDictionaryGetValue(dictionary, kCGWindowLayer)); int layer; CFNumberGetValue(window_layer, kCFNumberIntType, &layer); if (layer==0){ appOwner = uniCFStrToQStr(owner); + appTitle = uniCFStrToQStr(title); break; } } - sAppFileName fileName; - fileName.fileName = appOwner; - fileName.path = ""; + sSysInfo fileInfo; + fileInfo.fileName = appOwner.simplified(); + fileInfo.path = ""; + fileInfo.title = appTitle.simplified(); - return fileName; + return fileInfo; } //i know, this is wrong way. but it's simple, and i do not need slot/signals functionaloty in this part of code. @@ -401,6 +468,8 @@ class cMacOSXKeyboardThread : public QThread // The following callback method is invoked on every keypress. static CGEventRef CGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) { + Q_UNUSED(proxy) + Q_UNUSED(refcon) if (type != kCGEventKeyDown && type != kCGEventFlagsChanged && type != kCGEventKeyUp) { return event; } @@ -415,7 +484,7 @@ class cMacOSXKeyboardThread : public QThread m_KeyboardChanged = false; CGEventMask eventMask = (CGEventMaskBit(kCGEventKeyDown) | CGEventMaskBit(kCGEventFlagsChanged)); - CFMachPortRef eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, 0, eventMask, CGEventCallback, NULL ); + CFMachPortRef eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, eventMask, CGEventCallback, NULL ); if(!eventTap) { qCritical() << "ERROR: Unable to create event tap.\n"; diff --git a/TrackYourTime/tools/os_api.h b/TrackYourTime/tools/os_api.h index 5c530d4..fcf6cb4 100644 --- a/TrackYourTime/tools/os_api.h +++ b/TrackYourTime/tools/os_api.h @@ -29,9 +29,12 @@ struct sSysInfo{ }; sSysInfo getCurrentApplication(); + bool isKeyboardChanged(); QPoint getMousePos(); +QString getUserName(); + void setAutorun(); void removeAutorun(); diff --git a/TrackYourTime/tools/tools.cpp b/TrackYourTime/tools/tools.cpp index 491bc38..5efee48 100644 --- a/TrackYourTime/tools/tools.cpp +++ b/TrackYourTime/tools/tools.cpp @@ -3,6 +3,7 @@ #include #include #include +#include QMap loadPairsFile(const QString& fileName){ QMap list; @@ -31,3 +32,36 @@ QString readFile(const QString &fileName) } return QString(); } + +cSettings::cSettings() +{ + QString OSName = "UNKNOWN"; +#ifdef Q_OS_LINUX + OSName="Linux"; +#else + #ifdef Q_OS_WIN + OSName="Linux"; + #else + #ifdef Q_OS_MAC + OSName="MacOSX"; + #endif + #endif +#endif + if (QFileInfo("settings_"+OSName+".conf").exists()) + m_Settings = new QSettings("settings_"+OSName+".conf",QSettings::IniFormat); + else + if (QFileInfo("settings.conf").exists()) + m_Settings = new QSettings("settings.conf",QSettings::IniFormat); + else + m_Settings = new QSettings(); +} + +cSettings::~cSettings() +{ + delete m_Settings; +} + +QSettings *cSettings::db() +{ + return m_Settings; +} diff --git a/TrackYourTime/tools/tools.h b/TrackYourTime/tools/tools.h index cb3fcd2..6f451b7 100644 --- a/TrackYourTime/tools/tools.h +++ b/TrackYourTime/tools/tools.h @@ -3,8 +3,19 @@ #include #include +#include QMap loadPairsFile(const QString& fileName); QString readFile(const QString& fileName); +class cSettings{ +protected: + QSettings* m_Settings; +public: + cSettings(); + ~cSettings(); + + QSettings* db(); +}; + #endif // TOOLS_H diff --git a/TrackYourTime/ui/app_settingswindow.cpp b/TrackYourTime/ui/app_settingswindow.cpp index e2a0891..b27666e 100644 --- a/TrackYourTime/ui/app_settingswindow.cpp +++ b/TrackYourTime/ui/app_settingswindow.cpp @@ -10,7 +10,9 @@ App_SettingsWindow::App_SettingsWindow(cDataManager *DataManager) : ui->setupUi(this); m_DataManager = DataManager; +#if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) ui->plainTextEditScript->setPlaceholderText("Place title parser code here. Look predefined scripts for example."); +#endif connect(ui->pushButtonApply,SIGNAL(released()),this,SLOT(onApply())); connect(ui->pushButtonStartDebug,SIGNAL(released()),this,SLOT(onSetDebug())); } diff --git a/TrackYourTime/ui/app_settingswindow.ui b/TrackYourTime/ui/app_settingswindow.ui index 2252d83..7f1ce4c 100644 --- a/TrackYourTime/ui/app_settingswindow.ui +++ b/TrackYourTime/ui/app_settingswindow.ui @@ -11,7 +11,7 @@ - Dialog + Application settings @@ -135,6 +135,12 @@ + + + 0 + 0 + + Apply @@ -149,6 +155,12 @@ + + + 0 + 0 + + Start debuging current script diff --git a/TrackYourTime/ui/applicationswindow.cpp b/TrackYourTime/ui/applicationswindow.cpp index 40d6b5a..6798e1d 100644 --- a/TrackYourTime/ui/applicationswindow.cpp +++ b/TrackYourTime/ui/applicationswindow.cpp @@ -19,6 +19,7 @@ #include "applicationswindow.h" #include "ui_applicationswindow.h" #include +#include void ApplicationsWindow::rebuildProfilesList() { @@ -32,20 +33,29 @@ void ApplicationsWindow::rebuildProfilesList() m_LoadingData = false; } -QTreeWidgetItem* createTreeItemCategory(int index, QColor color, const QString& text){ +QIcon createColorIcon(QColor color){ QPixmap pixmap(16,16); pixmap.fill(color); - QIcon icon(pixmap); + return QIcon(pixmap); +} +QTreeWidgetItem* createTreeItemCategory(int index, QColor color, const QString& text){ QTreeWidgetItem* item = new QTreeWidgetItem(cApplicationsTreeWidget::TREE_ITEM_TYPE_CATEGORY); item->setText(0,text); - item->setIcon(0,icon); + item->setIcon(0,createColorIcon(color)); item->setData(0,Qt::UserRole,index); return item; } void ApplicationsWindow::rebuildApplicationsList() { + m_CategoriesExpandedState.resize(ui->treeWidgetApplications->topLevelItemCount()); + for (int i = 0; itreeWidgetApplications->topLevelItem(i); + m_CategoriesExpandedState[i] = item?item->isExpanded():false; + } + m_ScrollPos = ui->treeWidgetApplications->verticalScrollBar()->value(); + //create categories QVector categories; categories.resize(m_DataManager->categoriesCount()); @@ -55,8 +65,7 @@ void ApplicationsWindow::rebuildApplicationsList() categories[i] = createTreeItemCategory(i,category->color,category->name); categories[i]->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDropEnabled | Qt::ItemIsEnabled); ui->treeWidgetApplications->addTopLevelItem(categories[i]); - - } + } QTreeWidgetItem* uncategorized = createTreeItemCategory(-1,QColor(Qt::gray),tr("Uncategorized")); uncategorized->setFlags(Qt::ItemIsDropEnabled | Qt::ItemIsEnabled); ui->treeWidgetApplications->addTopLevelItem(uncategorized); @@ -68,70 +77,79 @@ void ApplicationsWindow::rebuildApplicationsList() for (int i = 0; iapplicationsCount(); i++){ const sAppInfo* app = m_DataManager->applications(i); - QVector app_in_categories; - app_in_categories.resize(categories.size()); - for (int j = 0; jactivities.size(); j++){ - const sActivityInfo* ainfo = &app->activities[j]; - if (showHidden || ainfo->visible){ - QTreeWidgetItem* parent = NULL; - if (app->activities[j].categories[currentProfile]==-1){ - parent = app_uncategorized; - if (parent==NULL){ - QTreeWidgetItem* item = new QTreeWidgetItem(cApplicationsTreeWidget::TREE_ITEM_TYPE_APPLICATION); - item->setText(0,app->activities[0].name); - item->setToolTip(0,app->path+"/"+app->activities[0].name); - item->setData(0,Qt::UserRole,i); - if (app->trackerType==sAppInfo::eTrackerType::TT_EXTERNAL_DETECTOR) - item->setIcon(0,m_ExternalDetector); - else - if (app->trackerType==sAppInfo::eTrackerType::TT_CUSTOM_SCRIPT || app->trackerType==sAppInfo::eTrackerType::TT_PREDEFINED_SCRIPT) - item->setIcon(0,m_ScriptDetector); - item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); - uncategorized->addChild(item); - app_uncategorized = item; - parent = item; + if (showHidden || app->visible){ + QVector app_in_categories; + app_in_categories.resize(categories.size()); + for (int j = 0; jactivities.size(); j++){ + const sActivityInfo* ainfo = &app->activities[j]; + if (showHidden || ainfo->visible){ + QTreeWidgetItem* parent = NULL; + if (app->activities[j].categories[currentProfile]==-1){ + parent = app_uncategorized; + if (parent==NULL){ + QTreeWidgetItem* item = new QTreeWidgetItem(cApplicationsTreeWidget::TREE_ITEM_TYPE_APPLICATION); + item->setText(0,app->activities[0].name); + item->setToolTip(0,app->path+"/"+app->activities[0].name); + item->setData(0,Qt::UserRole,i); + if (app->trackerType==sAppInfo::eTrackerType::TT_EXTERNAL_DETECTOR) + item->setIcon(0,m_ExternalDetector); + else + if (app->trackerType==sAppInfo::eTrackerType::TT_CUSTOM_SCRIPT || app->trackerType==sAppInfo::eTrackerType::TT_PREDEFINED_SCRIPT) + item->setIcon(0,m_ScriptDetector); + else + item->setIcon(0,createColorIcon(QColor(Qt::gray))); + item->setFlags(Qt::ItemIsEnabled); + uncategorized->addChild(item); + app_uncategorized = item; + parent = item; + } } - } - else{ - parent = app_in_categories[app->activities[j].categories[currentProfile]]; - if (parent==NULL){ - QTreeWidgetItem* item = new QTreeWidgetItem(cApplicationsTreeWidget::TREE_ITEM_TYPE_APPLICATION); - item->setText(0,app->activities[0].name); - item->setToolTip(0,app->path+"/"+app->activities[0].name); - item->setData(0,Qt::UserRole,i); - if (app->trackerType==sAppInfo::eTrackerType::TT_EXTERNAL_DETECTOR) - item->setIcon(0,m_ExternalDetector); - else - if (app->trackerType==sAppInfo::eTrackerType::TT_CUSTOM_SCRIPT || app->trackerType==sAppInfo::eTrackerType::TT_PREDEFINED_SCRIPT) - item->setIcon(0,m_ScriptDetector); - item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); - categories[app->activities[j].categories[currentProfile]]->addChild(item); - app_in_categories[app->activities[j].categories[currentProfile]] = item; - parent = item; + else{ + parent = app_in_categories[app->activities[j].categories[currentProfile]]; + if (parent==NULL){ + const sCategory* category = m_DataManager->categories(app->activities[j].categories[currentProfile]); + QTreeWidgetItem* item = new QTreeWidgetItem(cApplicationsTreeWidget::TREE_ITEM_TYPE_APPLICATION); + item->setText(0,app->activities[0].name); + item->setToolTip(0,app->path+"/"+app->activities[0].name); + item->setData(0,Qt::UserRole,i); + if (app->trackerType==sAppInfo::eTrackerType::TT_EXTERNAL_DETECTOR) + item->setIcon(0,m_ExternalDetector); + else + if (app->trackerType==sAppInfo::eTrackerType::TT_CUSTOM_SCRIPT || app->trackerType==sAppInfo::eTrackerType::TT_PREDEFINED_SCRIPT) + item->setIcon(0,m_ScriptDetector); + else + item->setIcon(0,createColorIcon(category->color)); + item->setFlags(Qt::ItemIsEnabled); + categories[app->activities[j].categories[currentProfile]]->addChild(item); + app_in_categories[app->activities[j].categories[currentProfile]] = item; + parent = item; + } } - } - QTreeWidgetItem* item = new QTreeWidgetItem(cApplicationsTreeWidget::TREE_ITEM_TYPE_APPLICATION_ACTIVITY); - if (j==0) - item->setText(0,ainfo->name+tr("(default)")); - else - item->setText(0,ainfo->name); - item->setData(0,Qt::UserRole,i); - item->setData(0,Qt::UserRole+1,j); - item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled); - parent->addChild(item); + QTreeWidgetItem* item = new QTreeWidgetItem(cApplicationsTreeWidget::TREE_ITEM_TYPE_APPLICATION_ACTIVITY); + if (j==0) + item->setText(0,ainfo->name+tr("(default)")); + else + item->setText(0,ainfo->name); + item->setData(0,Qt::UserRole,i); + item->setData(0,Qt::UserRole+1,j); + item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled); + parent->addChild(item); + } } } } - //expand all categories - uncategorized->setExpanded(true); - for (int i = 0; isetExpanded(true); + for (int i = 0; icategoriesCount(); i++) + if (isetExpanded(m_CategoriesExpandedState[i]); + if (categories.size()+1setExpanded(categories.size()+1); + ui->treeWidgetApplications->verticalScrollBar()->setValue(m_ScrollPos); } ApplicationsWindow::ApplicationsWindow(cDataManager *DataManager) : QMainWindow(0), @@ -163,6 +181,7 @@ ApplicationsWindow::ApplicationsWindow(cDataManager *DataManager) : QMainWindow( ui->treeWidgetApplications->setDragEnabled(true); ui->treeWidgetApplications->setDragDropMode(QAbstractItemView::InternalMove); connect(ui->treeWidgetApplications,SIGNAL(itemMoved(QTreeWidgetItem*,QTreeWidgetItem*)),this,SLOT(onApplicationMoved(QTreeWidgetItem*,QTreeWidgetItem*))); + connect(ui->treeWidgetApplications,SIGNAL(needRebuild()),this,SLOT(onDelayedRebuild())); connect(ui->treeWidgetApplications, SIGNAL (itemChanged(QTreeWidgetItem *, int)),this, SLOT (onCategoryChanged(QTreeWidgetItem *, int))); @@ -178,6 +197,8 @@ ApplicationsWindow::~ApplicationsWindow() void ApplicationsWindow::showEvent(QShowEvent *event) { QMainWindow::showEvent( event ); + m_ScrollPos = 0; + m_CategoriesExpandedState.clear(); rebuildProfilesList(); rebuildApplicationsList(); } @@ -195,6 +216,7 @@ void ApplicationsWindow::onApplicationsChange() void ApplicationsWindow::onCategoryChanged(QTreeWidgetItem *item, int column) { + Q_UNUSED(column) if (item->type()==cApplicationsTreeWidget::TREE_ITEM_TYPE_CATEGORY){ int categoryIndex = item->data(0,Qt::UserRole).toInt(); if (categoryIndex>-1) @@ -205,6 +227,7 @@ void ApplicationsWindow::onCategoryChanged(QTreeWidgetItem *item, int column) void ApplicationsWindow::onContextMenu(const QPoint &pos) { QTreeWidgetItem *item = ui->treeWidgetApplications->itemAt( pos ); + m_ContextMenuItem = item; bool canEditItem = false; bool canHideItem = false; bool canShowItem = false; @@ -240,9 +263,8 @@ void ApplicationsWindow::onContextMenu(const QPoint &pos) if (id=="APP_SETTINGS"){ actions[i]->setVisible(haveSettings); } - }\ + } - QPoint pt(pos); m_CategoriesMenu.exec( ui->treeWidgetApplications->mapToGlobal(pos) ); } @@ -280,15 +302,12 @@ void ApplicationsWindow::onMenuSelection(QAction *menuAction) delete itemsToDelete[i]; } if (id=="APP_SETTINGS"){ - QList items = ui->treeWidgetApplications->selectedItems(); - if (items.size()==1){ - QTreeWidgetItem* item = items.first(); - if (item->type()==cApplicationsTreeWidget::TREE_ITEM_TYPE_APPLICATION){ - int index = item->data(0,Qt::UserRole).toInt(); + if (m_ContextMenuItem) + if (m_ContextMenuItem->type()==cApplicationsTreeWidget::TREE_ITEM_TYPE_APPLICATION){ + int index = m_ContextMenuItem->data(0,Qt::UserRole).toInt(); if (index>-1) emit showAppSettings(index); } - } return; } if (id=="NEW_CATEGORY_MENU"){ @@ -345,3 +364,8 @@ void ApplicationsWindow::onApplicationMoved(QTreeWidgetItem* item,QTreeWidgetIte m_DataManager->setApplicationActivityCategory(QApplication::keyboardModifiers()==Qt::ControlModifier?-1:m_DataManager->getCurrentProfileIndex(), item->data(0,Qt::UserRole).toInt(), item->data(0,Qt::UserRole+1).toInt(), newParent->data(0,Qt::UserRole).toInt()); } } + +void ApplicationsWindow::onDelayedRebuild() +{ + QTimer::singleShot(10,this,SLOT(onApplicationsChange())); +} diff --git a/TrackYourTime/ui/applicationswindow.h b/TrackYourTime/ui/applicationswindow.h index f6e81ac..c7ebb1c 100644 --- a/TrackYourTime/ui/applicationswindow.h +++ b/TrackYourTime/ui/applicationswindow.h @@ -44,11 +44,12 @@ class cApplicationsTreeWidget : public QTreeWidget QList selected = selectedItems(); for (int i = 0; i m_CategoriesExpandedState; + int m_ScrollPos; + QTreeWidgetItem* m_ContextMenuItem; protected: QMenu m_CategoriesMenu; QIcon m_ScriptDetector; @@ -71,8 +78,7 @@ class ApplicationsWindow : public QMainWindow explicit ApplicationsWindow(cDataManager* DataManager); ~ApplicationsWindow(); -private: - Ui::ApplicationsWindow *ui; + protected: virtual void showEvent(QShowEvent * event) override; signals: @@ -87,6 +93,7 @@ public slots: void onProfileSelection(int newProfileIndex); void onApplicationMoved(QTreeWidgetItem* item, QTreeWidgetItem* newParent); void onEditProfiles(){emit showProfiles();} + void onDelayedRebuild(); }; #endif // APPLICATIONSWINDOW_H diff --git a/TrackYourTime/ui/applicationswindow.ui b/TrackYourTime/ui/applicationswindow.ui index c9ad2fe..6a6bcf6 100644 --- a/TrackYourTime/ui/applicationswindow.ui +++ b/TrackYourTime/ui/applicationswindow.ui @@ -60,13 +60,26 @@ - + + + + 0 + 0 + + + + + + 0 + 0 + + - 100 + 16777215 16777215 @@ -87,7 +100,7 @@ - QAbstractItemView::MultiSelection + QAbstractItemView::ExtendedSelection false diff --git a/TrackYourTime/ui/ctrayicon.cpp b/TrackYourTime/ui/ctrayicon.cpp index 9675c3d..f8a8c84 100644 --- a/TrackYourTime/ui/ctrayicon.cpp +++ b/TrackYourTime/ui/ctrayicon.cpp @@ -18,6 +18,8 @@ #include "ctrayicon.h" #include +#include +#include @@ -39,6 +41,8 @@ cTrayIcon::cTrayIcon(cDataManager *DataManager):QSystemTrayIcon() m_DataManager = DataManager; rebuildMenu(); + connect(this,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),this,SLOT(onTray(QSystemTrayIcon::ActivationReason))); + connect(&m_ProfilesMenu, SIGNAL(triggered(QAction*)), this, SLOT(onMenuSelection(QAction*))); m_ProfilesMenu.setTitle(tr("Profiles")); @@ -48,6 +52,7 @@ cTrayIcon::cTrayIcon(cDataManager *DataManager):QSystemTrayIcon() m_Menu.addAction(tr("Statistic..."))->setData("STATISTIC"); m_Menu.addSeparator(); m_Menu.addAction(tr("Settings..."))->setData("SETTINGS"); + m_Menu.addAction(tr("Schedule..."))->setData("SCHEDULE"); m_Menu.addSeparator(); #ifdef Q_OS_WIN m_Menu.addMenu(&m_ProfilesMenu); @@ -56,6 +61,7 @@ cTrayIcon::cTrayIcon(cDataManager *DataManager):QSystemTrayIcon() #endif m_Menu.addSeparator(); m_Menu.addAction(tr("About..."))->setData("ABOUT"); + m_Menu.addAction(tr("Help..."))->setData("HELP"); m_Menu.addSeparator(); m_Menu.addAction(tr("Exit"))->setData("EXIT"); @@ -64,6 +70,12 @@ cTrayIcon::cTrayIcon(cDataManager *DataManager):QSystemTrayIcon() show(); } +void cTrayIcon::onTray(QSystemTrayIcon::ActivationReason reason) +{ + if (reason==QSystemTrayIcon::Trigger) + emit showApplications(); +} + void cTrayIcon::setActive() { #ifdef Q_OS_MAC @@ -117,6 +129,11 @@ void cTrayIcon::onMenuSelection(QAction *menuAction) return; } + if (id=="SCHEDULE"){ + emit showSchedule(); + return; + } + if (id=="STATISTIC"){ emit showStatistic(); return; @@ -127,6 +144,11 @@ void cTrayIcon::onMenuSelection(QAction *menuAction) return; } + if (id=="HELP"){ + QDesktopServices::openUrl(QUrl(tr("https://github.com/Allexin/TrackYourTime/wiki/User-Manual"))); + return; + } + if (id=="PROFILES"){ m_ProfilesMenu.popup(QCursor::pos()); return; diff --git a/TrackYourTime/ui/ctrayicon.h b/TrackYourTime/ui/ctrayicon.h index 1b2aaf6..e816910 100644 --- a/TrackYourTime/ui/ctrayicon.h +++ b/TrackYourTime/ui/ctrayicon.h @@ -48,10 +48,12 @@ protected slots: signals: void showSettings(); + void showSchedule(); void showStatistic(); void showApplications(); void showAbout(); public slots: + void onTray(QSystemTrayIcon::ActivationReason reason); void setActive(); void setInactive(); void showHint(QString text); diff --git a/TrackYourTime/ui/notification_dummy.cpp b/TrackYourTime/ui/notification_dummy.cpp new file mode 100644 index 0000000..c8b7b8f --- /dev/null +++ b/TrackYourTime/ui/notification_dummy.cpp @@ -0,0 +1,32 @@ +#include "notification_dummy.h" +#include "ui_notification_dummy.h" + +notification_dummy::notification_dummy(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::notification_dummy) +{ + ui->setupUi(this); + connect(ui->pushButtonApply,SIGNAL(released()),this,SLOT(onButtonApply())); + connect(ui->pushButtonClose,SIGNAL(released()),this,SLOT(hide())); +} + +notification_dummy::~notification_dummy() +{ + delete ui; +} + +void notification_dummy::showWithMessage(const QString &format, bool compactMode) +{ + ui->labelMessage->setText(format); + ui->comboBoxCategories->setVisible(!compactMode); + ui->labelCategory->setVisible(!compactMode); + + show(); +} + +void notification_dummy::onButtonApply() +{ + emit onApplyPosAndSize(); + hide(); +} + diff --git a/TrackYourTime/ui/notification_dummy.h b/TrackYourTime/ui/notification_dummy.h new file mode 100644 index 0000000..055c7fc --- /dev/null +++ b/TrackYourTime/ui/notification_dummy.h @@ -0,0 +1,27 @@ +#ifndef NOTIFICATION_DUMMY_H +#define NOTIFICATION_DUMMY_H + +#include + +namespace Ui { +class notification_dummy; +} + +class notification_dummy : public QMainWindow +{ + Q_OBJECT + +public: + explicit notification_dummy(QWidget *parent = 0); + ~notification_dummy(); + + void showWithMessage(const QString& format, bool compactMode); +private: + Ui::notification_dummy *ui; +signals: + void onApplyPosAndSize(); +public slots: + void onButtonApply(); +}; + +#endif // NOTIFICATION_DUMMY_H diff --git a/TrackYourTime/ui/notification_dummy.ui b/TrackYourTime/ui/notification_dummy.ui new file mode 100644 index 0000000..18c7f79 --- /dev/null +++ b/TrackYourTime/ui/notification_dummy.ui @@ -0,0 +1,115 @@ + + + notification_dummy + + + + 0 + 0 + 800 + 187 + + + + Set position and size + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + + + true + + + + + + + 0 + + + + + Category: + + + + + + + false + + + + 0 + 0 + + + + + + + + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Apply + + + + + + + Close + + + + + + + + + + + diff --git a/TrackYourTime/ui/notificationwindow.cpp b/TrackYourTime/ui/notificationwindow.cpp new file mode 100644 index 0000000..55f3fe9 --- /dev/null +++ b/TrackYourTime/ui/notificationwindow.cpp @@ -0,0 +1,158 @@ +#include "notificationwindow.h" +#include "ui_notificationwindow.h" +#include "../tools/tools.h" + +NotificationWindow::NotificationWindow(cDataManager *dataManager) : + QMainWindow(0,Qt::Dialog), + ui(new Ui::NotificationWindow) +{ + setWindowFlags(windowFlags() | Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint); + setAttribute(Qt::WA_ShowWithoutActivating); + ui->setupUi(this); + m_DataManager = dataManager; + onPreferencesChanged(); + + connect(&m_Timer,SIGNAL(timeout()),this,SLOT(onTimeout())); + connect(ui->pushButtonSetFoCurrentProfile,SIGNAL(released()),this,SLOT(onButtonSetCurrent())); + connect(ui->pushButtonSetForAllProfiles,SIGNAL(released()),this,SLOT(onButtonSetAll())); + ui->centralwidget->installEventFilter(this); + ui->groupBoxCategory->installEventFilter(this); + ui->labelMessage->installEventFilter(this); + ui->pushButtonSetFoCurrentProfile->installEventFilter(this); + ui->pushButtonSetForAllProfiles->installEventFilter(this); + ui->comboBoxCategory->installEventFilter(this); +} + +NotificationWindow::~NotificationWindow() +{ + delete ui; +} + +void NotificationWindow::enterEvent(QEvent *event) +{ + QMainWindow::enterEvent(event); + if (m_ClosingInterrupted) + return; + if (m_ConfMoves>0){ + m_EntersCount++; + if (m_EntersCount>=m_ConfMoves) + stop(); + } +} + +bool NotificationWindow::eventFilter(QObject *object, QEvent *event) +{ + Q_UNUSED(object) + if (event->type()==QEvent::MouseButtonPress && m_CanCloseInterrupt){ + m_ClosingInterrupted = true; + setWindowOpacity(1.0); + } + return false; +} + +void NotificationWindow::focusInEvent(QFocusEvent *event) +{ + m_ClosingInterrupted = true; + QMainWindow::focusInEvent(event); +} + +void NotificationWindow::stop() +{ + hide(); + m_Timer.stop(); +} + +void NotificationWindow::onButtonSetCurrent() +{ + if (m_AppIndex>-1){ + m_DataManager->applications(m_AppIndex)->activities[m_ActivityIndex].categories[m_DataManager->getCurrentProfileIndex()] = ui->comboBoxCategory->currentIndex(); + } + stop(); +} + +void NotificationWindow::onButtonSetAll() +{ + if (m_AppIndex>-1){ + for (int i = 0; iprofilesCount(); i++) + m_DataManager->applications(m_AppIndex)->activities[m_ActivityIndex].categories[i] = ui->comboBoxCategory->currentIndex(); + } + stop(); +} + +void NotificationWindow::onTimeout() +{ + if (m_ClosingInterrupted){ + m_Timer.stop(); + return; + } + m_TimerCounter++; + if (m_TimerCounter>=m_ConfDelay){ + stop(); + } +} + +void NotificationWindow::onPreferencesChanged() +{ + cSettings settings; + m_ConfMessageFormat = settings.db()->value(cDataManager::CONF_NOTIFICATION_MESSAGE_ID).toString(); + m_ConfPosition = settings.db()->value(cDataManager::CONF_NOTIFICATION_POSITION_ID).toPoint(); + m_ConfSize = settings.db()->value(cDataManager::CONF_NOTIFICATION_SIZE_ID).toPoint(); + m_ConfOpacity = settings.db()->value(cDataManager::CONF_NOTIFICATION_OPACITY_ID).toInt(); + m_ConfDelay = settings.db()->value(cDataManager::CONF_NOTIFICATION_HIDE_SECONDS_ID).toInt(); + m_ConfMoves = settings.db()->value(cDataManager::CONF_NOTIFICATION_HIDE_MOVES_ID).toInt(); +} + +void NotificationWindow::onShow() +{ + if (m_ClosingInterrupted && isVisible()) + return; + QString appName = tr("UNKNOWN"); + QString appState = tr("UNKNOWN"); + QString appCategory = tr("NONE"); + int profile = m_DataManager->getCurrentProfileIndex(); + int category = -1; + m_AppIndex = m_DataManager->getCurrentAppliction(); + if (m_AppIndex>-1){ + sAppInfo* info = m_DataManager->applications(m_AppIndex); + appName = info->activities[0].name; + m_ActivityIndex = m_DataManager->getCurrentApplictionActivity(); + if (m_ActivityIndex==0) + appState=tr("default"); + else + appState=info->activities[m_ActivityIndex].name; + category = info->activities[m_ActivityIndex].categories[profile]; + if (category==-1) + appCategory=tr("Uncategorized"); + else + appCategory=m_DataManager->categories(category)->name; + } + QString message = m_ConfMessageFormat; + message = message.replace("%PROFILE%",m_DataManager->profiles(profile)->name); + message = message.replace("%APP_NAME%",appName); + message = message.replace("%APP_STATE%",appState); + message = message.replace("%APP_CATEGORY%",appCategory); + ui->labelMessage->setText(message); + + if (category==-1 && m_AppIndex>-1 && m_ConfMoves!=1){ + ui->comboBoxCategory->clear(); + for (int i = 0; icategoriesCount(); i++) + ui->comboBoxCategory->addItem(m_DataManager->categories(i)->name); + ui->comboBoxCategory->setCurrentIndex(category); + + ui->groupBoxCategory->setVisible(true); + m_CanCloseInterrupt = true; + } + else{ + ui->groupBoxCategory->setVisible(false); + m_CanCloseInterrupt = false; + } + setWindowOpacity(m_ConfOpacity==100?1.0:m_ConfOpacity/100.f); + setGeometry(m_ConfPosition.x(),m_ConfPosition.y(),m_ConfSize.x(),0); + + m_TimerCounter = 0; + m_ClosingInterrupted = false; + m_EntersCount = 0; + m_Timer.start(1000); + + show(); +} diff --git a/TrackYourTime/ui/notificationwindow.h b/TrackYourTime/ui/notificationwindow.h new file mode 100644 index 0000000..ae3b33a --- /dev/null +++ b/TrackYourTime/ui/notificationwindow.h @@ -0,0 +1,51 @@ +#ifndef NOTIFICATIONWINDOW_H +#define NOTIFICATIONWINDOW_H + +#include +#include "../data/cdatamanager.h" + +namespace Ui { +class NotificationWindow; +} + +class NotificationWindow : public QMainWindow +{ + Q_OBJECT +protected: + cDataManager* m_DataManager; + QString m_ConfMessageFormat; + QPoint m_ConfPosition; + QPoint m_ConfSize; + int m_ConfOpacity; + int m_ConfDelay; + int m_ConfMoves; + + QTimer m_Timer; + int m_TimerCounter; + bool m_ClosingInterrupted; + int m_EntersCount; + bool m_CanCloseInterrupt; + + int m_AppIndex; + int m_ActivityIndex; +public: + explicit NotificationWindow(cDataManager* dataManager); + ~NotificationWindow(); + +private: + Ui::NotificationWindow *ui; +protected: + virtual void enterEvent(QEvent * event) override; + virtual bool eventFilter(QObject *object, QEvent *event) override; + virtual void focusInEvent(QFocusEvent * event) override; + void stop(); +protected slots: + void onButtonSetCurrent(); + void onButtonSetAll(); + void onTimeout(); +public slots: + void onPreferencesChanged(); + void onShow(); +}; + +#endif // NOTIFICATIONWINDOW_H diff --git a/TrackYourTime/ui/notificationwindow.ui b/TrackYourTime/ui/notificationwindow.ui new file mode 100644 index 0000000..8e53b2d --- /dev/null +++ b/TrackYourTime/ui/notificationwindow.ui @@ -0,0 +1,110 @@ + + + NotificationWindow + + + + 0 + 0 + 800 + 192 + + + + Notification Window + + + + + + + + + + + 0 + 0 + + + + + + + true + + + + + + + Category + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + true + + + + 0 + 0 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Set for all profiles. + + + + + + + Set for current profile + + + + + + + + + + + + + + diff --git a/TrackYourTime/ui/profileswindow.cpp b/TrackYourTime/ui/profileswindow.cpp index 00b98fb..386f337 100644 --- a/TrackYourTime/ui/profileswindow.cpp +++ b/TrackYourTime/ui/profileswindow.cpp @@ -70,7 +70,6 @@ void ProfilesWindow::onProfileChanged(QListWidgetItem *item) void ProfilesWindow::onContextMenu(const QPoint &pos) { - QPoint pt(pos); m_Menu.exec( ui->listWidgetProfiles->mapToGlobal(pos) ); } diff --git a/TrackYourTime/ui/schedulewindow.cpp b/TrackYourTime/ui/schedulewindow.cpp new file mode 100644 index 0000000..dd0d4b8 --- /dev/null +++ b/TrackYourTime/ui/schedulewindow.cpp @@ -0,0 +1,80 @@ +#include "schedulewindow.h" +#include "ui_schedulewindow.h" + +ScheduleWindow::ScheduleWindow(cDataManager *dataManager, cSchedule *schedule) : + QMainWindow(0), + ui(new Ui::ScheduleWindow) +{ + m_DataManager = dataManager; + m_Schedule = schedule; + ui->setupUi(this); + + connect(ui->pushButtonAdd,SIGNAL(released()),this,SLOT(add())); + connect(ui->pushButtonDelete,SIGNAL(released()),this,SLOT(remove())); +} + +ScheduleWindow::~ScheduleWindow() +{ + delete ui; +} + +void ScheduleWindow::rebuild() +{ + ui->comboBoxAction->clear(); + for (int i = 0; icomboBoxAction->addItem(cScheduleItem::getActionName((cScheduleItem::eScheduleAction)i),i); + ui->comboBoxAction->setCurrentIndex(0); + + ui->comboBoxProfiles->clear(); + for (int i = 0; iprofilesCount(); i++) + ui->comboBoxProfiles->addItem(m_DataManager->profiles(i)->name,i); + ui->comboBoxProfiles->setCurrentIndex(0); + ui->lineEditCondition->setText(QDateTime::currentDateTime().toString(".*HH:mm")); + + ui->treeWidgetSchedule->clear(); + for (int i = 0; igetItemsCount(); i++){ + const cScheduleItem* action = m_Schedule->getItem(i); + + QTreeWidgetItem* item = new QTreeWidgetItem(); + item->setText(0,cScheduleItem::getActionName(action->action())); + item->setData(0,Qt::UserRole,i); + if (action->action()==cScheduleItem::SA_SET_PROFILE){ + const sProfile* profile = m_DataManager->profiles(action->param().toInt()); + if (profile) + item->setText(1,profile->name); + } + + item->setText(2,action->condition()); + ui->treeWidgetSchedule->addTopLevelItem(item); + } +} + +void ScheduleWindow::updateTimeSample() +{ + if (!isVisible()) + return; + + ui->labelCurrentDateTime->setText(m_Schedule->getSample()); + QTimer::singleShot(25000,this,SLOT(updateTimeSample())); +} + +void ScheduleWindow::add() +{ + m_Schedule->addItem((cScheduleItem::eScheduleAction)ui->comboBoxAction->currentIndex(),QString().setNum(ui->comboBoxProfiles->currentIndex()),ui->lineEditCondition->text()); + rebuild(); +} + +void ScheduleWindow::remove() +{ + if (ui->treeWidgetSchedule->selectedItems().size()==0) + return; + m_Schedule->deleteItem(ui->treeWidgetSchedule->selectedItems()[0]->data(0,Qt::UserRole).toInt()); + rebuild(); +} + +void ScheduleWindow::showEvent(QShowEvent *event) +{ + QMainWindow::showEvent( event ); + rebuild(); + updateTimeSample(); +} diff --git a/TrackYourTime/ui/schedulewindow.h b/TrackYourTime/ui/schedulewindow.h new file mode 100644 index 0000000..5e99bd6 --- /dev/null +++ b/TrackYourTime/ui/schedulewindow.h @@ -0,0 +1,35 @@ +#ifndef SCHEDULEWINDOW_H +#define SCHEDULEWINDOW_H + +#include +#include +#include "../data/cdatamanager.h" +#include "../data/cschedule.h" + + +namespace Ui { +class ScheduleWindow; +} + +class ScheduleWindow : public QMainWindow +{ + Q_OBJECT +protected: + cDataManager* m_DataManager; + cSchedule* m_Schedule; +public: + explicit ScheduleWindow(cDataManager* dataManager, cSchedule* schedule); + ~ScheduleWindow(); + +public slots: + void rebuild(); + void updateTimeSample(); + void add(); + void remove(); +protected: + virtual void showEvent(QShowEvent * event) override; +private: + Ui::ScheduleWindow *ui; +}; + +#endif // SCHEDULEWINDOW_H diff --git a/TrackYourTime/ui/schedulewindow.ui b/TrackYourTime/ui/schedulewindow.ui new file mode 100644 index 0000000..3836f64 --- /dev/null +++ b/TrackYourTime/ui/schedulewindow.ui @@ -0,0 +1,191 @@ + + + ScheduleWindow + + + + 0 + 0 + 800 + 566 + + + + Schedule + + + + + + + + + Schedule + + + + + + + 3 + + + false + + + 200 + + + true + + + + Action + + + + + Params + + + + + Condition + + + + + + + + + 0 + 200 + + + + New schedule record: + + + + + + + + + + Action + + + + + + + + + + + + + + Profile + + + + + + + + + + + + + + Condition(e.g .*15:37 or .*Mon.*12:40 ) + + + + + + + + 0 + 0 + + + + + + + + + + <html><head/><body><p>Regular Expressions syntax: <a href="https://doc.qt.io/qt-4.8/qregexp.html#introduction"><span style=" text-decoration: underline; color:#0000ff;">https://doc.qt.io/qt-4.8/qregexp.html#introduction</span></a></p></body></html> + + + true + + + + + + + + + Current date and time: + + + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + Add new record + + + + + + + + 0 + 0 + + + + Delete selected record + + + + + + + + + + + + + + + + diff --git a/TrackYourTime/ui/settingswindow.cpp b/TrackYourTime/ui/settingswindow.cpp index b431d0e..9d05888 100644 --- a/TrackYourTime/ui/settingswindow.cpp +++ b/TrackYourTime/ui/settingswindow.cpp @@ -18,24 +18,44 @@ #include "settingswindow.h" #include "ui_settingswindow.h" -#include +#include "../tools/tools.h" #include #include "../tools/cfilebin.h" void SettingsWindow::loadPreferences() { - QSettings settings; - - int UpdateDelay = settings.value(cDataManager::CONF_UPDATE_DELAY_ID,cDataManager::DEFAULT_SECONDS_UPDATE_DELAY).toInt(); - int IdleDelay = settings.value(cDataManager::CONF_IDLE_DELAY_ID,cDataManager::DEFAULT_SECONDS_IDLE_DELAY).toInt(); - int AutoSaveDelay = settings.value(cDataManager::CONF_AUTOSAVE_DELAY_ID,cDataManager::DEFAULT_SECONDS_AUTOSAVE_DELAY).toInt(); - bool ShowBaloons = settings.value(cDataManager::CONF_SHOW_BALOONS_ID,true).toBool(); - bool Autorun = settings.value(cDataManager::CONF_AUTORUN_ID,true).toBool(); - QString StorageFileName = settings.value(cDataManager::CONF_STORAGE_FILENAME_ID,m_DataManager->getStorageFileName()).toString(); + cSettings settings; + + int IdleDelay = settings.db()->value(cDataManager::CONF_IDLE_DELAY_ID,cDataManager::DEFAULT_SECONDS_IDLE_DELAY).toInt(); + int AutoSaveDelay = settings.db()->value(cDataManager::CONF_AUTOSAVE_DELAY_ID,cDataManager::DEFAULT_SECONDS_AUTOSAVE_DELAY).toInt(); + cDataManager::eNotificationType NotificationType = (cDataManager::eNotificationType)settings.db()->value(cDataManager::CONF_NOTIFICATION_TYPE_ID,1).toInt(); + bool Autorun = settings.db()->value(cDataManager::CONF_AUTORUN_ID,true).toBool(); + QString StorageFileName = settings.db()->value(cDataManager::CONF_STORAGE_FILENAME_ID,m_DataManager->getStorageFileName()).toString(); QString Language = QLocale::system().name(); Language.truncate(Language.lastIndexOf('_')); - Language = settings.value(cDataManager::CONF_LANGUAGE_ID,Language).toString(); - + Language = settings.db()->value(cDataManager::CONF_LANGUAGE_ID,Language).toString(); + bool ClientMode = settings.db()->value(cDataManager::CONF_CLIENT_MODE_ID,false).toBool(); + QString ClientModeHost = settings.db()->value(cDataManager::CONF_CLIENT_MODE_HOST_ID,"").toString(); + QString NotificationMessage = settings.db()->value(cDataManager::CONF_NOTIFICATION_MESSAGE_ID,getDefaultMessage()).toString(); + m_NotifPos = settings.db()->value(cDataManager::CONF_NOTIFICATION_POSITION_ID,QPoint(10,10)).toPoint(); + m_NotifSize = settings.db()->value(cDataManager::CONF_NOTIFICATION_SIZE_ID,QPoint(250,100)).toPoint(); + int NotificationDelay = settings.db()->value(cDataManager::CONF_NOTIFICATION_HIDE_SECONDS_ID,4).toInt(); + int NotificationMoves = settings.db()->value(cDataManager::CONF_NOTIFICATION_HIDE_MOVES_ID,3).toInt(); + int NotificationOpacity = settings.db()->value(cDataManager::CONF_NOTIFICATION_OPACITY_ID,100).toInt(); + + ui->checkBoxClientMode->setChecked(ClientMode); + ui->lineEditClientModeHost->setText(ClientModeHost); + + ui->lineEditNotif_Message->setText(NotificationMessage); + ui->spinBoxNotif_Delay->setValue(NotificationDelay); + if (NotificationMoves==0) + ui->radioButtonNotif_NerverHideOnMouse->setChecked(true); + else + if (NotificationMoves==1) + ui->radioButtonNotif_HideOnMouse1->setChecked(true); + else + ui->radioButtonNotif_HideOnMouse3->setChecked(true); + ui->spinBoxNotif_Opacity->setValue(NotificationOpacity); ui->comboBoxLanguage->setCurrentIndex(-1); for (int i = 0; icomboBoxLanguage->count(); i++) @@ -43,41 +63,85 @@ void SettingsWindow::loadPreferences() ui->comboBoxLanguage->setCurrentIndex(i); break; } - ui->spinBoxUpdateDelay->setValue(UpdateDelay); ui->spinBoxIdleDelay->setValue(IdleDelay); ui->spinBoxAutosaveDelay->setValue(AutoSaveDelay); ui->lineEditStorageFileName->setText(StorageFileName); - ui->checkBoxShowBaloon->setChecked(ShowBaloons); ui->checkBoxAutorun->setChecked(Autorun); + switch(NotificationType){ + case cDataManager::NT_NONE:{ + ui->radioButtonNotif_Off->setChecked(true); + } + break; + case cDataManager::NT_SYSTEM:{ + ui->radioButtonNotif_System->setChecked(true); + } + break; + case cDataManager::NT_BUILTIN:{ + ui->radioButtonNotif_Custom->setChecked(true); + } + break; + } + } void SettingsWindow::applyPreferences() { - QSettings settings; - - settings.setValue(cDataManager::CONF_UPDATE_DELAY_ID,ui->spinBoxUpdateDelay->value()); - settings.setValue(cDataManager::CONF_IDLE_DELAY_ID,ui->spinBoxIdleDelay->value()); - settings.setValue(cDataManager::CONF_AUTOSAVE_DELAY_ID,ui->spinBoxAutosaveDelay->value()); - settings.setValue(cDataManager::CONF_STORAGE_FILENAME_ID,ui->lineEditStorageFileName->text()); + cSettings settings; + + settings.db()->setValue(cDataManager::CONF_IDLE_DELAY_ID,ui->spinBoxIdleDelay->value()); + settings.db()->setValue(cDataManager::CONF_AUTOSAVE_DELAY_ID,ui->spinBoxAutosaveDelay->value()); + settings.db()->setValue(cDataManager::CONF_STORAGE_FILENAME_ID,ui->lineEditStorageFileName->text().trimmed()); + settings.db()->setValue(cDataManager::CONF_CLIENT_MODE_ID,ui->checkBoxClientMode->isChecked()); + settings.db()->setValue(cDataManager::CONF_CLIENT_MODE_HOST_ID,ui->lineEditClientModeHost->text()); + settings.db()->setValue(cDataManager::CONF_NOTIFICATION_MESSAGE_ID,ui->lineEditNotif_Message->text()); + settings.db()->setValue(cDataManager::CONF_NOTIFICATION_POSITION_ID,m_NotifPos); + settings.db()->setValue(cDataManager::CONF_NOTIFICATION_SIZE_ID,m_NotifSize); + settings.db()->setValue(cDataManager::CONF_NOTIFICATION_HIDE_SECONDS_ID,ui->spinBoxNotif_Delay->value()); + + settings.db()->setValue(cDataManager::CONF_NOTIFICATION_OPACITY_ID,ui->spinBoxNotif_Opacity->value()); + + int movesToHide = 3; + if (ui->radioButtonNotif_NerverHideOnMouse->isChecked()) + movesToHide = 0; + else + if (ui->radioButtonNotif_HideOnMouse1->isChecked()) + movesToHide = 1; + else + if (ui->radioButtonNotif_HideOnMouse3->isChecked()) + movesToHide = 3; + settings.db()->setValue(cDataManager::CONF_NOTIFICATION_HIDE_MOVES_ID,movesToHide); if (ui->comboBoxLanguage->currentIndex()>-1) - settings.setValue(cDataManager::CONF_LANGUAGE_ID,ui->comboBoxLanguage->itemData(ui->comboBoxLanguage->currentIndex()).toString()); - settings.setValue(cDataManager::CONF_SHOW_BALOONS_ID,ui->checkBoxShowBaloon->isChecked()); + settings.db()->setValue(cDataManager::CONF_LANGUAGE_ID,ui->comboBoxLanguage->itemData(ui->comboBoxLanguage->currentIndex()).toString()); + + cDataManager::eNotificationType notificationType = cDataManager::NT_SYSTEM; + if (ui->radioButtonNotif_Off->isChecked()) + notificationType = cDataManager::NT_NONE; + if (ui->radioButtonNotif_System->isChecked()) + notificationType = cDataManager::NT_SYSTEM; + if (ui->radioButtonNotif_Custom->isChecked()) + notificationType = cDataManager::NT_BUILTIN; + settings.db()->setValue(cDataManager::CONF_NOTIFICATION_TYPE_ID,notificationType); if (ui->checkBoxAutorun->isChecked()){ setAutorun(); - settings.setValue(cDataManager::CONF_AUTORUN_ID,true); + settings.db()->setValue(cDataManager::CONF_AUTORUN_ID,true); } else{ removeAutorun(); - settings.setValue(cDataManager::CONF_AUTORUN_ID,false); + settings.db()->setValue(cDataManager::CONF_AUTORUN_ID,false); } - settings.sync(); + settings.db()->sync(); emit preferencesChange(); } +QString SettingsWindow::getDefaultMessage() +{ + return tr("
Current profile: %PROFILE%
Application: %APP_NAME%
State: %APP_STATE%
Category: %APP_CATEGORY%
"); +} + SettingsWindow::SettingsWindow(cDataManager *DataManager) : QMainWindow(0), ui(new Ui::SettingsWindow) { @@ -87,6 +151,9 @@ SettingsWindow::SettingsWindow(cDataManager *DataManager) : QMainWindow(0), connect(ui->pushButtonApply, SIGNAL (released()),this, SLOT (handleButtonApply())); connect(ui->pushButtonCancel, SIGNAL (released()),this, SLOT (handleButtonCancel())); connect(ui->pushButtonBrowseStorageFileName, SIGNAL (released()),this, SLOT (handleButtonBrowse())); + connect(ui->pushButtonSetNotificationWindow, SIGNAL (released()),this, SLOT (handleButtonSetNotificationWindow())); + connect(ui->pushButtonResetNotificationWindow, SIGNAL (released()),this, SLOT (handleButtonResetNotificationWindow())); + connect(ui->pushButtonSetDefaultMessage,SIGNAL(released()),this, SLOT(handleButtonSetDefaultMessage())); QString languagesPath = QDir::currentPath()+"/data/languages"; QStringList languagesList = QDir(languagesPath).entryList(QStringList() << "*.qm"); @@ -104,10 +171,13 @@ SettingsWindow::SettingsWindow(cDataManager *DataManager) : QMainWindow(0), } m_DataManager = DataManager; + m_NotificationSetupWindow = new notification_dummy(this); + connect(m_NotificationSetupWindow,SIGNAL(onApplyPosAndSize()),this,SLOT(onNotificationSetPosAndSize())); } SettingsWindow::~SettingsWindow() { + delete m_NotificationSetupWindow; delete ui; } @@ -139,3 +209,28 @@ void SettingsWindow::handleButtonBrowse() if (!NewStorageFileName.isEmpty()) ui->lineEditStorageFileName->setText(NewStorageFileName); } + +void SettingsWindow::handleButtonSetNotificationWindow() +{ + m_NotificationSetupWindow->showWithMessage(ui->lineEditNotif_Message->text(), ui->radioButtonNotif_HideOnMouse1->isChecked()); + m_NotificationSetupWindow->setGeometry(m_NotifPos.x(),m_NotifPos.y(),m_NotifSize.x(),m_NotifSize.y()); + m_NotificationSetupWindow->setWindowOpacity(ui->spinBoxNotif_Opacity->value()/100.f); +} + +void SettingsWindow::handleButtonResetNotificationWindow() +{ + m_NotifPos = QPoint(0,0); + m_NotifSize = QPoint(250,100); + m_NotificationSetupWindow->setGeometry(m_NotifPos.x(),m_NotifPos.y(),m_NotifSize.x(),m_NotifSize.y()); +} + +void SettingsWindow::handleButtonSetDefaultMessage() +{ + ui->lineEditNotif_Message->setText(getDefaultMessage()); +} + +void SettingsWindow::onNotificationSetPosAndSize() +{ + m_NotifPos = QPoint(m_NotificationSetupWindow->geometry().left(),m_NotificationSetupWindow->geometry().top()); + m_NotifSize = QPoint(m_NotificationSetupWindow->geometry().width(),m_NotificationSetupWindow->geometry().height()); +} diff --git a/TrackYourTime/ui/settingswindow.h b/TrackYourTime/ui/settingswindow.h index 9484402..9d51caa 100644 --- a/TrackYourTime/ui/settingswindow.h +++ b/TrackYourTime/ui/settingswindow.h @@ -21,6 +21,7 @@ #include #include "../data/cdatamanager.h" +#include "notification_dummy.h" namespace Ui { class SettingsWindow; @@ -31,8 +32,12 @@ class SettingsWindow : public QMainWindow Q_OBJECT protected: cDataManager* m_DataManager; + QPoint m_NotifPos; + QPoint m_NotifSize; + notification_dummy* m_NotificationSetupWindow; void loadPreferences(); void applyPreferences(); + QString getDefaultMessage(); public: explicit SettingsWindow(cDataManager* DataManager); ~SettingsWindow(); @@ -48,6 +53,11 @@ public slots: void handleButtonCancel(); void handleButtonBrowse(); + void handleButtonSetNotificationWindow(); + void handleButtonResetNotificationWindow(); + void handleButtonSetDefaultMessage(); + + void onNotificationSetPosAndSize(); }; #endif // SETTINGSWINDOW_H diff --git a/TrackYourTime/ui/settingswindow.ui b/TrackYourTime/ui/settingswindow.ui index 0961c5f..2263dd5 100644 --- a/TrackYourTime/ui/settingswindow.ui +++ b/TrackYourTime/ui/settingswindow.ui @@ -6,8 +6,8 @@ 0 0 - 614 - 359 + 980 + 592
@@ -33,108 +33,147 @@ + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + - - - Language(need restart): - - - false - - - - - - - - - - How often check system state(seconds): - - - false - - - - - - - 1 - - - 60 - - - - - - - Duration of inactivity before falling asleep(seconds): - - - false - - - - - - - 60 - - - 3600 - - - 300 - - - - - - - Autosave: how often save db(seconds): - - - false - - + + + + + Language(need restart): + + + false + + + + + + + + 0 + 0 + + + + + - - - 300 - - - 3600 - - - 1500 - - + + + + + Duration of inactivity before falling asleep(seconds): + + + false + + + + + + + + 0 + 0 + + + + 60 + + + 3600 + + + 300 + + + + - - - - 0 - 0 - - - - Storage File Name: - - - false - - + + + + + Autosave: how often save db(seconds): + + + false + + + + + + + + 0 + 0 + + + + 300 + + + 3600 + + + 1500 + + + + - + + + + 0 + 0 + + + + Storage File Name: + + + false + + + + + + + + 0 + 0 + + + + + + 0 + 0 + + Browse... @@ -143,20 +182,246 @@ - + + + + + Send data to another host: + + + + + + + + + + - + 0 0 - - Show baloon when category changed + + Notifications + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + No notifications + + + + + + + System notification system + + + + + + + Built-in notification system: + + + + + + + 0 + + + 40 + + + 0 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Set window position and size + + + + + + + Reset window position + + + + + + + + + + + Hide after(seconds): + + + + + + + 1 + + + 60 + + + 4 + + + + + + + + + + + Opacity(percents) + + + + + + + 1 + + + 100 + + + 100 + + + + + + + + + Mouse interactions + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Hide notification on mouse move and never show category selection menu + + + + + + + Never hide notification on mouse move(hide only by timer) and show category selection menu if category not selected + + + + + + + Hide notification on some mouse moves and show category selection meny if category not selected(recomended) + + + + + + + + + + Message format: + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Set default message + + + + + + + + + + true + 0 @@ -185,6 +450,12 @@ + + + 0 + 0 + + Apply @@ -192,6 +463,12 @@ + + + 0 + 0 + + Cancel diff --git a/TrackYourTime/ui/statisticwindow.cpp b/TrackYourTime/ui/statisticwindow.cpp index ae5fbb8..d2c4e46 100644 --- a/TrackYourTime/ui/statisticwindow.cpp +++ b/TrackYourTime/ui/statisticwindow.cpp @@ -20,6 +20,7 @@ #include "ui_statisticwindow.h" #include #include +#include QString DurationToString(quint32 durationSeconds) { @@ -227,7 +228,8 @@ StatisticWindow::StatisticWindow(cDataManager *DataManager) : ui->widgetDiagram->setCategories(&m_Categories,&m_Uncategorized); - connect(ui->pushButtonSetToday, SIGNAL(released()), this, SLOT(onSetTodayPress())); + connect(ui->pushButtonSetPeriod, SIGNAL(released()), this, SLOT(onSetPeriodPress())); + connect(ui->comboBoxPeriod,SIGNAL(currentIndexChanged(int)),this, SLOT(onSetPeriodPress())); connect(ui->pushButtonUpdate, SIGNAL(released()), this, SLOT(onUpdatePress())); connect(ui->pushButtonExportApplicationsCSV, SIGNAL(released()), this, SLOT(onExportApplicationsCSVPress())); connect(ui->pushButtonExportCategoriesCSV, SIGNAL(released()), this, SLOT(onExportCategoriesCSVPress())); @@ -241,10 +243,38 @@ StatisticWindow::~StatisticWindow() delete ui; } -void StatisticWindow::onSetTodayPress() +enum ePeriod{ + P_TODAY = 0, + P_WEEK, + P_MONTH, + P_YEAR +}; + +void StatisticWindow::onSetPeriodPress() { - ui->dateEditFrom->setDate(QDate::currentDate()); + switch(ui->comboBoxPeriod->currentIndex()){ + case P_TODAY:{ + ui->dateEditFrom->setDate(QDate::currentDate()); + } + break; + case P_WEEK:{ + QDate date = QDate::currentDate(); + ui->dateEditFrom->setDate(date.addDays(-date.dayOfWeek()+1)); + } + break; + case P_MONTH:{ + QDate date = QDate::currentDate(); + ui->dateEditFrom->setDate(date.addDays(-date.day()+1)); + } + break; + case P_YEAR:{ + QDate date = QDate::currentDate(); + ui->dateEditFrom->setDate(date.addDays(-date.dayOfYear()+1)); + } + break; + } ui->dateEditTo->setDate(QDate::currentDate()); + onUpdatePress(); } @@ -263,6 +293,7 @@ void StatisticWindow::onUpdatePress() void cStatisticDiagramWidget::paintEvent(QPaintEvent *event) { + Q_UNUSED(event) QPainter painter( this ); painter.setPen( QPen( Qt::black, 1 ) ); @@ -287,7 +318,7 @@ void cStatisticDiagramWidget::paintEvent(QPaintEvent *event) QRectF r(0,shift,width()-1,catHeight); painter.drawRect(r); if (catHeight>20){ - painter.drawText(r,Qt::AlignCenter | Qt::TextSingleLine,item.Name+"["+DurationToString(item.TotalTime)+"]"); + painter.drawText(r,Qt::AlignCenter | Qt::TextSingleLine,item.Name+"["+DurationToString(item.TotalTime)+"]["+QString::number(item.NormalValue*100,'f',2)+"%]"); } shift+=catHeight; } @@ -300,7 +331,7 @@ void cStatisticDiagramWidget::paintEvent(QPaintEvent *event) QRectF r(0,shift,width()-1,catHeight); painter.drawRect(r); if (catHeight>20){ - painter.drawText(r,Qt::AlignCenter | Qt::TextSingleLine,m_Uncategorized->Name+"["+DurationToString(m_Uncategorized->TotalTime)+"]"); + painter.drawText(r,Qt::AlignCenter | Qt::TextSingleLine,m_Uncategorized->Name+"["+DurationToString(m_Uncategorized->TotalTime)+"]["+QString::number(m_Uncategorized->NormalValue*100,'f',2)+"%]"); } shift+=catHeight; } diff --git a/TrackYourTime/ui/statisticwindow.h b/TrackYourTime/ui/statisticwindow.h index c042646..8fb4bcb 100644 --- a/TrackYourTime/ui/statisticwindow.h +++ b/TrackYourTime/ui/statisticwindow.h @@ -71,7 +71,7 @@ class StatisticWindow : public QMainWindow private: Ui::StatisticWindow *ui; public slots: - void onSetTodayPress(); + void onSetPeriodPress(); void onUpdatePress(); void onExportCategoriesCSVPress(); void onExportApplicationsCSVPress(); diff --git a/TrackYourTime/ui/statisticwindow.ui b/TrackYourTime/ui/statisticwindow.ui index 1a94ad2..88ac933 100644 --- a/TrackYourTime/ui/statisticwindow.ui +++ b/TrackYourTime/ui/statisticwindow.ui @@ -6,8 +6,8 @@ 0 0 - 735 - 551 + 776 + 550 @@ -20,9 +20,48 @@ - + + + + 0 + 0 + + + + 0 + + + + Today + + + + + This week + + + + + This month + + + + + This year + + + + + + + + + 0 + 0 + + - Set today>> + >> @@ -34,7 +73,14 @@ - + + + + 0 + 0 + + + @@ -44,10 +90,23 @@ - + + + + 0 + 0 + + + + + + 0 + 0 + + Update @@ -79,6 +138,12 @@ + + + 0 + 0 + + Export categories to CSV... @@ -86,6 +151,12 @@ + + + 0 + 0 + + Export applications to CSV... diff --git a/change.log b/change.log index 49ab48b..a804e17 100644 --- a/change.log +++ b/change.log @@ -1,4 +1,13 @@ 0.9.2 -change external trackers format from binary to text -add http server for external trackers on port 25856 --add detailed information about app activity in applications window and statistic window \ No newline at end of file +-add detailed information about app activity in applications window and statistic window +-add portable config support +-fix all warnings in source code +-add schedule +-Improve HDPI display support +-Add periods in statistic window +-Add percents on categories statistic +-Show Applications on tray icon click +-Add built-in notification window +-Add modern windows apps support \ No newline at end of file diff --git a/checksystem/.gitignore b/checksystem/.gitignore index d887912..86e8755 100644 --- a/checksystem/.gitignore +++ b/checksystem/.gitignore @@ -1 +1,3 @@ /build-checksystem-Desktop_Qt_5_5_Bundled_GCC_64bit-Release/ +/build-checksystem-Desktop_Qt_5_5_1_GCC_64bit-Debug/ +/build-checksystem-Desktop_Qt_5_5_1_GCC_64bit-Release/ diff --git a/checksystem/checksystem/.gitignore b/checksystem/checksystem/.gitignore new file mode 100644 index 0000000..75c107b --- /dev/null +++ b/checksystem/checksystem/.gitignore @@ -0,0 +1 @@ +*.pro.user diff --git a/checksystem/checksystem/checksystem.pro b/checksystem/checksystem/checksystem.pro index b48bd05..d29c382 100644 --- a/checksystem/checksystem/checksystem.pro +++ b/checksystem/checksystem/checksystem.pro @@ -4,9 +4,8 @@ # #------------------------------------------------- -QT += core - -QT -= gui +QT += core gui network script +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = checksystem CONFIG += console diff --git a/checksystem/checksystem/checksystem.pro.user b/checksystem/checksystem/checksystem.pro.user deleted file mode 100644 index 2edb813..0000000 --- a/checksystem/checksystem/checksystem.pro.user +++ /dev/null @@ -1,271 +0,0 @@ - - - - - - EnvironmentId - {5d65475a-00f5-405a-9705-65d648510aa3} - - - ProjectExplorer.Project.ActiveTarget - 0 - - - ProjectExplorer.Project.EditorSettings - - true - false - true - - Cpp - - CppGlobal - - - - QmlJS - - QmlJSGlobal - - - 2 - UTF-8 - false - 4 - false - 80 - true - true - 1 - true - false - 0 - true - 0 - 8 - true - 1 - true - true - true - false - - - - ProjectExplorer.Project.PluginSettings - - - - ProjectExplorer.Project.Target.0 - - Desktop Qt 5.5 Bundled GCC 64bit - Desktop Qt 5.5 Bundled GCC 64bit - {5411acdd-e4b3-4761-9122-8cf6c57a9e0b} - 1 - 0 - 0 - - /home/Allex/Projects/TrackYourTime/checksystem/build-checksystem-Desktop_Qt_5_5_Bundled_GCC_64bit-Debug - - - true - qmake - - QtProjectManager.QMakeBuildStep - false - true - - false - false - false - - - true - Make - - Qt4ProjectManager.MakeStep - - -w - -r - - false - - - - 2 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - Make - - Qt4ProjectManager.MakeStep - - -w - -r - - true - clean - - - 1 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Debug - - Qt4ProjectManager.Qt4BuildConfiguration - 2 - true - - - /home/Allex/Projects/TrackYourTime/checksystem/build-checksystem-Desktop_Qt_5_5_Bundled_GCC_64bit-Release - - - true - qmake - - QtProjectManager.QMakeBuildStep - false - true - - false - false - false - - - true - Make - - Qt4ProjectManager.MakeStep - - -w - -r - - false - - - - 2 - Build - - ProjectExplorer.BuildSteps.Build - - - - true - Make - - Qt4ProjectManager.MakeStep - - -w - -r - - true - clean - - - 1 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Release - - Qt4ProjectManager.Qt4BuildConfiguration - 0 - true - - 2 - - - 0 - Deploy - - ProjectExplorer.BuildSteps.Deploy - - 1 - Deploy locally - - ProjectExplorer.DefaultDeployConfiguration - - 1 - - - - false - false - false - false - true - 0.01 - 10 - true - 1 - 25 - - 1 - true - false - true - valgrind - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - - 2 - - checksystem - - Qt4ProjectManager.Qt4RunConfiguration:/home/Allex/Projects/TrackYourTime/checksystem/checksystem/checksystem.pro - - checksystem.pro - false - true - - 3768 - false - true - false - false - true - - 1 - - - - ProjectExplorer.Project.TargetCount - 1 - - - ProjectExplorer.Project.Updater.FileVersion - 18 - - - Version - 18 - - diff --git a/checksystem/checksystem/main.cpp b/checksystem/checksystem/main.cpp index 506659c..4d99948 100644 --- a/checksystem/checksystem/main.cpp +++ b/checksystem/checksystem/main.cpp @@ -19,11 +19,14 @@ #include #include #include +#include #include #include #include #include #include +#include + enum eActiveWindowState{ @@ -42,8 +45,6 @@ eActiveWindowState checkActiveWindow(){ Atom active = XInternAtom(display, "_NET_ACTIVE_WINDOW", False); XTextProperty text; - char **name = NULL; - int param; Atom type_ret; int format_ret; @@ -75,20 +76,50 @@ enum eInputState{ UDEV_NOACCESS }; + eInputState checkUdev(){ QDir dir("/dev/input/by-id"); if (!dir.exists()) return UDEV_NOTFOUND; - QStringList keyboards = dir.entryList(QStringList() << "*keyboard*"); - if (keyboards.size()==0) + QVector keyboards_fd; + + QString path; + QStringList keyboards; + + path = "/dev/input/by-id"; + keyboards = QDir(path).entryList(QStringList() << "*keyboard*"); + for (int i = 0; i-1){ + close(keyboards_fd[i]); + haveActiveKeyboard = true; + } + + if (!haveActiveKeyboard) + return UDEV_NOACCESS; + return UDEV_OK; } diff --git a/data/app_predef/Google Chrome.predef b/data/app_predef/Google Chrome.predef new file mode 100644 index 0000000..d1a722c --- /dev/null +++ b/data/app_predef/Google Chrome.predef @@ -0,0 +1,2 @@ +TYPE==EXTERNAL_TRACKER +INFO==more info:https://github.com/Allexin/TrackYourTime/wiki/Install-chrome-tracker \ No newline at end of file diff --git a/data/app_predef/Skype.exe.predef b/data/app_predef/Skype.exe.predef deleted file mode 100644 index a21d6dc..0000000 --- a/data/app_predef/Skype.exe.predef +++ /dev/null @@ -1,2 +0,0 @@ -TYPE==PREDEFINED_SCRIPT -INFO==Skype predefined script parse title of skype window and try co get conversation name \ No newline at end of file diff --git a/data/app_predef/chrome_extension/background.js b/data/app_predef/chrome_extension/background.js index 83d87fc..7d82ad1 100644 --- a/data/app_predef/chrome_extension/background.js +++ b/data/app_predef/chrome_extension/background.js @@ -29,13 +29,23 @@ function extractDomain(url) { return domain; } +var delimeter = ":"; function sendState(url){ - var TRACKER_INFO='PREFIX=TYTET;VERSION=1;APP_1=chrome.exe;APP_2=chromium.exe;APP_3=Google-chrome-stable;APP_4=google-chrome;APP_5=chromium-browser;STATE='+extractDomain(url); + var TRACKER_INFO='PREFIX=TYTET&VERSION=1&APP_1=chrome.exe&APP_2=chromium.exe&APP_3=Google-chrome-stable&APP_4=google-chrome&APP_5=chromium-browser&APP_6=Google%20Chrome&STATE='+extractDomain(url); var xhr = new XMLHttpRequest(); - xhr.open("GET", "http://127.0.0.1:25856?data=["+TRACKER_INFO+"]", true); - xhr.send(); - + xhr.open("GET", "http://127.0.0.1:25856?"+TRACKER_INFO, true); + xhr.send(); + var currentTime = new Date(); + var h = currentTime.getHours(); + var m = currentTime.getMinutes().toString(); + if (m.length==1) m = "0"+m; + var text = h+delimeter+m; + chrome.browserAction.setBadgeText({text:text}); + if (delimeter==":") + delimeter = " "; + else + delimeter = ":"; } function prepareData(){ @@ -44,5 +54,6 @@ function prepareData(){ chrome.alarms.onAlarm.addListener(prepareData); chrome.alarms.create("TRACK_YOUR_TIME_TIMER", { - delayInMinutes: 0.05, periodInMinutes: 0.05} - ); \ No newline at end of file + delayInMinutes: 0.05, periodInMinutes: 0.02} + ); +chrome.browserAction.setBadgeBackgroundColor({color:[0,0,0,255]}); \ No newline at end of file diff --git a/data/app_predef/scripts/Skype.exe.script b/data/app_predef/scripts/Skype.exe.script deleted file mode 100644 index 43ea8b0..0000000 --- a/data/app_predef/scripts/Skype.exe.script +++ /dev/null @@ -1,6 +0,0 @@ -function parseTitle(appName,appTitle,currentOS){ - var pos = appTitle.indexOf("-"); - if (pos>0) - return appTitle.substring(0,pos); - return ""; -} \ No newline at end of file diff --git a/data/app_predef/scripts/skype.script b/data/app_predef/scripts/skype.script index 43ea8b0..d2ebd32 100644 --- a/data/app_predef/scripts/skype.script +++ b/data/app_predef/scripts/skype.script @@ -1,6 +1,9 @@ function parseTitle(appName,appTitle,currentOS){ + var unreadPos=appTitle.indexOf("]"); + if (unreadPos>0) + unreadPos=unreadPos+1; var pos = appTitle.indexOf("-"); if (pos>0) - return appTitle.substring(0,pos); + return appTitle.substring(unreadPos,pos); return ""; } \ No newline at end of file diff --git a/data/languages/lang_en.qm b/data/languages/lang_en.qm index 9dad8df..2bafe37 100644 Binary files a/data/languages/lang_en.qm and b/data/languages/lang_en.qm differ diff --git a/data/languages/lang_ru.qm b/data/languages/lang_ru.qm index 6616441..1030a78 100644 Binary files a/data/languages/lang_ru.qm and b/data/languages/lang_ru.qm differ