openall_time_applet 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,185 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <interface>
3
+ <requires lib="gtk+" version="2.24"/>
4
+ <!-- interface-naming-policy project-wide -->
5
+ <object class="GtkWindow" id="window">
6
+ <property name="can_focus">False</property>
7
+ <property name="title" translatable="yes">Timelog</property>
8
+ <property name="window_position">center</property>
9
+ <property name="default_width">640</property>
10
+ <property name="default_height">480</property>
11
+ <child>
12
+ <object class="GtkVBox" id="vbox1">
13
+ <property name="visible">True</property>
14
+ <property name="can_focus">False</property>
15
+ <child>
16
+ <object class="GtkFrame" id="frame1">
17
+ <property name="visible">True</property>
18
+ <property name="can_focus">False</property>
19
+ <property name="label_xalign">0</property>
20
+ <property name="shadow_type">none</property>
21
+ <child>
22
+ <object class="GtkAlignment" id="alignment1">
23
+ <property name="visible">True</property>
24
+ <property name="can_focus">False</property>
25
+ <property name="left_padding">12</property>
26
+ <child>
27
+ <object class="GtkTable" id="table1">
28
+ <property name="visible">True</property>
29
+ <property name="can_focus">False</property>
30
+ <property name="n_rows">3</property>
31
+ <property name="n_columns">2</property>
32
+ <property name="column_spacing">3</property>
33
+ <property name="row_spacing">3</property>
34
+ <child>
35
+ <object class="GtkLabel" id="label3">
36
+ <property name="visible">True</property>
37
+ <property name="can_focus">False</property>
38
+ <property name="xalign">0</property>
39
+ <property name="label" translatable="yes">Description</property>
40
+ </object>
41
+ <packing>
42
+ <property name="x_options">GTK_FILL</property>
43
+ <property name="y_options">GTK_FILL</property>
44
+ </packing>
45
+ </child>
46
+ <child>
47
+ <object class="GtkLabel" id="label4">
48
+ <property name="visible">True</property>
49
+ <property name="can_focus">False</property>
50
+ <property name="xalign">0</property>
51
+ <property name="label" translatable="yes">Time</property>
52
+ </object>
53
+ <packing>
54
+ <property name="top_attach">1</property>
55
+ <property name="bottom_attach">2</property>
56
+ <property name="x_options">GTK_FILL</property>
57
+ <property name="y_options">GTK_FILL</property>
58
+ </packing>
59
+ </child>
60
+ <child>
61
+ <object class="GtkEntry" id="txtDescr">
62
+ <property name="visible">True</property>
63
+ <property name="can_focus">True</property>
64
+ <property name="invisible_char">•</property>
65
+ <property name="primary_icon_activatable">False</property>
66
+ <property name="secondary_icon_activatable">False</property>
67
+ <property name="primary_icon_sensitive">True</property>
68
+ <property name="secondary_icon_sensitive">True</property>
69
+ </object>
70
+ <packing>
71
+ <property name="left_attach">1</property>
72
+ <property name="right_attach">2</property>
73
+ </packing>
74
+ </child>
75
+ <child>
76
+ <object class="GtkEntry" id="txtTime">
77
+ <property name="visible">True</property>
78
+ <property name="can_focus">True</property>
79
+ <property name="invisible_char">•</property>
80
+ <property name="primary_icon_activatable">False</property>
81
+ <property name="secondary_icon_activatable">False</property>
82
+ <property name="primary_icon_sensitive">True</property>
83
+ <property name="secondary_icon_sensitive">True</property>
84
+ </object>
85
+ <packing>
86
+ <property name="left_attach">1</property>
87
+ <property name="right_attach">2</property>
88
+ <property name="top_attach">1</property>
89
+ <property name="bottom_attach">2</property>
90
+ </packing>
91
+ </child>
92
+ <child>
93
+ <object class="GtkLabel" id="label5">
94
+ <property name="visible">True</property>
95
+ <property name="can_focus">False</property>
96
+ <property name="xalign">0</property>
97
+ <property name="label" translatable="yes">Transport</property>
98
+ </object>
99
+ <packing>
100
+ <property name="top_attach">2</property>
101
+ <property name="bottom_attach">3</property>
102
+ <property name="x_options">GTK_FILL</property>
103
+ <property name="y_options">GTK_FILL</property>
104
+ </packing>
105
+ </child>
106
+ <child>
107
+ <object class="GtkEntry" id="txtTimeTransport">
108
+ <property name="visible">True</property>
109
+ <property name="can_focus">True</property>
110
+ <property name="invisible_char">•</property>
111
+ <property name="primary_icon_activatable">False</property>
112
+ <property name="secondary_icon_activatable">False</property>
113
+ <property name="primary_icon_sensitive">True</property>
114
+ <property name="secondary_icon_sensitive">True</property>
115
+ </object>
116
+ <packing>
117
+ <property name="left_attach">1</property>
118
+ <property name="right_attach">2</property>
119
+ <property name="top_attach">2</property>
120
+ <property name="bottom_attach">3</property>
121
+ </packing>
122
+ </child>
123
+ </object>
124
+ </child>
125
+ </object>
126
+ </child>
127
+ <child type="label">
128
+ <object class="GtkLabel" id="label1">
129
+ <property name="visible">True</property>
130
+ <property name="can_focus">False</property>
131
+ <property name="label" translatable="yes">&lt;b&gt;Timelog&lt;/b&gt;</property>
132
+ <property name="use_markup">True</property>
133
+ </object>
134
+ </child>
135
+ </object>
136
+ <packing>
137
+ <property name="expand">False</property>
138
+ <property name="fill">True</property>
139
+ <property name="position">0</property>
140
+ </packing>
141
+ </child>
142
+ <child>
143
+ <object class="GtkHButtonBox" id="hbuttonbox1">
144
+ <property name="visible">True</property>
145
+ <property name="can_focus">False</property>
146
+ <property name="spacing">3</property>
147
+ <property name="layout_style">end</property>
148
+ <child>
149
+ <object class="GtkButton" id="btnSave">
150
+ <property name="label">gtk-save</property>
151
+ <property name="visible">True</property>
152
+ <property name="can_focus">True</property>
153
+ <property name="receives_default">True</property>
154
+ <property name="use_action_appearance">False</property>
155
+ <property name="use_stock">True</property>
156
+ <signal name="clicked" handler="on_btnSave_clicked" swapped="no"/>
157
+ </object>
158
+ <packing>
159
+ <property name="expand">False</property>
160
+ <property name="fill">False</property>
161
+ <property name="position">0</property>
162
+ </packing>
163
+ </child>
164
+ </object>
165
+ <packing>
166
+ <property name="expand">False</property>
167
+ <property name="fill">True</property>
168
+ <property name="position">1</property>
169
+ </packing>
170
+ </child>
171
+ <child>
172
+ <object class="GtkLabel" id="label2">
173
+ <property name="visible">True</property>
174
+ <property name="can_focus">False</property>
175
+ </object>
176
+ <packing>
177
+ <property name="expand">True</property>
178
+ <property name="fill">True</property>
179
+ <property name="position">2</property>
180
+ </packing>
181
+ </child>
182
+ </object>
183
+ </child>
184
+ </object>
185
+ </interface>
data/gui/trayicon.rb ADDED
@@ -0,0 +1,55 @@
1
+ class Openall_time_applet::Gui::Trayicon
2
+ attr_reader :args
3
+
4
+ def initialize(args)
5
+ @args = args
6
+
7
+ @ti = Gtk::StatusIcon.new
8
+ @ti.file = "../gfx/icon_time.png"
9
+ @ti.signal_connect("popup-menu", &self.method(:on_statusicon_rightclick))
10
+
11
+ #Build rightclick-menu for tray-icon.
12
+ timelog_new = Gtk::ImageMenuItem.new(Gtk::Stock::NEW)
13
+ timelog_new.label = _("New timelog")
14
+ timelog_new.signal_connect("activate", &self.method(:on_timelogNew_activate))
15
+
16
+ overview = Gtk::ImageMenuItem.new(Gtk::Stock::EDIT)
17
+ overview.label = _("Overview")
18
+ overview.signal_connect("activate", &self.method(:on_overview_activate))
19
+
20
+ pref = Gtk::ImageMenuItem.new(Gtk::Stock::PREFERENCES)
21
+ pref.signal_connect("activate", &self.method(:on_preferences_activate))
22
+
23
+ quit = Gtk::ImageMenuItem.new(Gtk::Stock::QUIT)
24
+ quit.signal_connect("activate", &self.method(:on_quit_activate))
25
+
26
+ @menu = Gtk::Menu.new
27
+ @menu.append(timelog_new)
28
+ @menu.append(overview)
29
+ @menu.append(Gtk::SeparatorMenuItem.new)
30
+ @menu.append(pref)
31
+ @menu.append(Gtk::SeparatorMenuItem.new)
32
+ @menu.append(quit)
33
+ @menu.show_all
34
+ end
35
+
36
+ def on_statusicon_rightclick(tray, button, time)
37
+ @menu.popup(nil, nil, button, time)
38
+ end
39
+
40
+ def on_preferences_activate(*args)
41
+ @args[:oata].show_preferences
42
+ end
43
+
44
+ def on_timelogNew_activate(*args)
45
+ @args[:oata].show_timelog_new
46
+ end
47
+
48
+ def on_overview_activate(*args)
49
+ @args[:oata].show_overview
50
+ end
51
+
52
+ def on_quit_activate(*args)
53
+ Gtk.main_quit
54
+ end
55
+ end
@@ -0,0 +1,38 @@
1
+ class Openall_time_applet::Gui::Win_overview
2
+ attr_reader :args, :gui
3
+
4
+ def initialize(args)
5
+ @args = args
6
+
7
+ @gui = Gtk::Builder.new.add("../glade/win_overview.glade")
8
+ @gui.translate
9
+ @gui.connect_signals{|h| method(h)}
10
+
11
+ @gui["tvTimelogs"].init([_("ID"), _("Description"), _("Time"), _("Transport"), _("Needs sync")])
12
+ @gui["tvTimelogs"].columns[0].visible = false
13
+ self.reload_timelogs
14
+
15
+ @gui["window"].show_all
16
+ end
17
+
18
+ def reload_timelogs
19
+ @args[:oata].ob.list(:Timelog, {"orderby" => "id"}) do |timelog|
20
+ descr = timelog[:descr].to_s.gsub("\n", " ").gsub(/\s{2,}/, " ")
21
+ descr = Knj::Strings.shorten(descr, 20)
22
+
23
+ sync_need = Knj::Strings.yn_str(timelog[:sync_need], _("Yes"), _("No"))
24
+
25
+ @gui["tvTimelogs"].append([timelog.id, descr, timelog[:time], timelog[:time_transport], sync_need])
26
+ end
27
+ end
28
+
29
+ def on_tvTimelogs_row_activated(*args)
30
+ row = @gui["tvTimelogs"].sel
31
+ return nil if !row
32
+
33
+ timelog = @args[:oata].ob.get(:Timelog, row[0])
34
+ win_timelog_edit = @args[:oata].show_timelog_edit(timelog)
35
+ win_timelog_edit.gui["window"].modal = @gui["window"]
36
+ win_timelog_edit.gui["window"].transient_for = @gui["window"]
37
+ end
38
+ end
@@ -0,0 +1,63 @@
1
+ class Openall_time_applet::Gui::Win_preferences
2
+ attr_reader :args, :gui
3
+
4
+ def initialize(args)
5
+ @args = args
6
+
7
+ @gui = Gtk::Builder.new.add("../glade/win_preferences.glade")
8
+ @gui.translate
9
+ @gui.connect_signals{|h| method(h)}
10
+
11
+ self.load_values
12
+
13
+ @gui["window"].show_all
14
+ end
15
+
16
+ def load_values
17
+ @gui["txtHost"].text = Knj::Opts.get("openall_host")
18
+ @gui["txtPort"].text = Knj::Opts.get("openall_port")
19
+ @gui["txtUsername"].text = Knj::Opts.get("openall_username")
20
+ @gui["txtPassword"].text = Base64.strict_decode64(Knj::Opts.get("openall_password"))
21
+
22
+ if Knj::Opts.get("openall_ssl") == "1"
23
+ @gui["cbSSL"].active = true
24
+ else
25
+ @gui["cbSSL"].active = false
26
+ end
27
+ end
28
+
29
+ def on_btnSave_clicked
30
+ Knj::Opts.set("openall_host", @gui["txtHost"].text)
31
+ Knj::Opts.set("openall_port", @gui["txtPort"].text)
32
+ Knj::Opts.set("openall_ssl", Knj::Strings.yn_str(@gui["cbSSL"].active?, 1, 0))
33
+ Knj::Opts.set("openall_username", @gui["txtUsername"].text)
34
+ Knj::Opts.set("openall_password", Base64.strict_encode64(@gui["txtPassword"].text))
35
+ @gui["window"].destroy
36
+ end
37
+
38
+ def on_btnTest_clicked
39
+ ws = Knj::Gtk2::StatusWindow.new("transient_for" => @gui["window"])
40
+ ws.label = _("Connecting and logging in...")
41
+
42
+ Knj::Thread.new do
43
+ begin
44
+ @args[:oata].oa_conn do |conn|
45
+ ws.percent = 0.3
46
+ ws.label = _("Getting task-list.")
47
+ task_list = conn.task_list
48
+
49
+ ws.label = sprintf(_("Got %s tasks."), task_list.length)
50
+ ws.percent = 1
51
+ end
52
+ rescue => e
53
+ raise e
54
+ Knj::Gtk2.msgbox(e.message, "warning", _("Error"))
55
+ ensure
56
+ Knj::Thread.new do
57
+ sleep 1.5
58
+ ws.destroy
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,29 @@
1
+ class Openall_time_applet::Gui::Win_timelog_edit
2
+ attr_reader :args, :gui
3
+
4
+ def initialize(args)
5
+ @args = args
6
+
7
+ @gui = Gtk::Builder.new.add("../glade/win_timelog_edit.glade")
8
+ @gui.translate
9
+ @gui.connect_signals{|h| method(h)}
10
+
11
+ @gui["window"].show_all
12
+ end
13
+
14
+ def on_btnSave_clicked(*args)
15
+ save_hash = {
16
+ :descr => @gui["txtDescr"].text,
17
+ :time => @gui["txtTime"].text,
18
+ :time_transport => @gui["txtTimeTransport"].text
19
+ }
20
+
21
+ if @timelog
22
+ @timelog.update(save_hash)
23
+ else
24
+ @timelog = @args[:oata].ob.add(:Timelog, save_hash)
25
+ end
26
+
27
+ @gui["window"].destroy
28
+ end
29
+ end
@@ -0,0 +1,130 @@
1
+ require "rubygems"
2
+ require "knjrbfw"
3
+ require "gtk2"
4
+ require "sqlite3"
5
+ require "gettext"
6
+ require "base64"
7
+
8
+ require "knj/gtk2"
9
+ require "knj/gtk2_tv"
10
+ require "knj/gtk2_statuswindow"
11
+
12
+ class Openall_time_applet
13
+ def self.exec
14
+ require "#{File.dirname(__FILE__)}/../bin/openall_time_applet"
15
+ end
16
+
17
+ #Subclass controlling autoloading of models.
18
+ class Models
19
+ def self.const_missing(name)
20
+ require "../models/#{name.to_s.downcase}.rb"
21
+ return Openall_time_applet::Models.const_get(name)
22
+ end
23
+ end
24
+
25
+ class Gui
26
+ #Autoloader for subclasses.
27
+ def self.const_missing(name)
28
+ require "../gui/#{name.to_s.downcase}.rb"
29
+ return Openall_time_applet::Gui.const_get(name)
30
+ end
31
+ end
32
+
33
+ #Autoloader for subclasses.
34
+ def self.const_missing(name)
35
+ namel = name.to_s.downcase
36
+ tries = [
37
+ "../classes/#{namel}.rb"
38
+ ]
39
+ tries.each do |try|
40
+ if File.exists?(try)
41
+ require try
42
+ return Openall_time_applet.const_get(name)
43
+ end
44
+ end
45
+
46
+ raise "Could not load constant: '#{name}'."
47
+ end
48
+
49
+ #Various readable variables.
50
+ attr_reader :db, :ob
51
+
52
+ #Config controlling paths and more.
53
+ CONFIG = {
54
+ :settings_path => "#{Knj::Os.homedir}/.openall_time_applet",
55
+ :db_path => "#{Knj::Os.homedir}/.openall_time_applet/openall_time_applet.sqlite3"
56
+ }
57
+
58
+ #Initializes config-dir and database.
59
+ def initialize(args = {})
60
+ Dir.mkdir(CONFIG[:settings_path]) if !File.exists?(CONFIG[:settings_path])
61
+
62
+ #Database-connection.
63
+ @db = Knj::Db.new(
64
+ :type => "sqlite3",
65
+ :path => CONFIG[:db_path],
66
+ :return_keys => "symbols"
67
+ )
68
+
69
+ #Models-handeler.
70
+ @ob = Knj::Objects.new(
71
+ :datarow => true,
72
+ :db => @db,
73
+ :class_path => "../models",
74
+ :class_pre => "",
75
+ :module => Openall_time_applet::Models
76
+ )
77
+
78
+ #Options used to save various information (Openall-username and such).
79
+ Knj::Opts.init("knjdb" => @db, "table" => "Option")
80
+ end
81
+
82
+ #Updates the database according to the db-schema.
83
+ def update_db
84
+ require "../conf/db_schema.rb"
85
+ rev = Knj::Db::Revision.new.init_db("db" => @db, "schema" => Openall_time_applet::DB_SCHEMA)
86
+ end
87
+
88
+ def oa_conn
89
+ begin
90
+ conn = Openall_time_applet::Connection.new(
91
+ :oata => self,
92
+ :host => Knj::Opts.get("openall_host"),
93
+ :port => Knj::Opts.get("openall_port"),
94
+ :username => Knj::Opts.get("openall_username"),
95
+ :password => Base64.strict_decode64(Knj::Opts.get("openall_password"))
96
+ )
97
+ yield(conn)
98
+ ensure
99
+ conn.destroy if conn
100
+ end
101
+ end
102
+
103
+ #Spawns the trayicon in systray.
104
+ def spawn_trayicon
105
+ return nil if @ti
106
+ @ti = Openall_time_applet::Gui::Trayicon.new(:oata => self)
107
+ end
108
+
109
+ #Spawns the preference-window.
110
+ def show_preferences
111
+ Openall_time_applet::Gui::Win_preferences.new(:oata => self)
112
+ end
113
+
114
+ def show_timelog_new
115
+ Openall_time_applet::Gui::Win_timelog_edit.new(:oata => self)
116
+ end
117
+
118
+ def show_timelog_edit(timelog)
119
+ Openall_time_applet::Gui::Win_timelog_edit.new(:oata => self, :timelog => timelog)
120
+ end
121
+
122
+ def show_overview
123
+ Openall_time_applet::Gui::Win_overview.new(:oata => self)
124
+ end
125
+ end
126
+
127
+ #Gettext support.
128
+ def _(*args, &block)
129
+ return GetText._(*args, &block)
130
+ end