Commit e118bfa7 authored by Claude Brisson's avatar Claude Brisson

Initial commit

parents
src/config.h
# programs
CXX = g++
# c++ flags
CXXFLAGS += -std=c++11 -Isrc -I/usr/local/include -I/usr/include
CXXFLAGS += -I/usr/include/glibmm-2.4 -I/usr/lib/x86_64-linux-gnu/glibmm-2.4/include
CXXFLAGS += -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
CXXFLAGS += -I/usr/include/sigc++-2.0 -I/usr/lib/x86_64-linux-gnu/sigc++-2.0/include
CXXFLAGS += -I/usr/include/giomm-2.4 -I/usr/lib/x86_64-linux-gnu/giomm-2.4/include
CXXFLAGS += -I/usr/include/gdkmm-3.0 -I/usr/lib/x86_64-linux-gnu/gdkmm-3.0/include
CXXFLAGS += -I/usr/include/pango-1.0 -I/usr/include/pangomm-1.4 -I/usr/lib/x86_64-linux-gnu/pangomm-1.4/include
CXXFLAGS += -I/usr/include/gtk-3.0 -I/usr/include/gtkmm-3.0 -I/usr/lib/x86_64-linux-gnu/gtkmm-3.0/include
CXXFLAGS += -I/usr/include/cairo
CXXFLAGS += -I/usr/include/gdk-pixbuf-2.0
CXXFLAGS += -I/usr/include/cairomm-1.0
CXXFLAGS += -I/usr/include/freetype2
CXXFLAGS += -I/usr/include/atk-1.0 -I/usr/include/atkmm-1.6
CXXFLAGS += -I/usr/include/mysql
# link flags
LDFLAGS += -L/usr/local/lib -L/usr/lib -L/usr/lib/x86_64-linux-gnu -lgtkmm-3.0 -latkmm-1.6 -lglibmm-2.4 -lsigc-2.0 -lmysqlpp -ldl
all: timeslice
.PHONY: all clean
timeslice: obj/timeslice.o obj/main.o
$(CXX) $^ -o $@ $(LDFLAGS)
obj/timeslice.o: src/timeslice.cpp src/timeslice.h
mkdir -p obj
$(CXX) $(CXXFLAGS) -o $@ -c $<
obj/main.o: src/main.cpp src/timeslice.h
mkdir -p obj
$(CXX) $(CXXFLAGS) -o $@ -c $<
clean:
rm -rf obj timeslice
#pragma once
#define TS_DB "billing"
#define TS_HOST "localhost"
#define TS_USER "timeslice"
#define TS_PASSWORD "XXXXXXX"
#include "timeslice.h"
#include <iostream>
#include <gtkmm-3.0/gtkmm.h>
int main (int argc, char *argv[])
{
try
{
auto app = Gtk::Application::create(argc, argv, "com.republicate");
TimeSlice timeslice;
timeslice.init();
//Shows the window and returns when it is closed.
return app->run(timeslice);
}
catch (std::exception &ex)
{
std::cerr << "exception:" << ex.what() << std::endl;
return 1;
}
}
#include "timeslice.h"
#include <exception>
#include <iostream>
#include <mysql++/mysql++.h>
static TimeSlice *app = nullptr;
Project::Project(int id, std::string name) : id(id), name(name)
{
button = std::make_shared<Gtk::RadioButton>(app->getGroup(), name);
label = std::make_shared<Gtk::Label>("00:00:00");
button->show();
label->show();
}
void Project::on_button_clicked()
{
app->setActive(this);
app->resetStart();
}
TimeSlice::TimeSlice()
{
app = this;
}
TimeSlice::~TimeSlice()
{
timer.disconnect();
}
void TimeSlice::readProjects()
{
mysqlpp::Connection conn;
mysqlpp::SetCharsetNameOption *scno = new mysqlpp::SetCharsetNameOption("utf8");
conn.set_option(scno);
conn.connect(TS_DB, TS_HOST, TS_TIMESLICE, TS_PASSWORD);
mysqlpp::Query query = conn.query();
query << "SELECT pr_id, name FROM project ORDER BY name";
mysqlpp::StoreQueryResult res = query.store();
if (res && res.num_rows())
{
mysqlpp::StoreQueryResult::iterator rit;
for (rit = res.begin(); rit != res.end(); ++rit)
{
int id = int((*rit)[0]);
std::string name;
(*rit)[1].to_string(name);
std::shared_ptr<Project> project = std::make_shared<Project>(id, name);
projects.emplace_back(project);
}
}
else
{
throw std::runtime_error("no project found");
}
}
void TimeSlice::startTimer()
{
sigc::slot<bool> slot = sigc::mem_fun(*this, &TimeSlice::on_timer);
timer = Glib::signal_timeout().connect(slot, TIMEOUT);
}
void TimeSlice::init()
{
// window
set_border_width(10);
// grid
grid = std::make_shared<Gtk::Grid>();
//grid->property_orientation() = Gtk::Orientation::ORIENTATION_VERTICAL;
add(*grid);
// buttons
group = std::make_shared<Gtk::RadioButtonGroup>();
idle = std::make_shared<Gtk::RadioButton>(*group, "idle");
idle->show();
idle->signal_clicked().connect(sigc::mem_fun(*this, &TimeSlice::on_idle_clicked));
grid->attach(*idle, 0, 0, 2, 1);
int row = 1;
readProjects();
for (auto &project : projects)
{
std::shared_ptr<Gtk::RadioButton> button = project->button;
button->signal_clicked().connect(sigc::mem_fun(*project, &Project::on_button_clicked));
grid->attach(*project->button, 0, row, 1, 1);
grid->attach(*project->label, 1, row, 1, 1);
++row;
}
grid->show();
set_keep_above(true);
startTimer();
}
void TimeSlice::on_idle_clicked()
{
active = nullptr;
}
void TimeSlice::setActive(Project *project)
{
if (active)
{
timestamp now = std::chrono::system_clock::now();
std::cerr << "@@@ old:" << (now - start).count() << std::endl;
std::cerr << "@@@ new:" << time_diff(now, start) << std::endl;
active->elapsed += time_diff(now, start);
}
active = project;
}
bool TimeSlice::on_timer()
{
if (active)
{
timestamp now = std::chrono::system_clock::now();
long elapsed = active->elapsed + time_diff(now, start);
long hours = elapsed / 3600;
long minutes = (elapsed % 3600) / 60;
long seconds = elapsed % 60;
std::ostringstream oss;
oss << std::setfill('0') << std::setw(2) << hours << ':' << std::setw(2) << minutes << ':' << std::setw(2) << seconds;
std::string hms = oss.str();
active->label->set_text(hms);
active->label->queue_draw();
registerTimeSlice(active->id, start, elapsed);
}
return true;
}
void TimeSlice::registerTimeSlice(int id, timestamp start, long elapsed)
{
mysqlpp::Connection conn;
mysqlpp::SetCharsetNameOption *scno = new mysqlpp::SetCharsetNameOption("utf8");
conn.set_option(scno);
conn.connect(TS_DB, TS_HOST, TS_TIMESLICE, TS_PASSWORD);
mysqlpp::Query query = conn.query();
std::time_t time = std::chrono::system_clock::to_time_t(start);
std::cerr << "@@@ " << std::put_time(std::localtime(&time), "%F %T") << std::endl;
query << "INSERT INTO timeslice (pr_id, starttime, duration) VALUES (" << id << ", '" << std::put_time(std::localtime(&time), "%F %T") << "', " << elapsed << ") ON DUPLICATE KEY UPDATE duration = VALUES(duration)";
if (!query.exec()) throw std::runtime_error("could not update time slice");
}
#pragma once
#include <gtkmm-3.0/gtkmm.h>
#define TIMEOUT 1000
typedef std::chrono::time_point<std::chrono::system_clock> timestamp;
#define time_diff(a,b) (std::chrono::duration_cast<std::chrono::seconds>((a) - (b)).count())
struct Project
{
Project (int id, std::string name);
int id;
std::string name;
std::shared_ptr<Gtk::RadioButton> button;
std::shared_ptr<Gtk::Label> label;
void on_button_clicked();
long elapsed = 0;
};
class TimeSlice : public Gtk::Window
{
public:
TimeSlice();
void init();
void readProjects();
void startTimer();
Gtk::RadioButtonGroup& getGroup() { return *group; }
virtual ~TimeSlice();
void on_idle_clicked();
bool on_timer();
void setActive(Project *project);
void resetStart() { start = std::chrono::system_clock::now(); }
void registerTimeSlice(int id, timestamp start, long elapsed);
protected:
std::shared_ptr<Gtk::RadioButtonGroup> group;
std::shared_ptr<Gtk::Grid> grid;
std::shared_ptr<Gtk::RadioButton> idle;
std::vector<std::shared_ptr<Project>> projects;
sigc::connection timer;
Project * active = nullptr;
timestamp start;
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment