openall_time_applet 0.0.11 → 0.0.12

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -1,6 +1,7 @@
1
1
  = openall_time_applet
2
2
 
3
- Description goes here.
3
+ Open main window from shell when time applet is already running:
4
+ ruby-1.9.2-head openall_time_applet.rb --cmd=open_main_window
4
5
 
5
6
  == Contributing to openall_time_applet
6
7
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.11
1
+ 0.0.12
@@ -5,6 +5,6 @@ require "../lib/openall_time_applet.rb"
5
5
 
6
6
  GetText.bindtextdomain("default", "../locales", ENV["LANGUAGE"])
7
7
 
8
- oata = Openall_time_applet.new
8
+ oata = Openall_time_applet.new(:debug => true)
9
9
 
10
10
  Gtk.main
@@ -0,0 +1,32 @@
1
+ class Openall_time_applet::Unix_socket
2
+ def initialize(args)
3
+ @args = args
4
+
5
+ #Remove the sock-file if it already exists.
6
+ File.unlink(Openall_time_applet::CONFIG[:sock_path]) if File.exists?(Openall_time_applet::CONFIG[:sock_path])
7
+
8
+ #Start Unix-socket.
9
+ require "socket"
10
+ @usock = UNIXServer.new(Openall_time_applet::CONFIG[:sock_path])
11
+
12
+ #Remove the sock-file after this process is done.
13
+ Kernel.at_exit do
14
+ File.unlink(Openall_time_applet::CONFIG[:sock_path]) if File.exists?(Openall_time_applet::CONFIG[:sock_path])
15
+ end
16
+
17
+ #Start thread that listens for connections through the Unix-socket.
18
+ Knj::Thread.new do
19
+ while client = @usock.accept
20
+ client.each_line do |line|
21
+ line = line.strip
22
+
23
+ if line.strip == "open_main_window"
24
+ @args[:oata].show_main
25
+ else
26
+ print "Unknown line: #{line}\n"
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,302 @@
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="GtkImage" id="image1">
6
+ <property name="visible">True</property>
7
+ <property name="can_focus">False</property>
8
+ <property name="stock">gtk-missing-image</property>
9
+ </object>
10
+ <object class="GtkImage" id="image2">
11
+ <property name="visible">True</property>
12
+ <property name="can_focus">False</property>
13
+ <property name="stock">gtk-missing-image</property>
14
+ </object>
15
+ <object class="GtkWindow" id="window">
16
+ <property name="can_focus">False</property>
17
+ <property name="window_position">center</property>
18
+ <property name="default_width">640</property>
19
+ <signal name="destroy" handler="on_window_destroy" swapped="no"/>
20
+ <child>
21
+ <object class="GtkVBox" id="vbox1">
22
+ <property name="visible">True</property>
23
+ <property name="can_focus">False</property>
24
+ <property name="spacing">5</property>
25
+ <child>
26
+ <object class="GtkMenuBar" id="menubar1">
27
+ <property name="visible">True</property>
28
+ <property name="can_focus">False</property>
29
+ <property name="ubuntu_local">True</property>
30
+ <child>
31
+ <object class="GtkMenuItem" id="menuitem1">
32
+ <property name="visible">True</property>
33
+ <property name="can_focus">False</property>
34
+ <property name="use_action_appearance">False</property>
35
+ <property name="label" translatable="yes">_Tracker</property>
36
+ <property name="use_underline">True</property>
37
+ <child type="submenu">
38
+ <object class="GtkMenu" id="menu1">
39
+ <property name="visible">True</property>
40
+ <property name="can_focus">False</property>
41
+ <property name="ubuntu_local">True</property>
42
+ <child>
43
+ <object class="GtkImageMenuItem" id="imiWeekview">
44
+ <property name="label" translatable="yes">Week view</property>
45
+ <property name="visible">True</property>
46
+ <property name="can_focus">False</property>
47
+ <property name="use_action_appearance">False</property>
48
+ <property name="image">image1</property>
49
+ <property name="use_stock">False</property>
50
+ <signal name="activate" handler="on_imiWeekview_activate" swapped="no"/>
51
+ </object>
52
+ </child>
53
+ <child>
54
+ <object class="GtkImageMenuItem" id="imiPreferences">
55
+ <property name="label" translatable="yes">Preferences</property>
56
+ <property name="visible">True</property>
57
+ <property name="can_focus">False</property>
58
+ <property name="use_action_appearance">False</property>
59
+ <property name="image">image2</property>
60
+ <property name="use_stock">False</property>
61
+ <signal name="activate" handler="on_imiPreferences_activate" swapped="no"/>
62
+ </object>
63
+ </child>
64
+ <child>
65
+ <object class="GtkSeparatorMenuItem" id="separatormenuitem1">
66
+ <property name="visible">True</property>
67
+ <property name="can_focus">False</property>
68
+ <property name="use_action_appearance">False</property>
69
+ </object>
70
+ </child>
71
+ <child>
72
+ <object class="GtkImageMenuItem" id="imiQuit">
73
+ <property name="label">gtk-quit</property>
74
+ <property name="visible">True</property>
75
+ <property name="can_focus">False</property>
76
+ <property name="use_action_appearance">False</property>
77
+ <property name="use_underline">True</property>
78
+ <property name="use_stock">True</property>
79
+ <signal name="activate" handler="on_imiQuit_activate" swapped="no"/>
80
+ </object>
81
+ </child>
82
+ </object>
83
+ </child>
84
+ </object>
85
+ </child>
86
+ </object>
87
+ <packing>
88
+ <property name="expand">False</property>
89
+ <property name="fill">True</property>
90
+ <property name="position">0</property>
91
+ </packing>
92
+ </child>
93
+ <child>
94
+ <object class="GtkFrame" id="frame1">
95
+ <property name="visible">True</property>
96
+ <property name="can_focus">False</property>
97
+ <property name="label_xalign">0</property>
98
+ <property name="shadow_type">none</property>
99
+ <child>
100
+ <object class="GtkAlignment" id="alignment1">
101
+ <property name="visible">True</property>
102
+ <property name="can_focus">False</property>
103
+ <property name="left_padding">12</property>
104
+ <child>
105
+ <object class="GtkHBox" id="hbox1">
106
+ <property name="visible">True</property>
107
+ <property name="can_focus">False</property>
108
+ <property name="spacing">6</property>
109
+ <child>
110
+ <object class="GtkEntry" id="txtDescr">
111
+ <property name="visible">True</property>
112
+ <property name="can_focus">True</property>
113
+ <property name="invisible_char">•</property>
114
+ <property name="primary_icon_activatable">False</property>
115
+ <property name="secondary_icon_activatable">False</property>
116
+ <property name="primary_icon_sensitive">True</property>
117
+ <property name="secondary_icon_sensitive">True</property>
118
+ <signal name="activate" handler="on_txtDescr_activate" swapped="no"/>
119
+ </object>
120
+ <packing>
121
+ <property name="expand">True</property>
122
+ <property name="fill">True</property>
123
+ <property name="position">0</property>
124
+ </packing>
125
+ </child>
126
+ <child>
127
+ <object class="GtkComboBox" id="cbTask">
128
+ <property name="visible">True</property>
129
+ <property name="can_focus">False</property>
130
+ </object>
131
+ <packing>
132
+ <property name="expand">False</property>
133
+ <property name="fill">True</property>
134
+ <property name="position">1</property>
135
+ </packing>
136
+ </child>
137
+ <child>
138
+ <object class="GtkButton" id="btnSwitch">
139
+ <property name="label" translatable="yes">Switch</property>
140
+ <property name="visible">True</property>
141
+ <property name="can_focus">True</property>
142
+ <property name="receives_default">True</property>
143
+ <property name="use_action_appearance">False</property>
144
+ <signal name="clicked" handler="on_btnSwitch_clicked" swapped="no"/>
145
+ </object>
146
+ <packing>
147
+ <property name="expand">False</property>
148
+ <property name="fill">True</property>
149
+ <property name="position">2</property>
150
+ </packing>
151
+ </child>
152
+ </object>
153
+ </child>
154
+ </object>
155
+ </child>
156
+ <child type="label">
157
+ <object class="GtkLabel" id="label1">
158
+ <property name="visible">True</property>
159
+ <property name="can_focus">False</property>
160
+ <property name="label" translatable="yes">&lt;b&gt;Description&lt;/b&gt;</property>
161
+ <property name="use_markup">True</property>
162
+ </object>
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="GtkExpander" id="expOverview">
173
+ <property name="visible">True</property>
174
+ <property name="can_focus">True</property>
175
+ <signal name="activate" handler="on_expOverview_activate" swapped="no"/>
176
+ <child>
177
+ <object class="GtkVBox" id="vbox2">
178
+ <property name="visible">True</property>
179
+ <property name="can_focus">False</property>
180
+ <property name="spacing">5</property>
181
+ <child>
182
+ <object class="GtkAlignment" id="alignment2">
183
+ <property name="visible">True</property>
184
+ <property name="can_focus">False</property>
185
+ <property name="left_padding">12</property>
186
+ <child>
187
+ <object class="GtkViewport" id="viewport1">
188
+ <property name="visible">True</property>
189
+ <property name="can_focus">False</property>
190
+ <child>
191
+ <object class="GtkScrolledWindow" id="scrolledwindow1">
192
+ <property name="visible">True</property>
193
+ <property name="can_focus">True</property>
194
+ <property name="hscrollbar_policy">automatic</property>
195
+ <property name="vscrollbar_policy">automatic</property>
196
+ <child>
197
+ <object class="GtkTreeView" id="tvTimelogs">
198
+ <property name="visible">True</property>
199
+ <property name="can_focus">True</property>
200
+ </object>
201
+ </child>
202
+ </object>
203
+ </child>
204
+ </object>
205
+ </child>
206
+ </object>
207
+ <packing>
208
+ <property name="expand">True</property>
209
+ <property name="fill">True</property>
210
+ <property name="position">0</property>
211
+ </packing>
212
+ </child>
213
+ <child>
214
+ <object class="GtkHButtonBox" id="hbuttonbox2">
215
+ <property name="visible">True</property>
216
+ <property name="can_focus">False</property>
217
+ <property name="spacing">5</property>
218
+ <property name="layout_style">start</property>
219
+ <child>
220
+ <object class="GtkButton" id="btnPlus">
221
+ <property name="label" translatable="yes">+</property>
222
+ <property name="visible">True</property>
223
+ <property name="can_focus">True</property>
224
+ <property name="receives_default">True</property>
225
+ <property name="use_action_appearance">False</property>
226
+ <signal name="clicked" handler="on_btnPlus_clicked" swapped="no"/>
227
+ </object>
228
+ <packing>
229
+ <property name="expand">False</property>
230
+ <property name="fill">False</property>
231
+ <property name="position">0</property>
232
+ </packing>
233
+ </child>
234
+ <child>
235
+ <object class="GtkButton" id="btnMinus">
236
+ <property name="label" translatable="yes">-</property>
237
+ <property name="visible">True</property>
238
+ <property name="can_focus">True</property>
239
+ <property name="receives_default">True</property>
240
+ <property name="use_action_appearance">False</property>
241
+ <signal name="clicked" handler="on_btnMinus_clicked" swapped="no"/>
242
+ </object>
243
+ <packing>
244
+ <property name="expand">False</property>
245
+ <property name="fill">False</property>
246
+ <property name="position">1</property>
247
+ </packing>
248
+ </child>
249
+ </object>
250
+ <packing>
251
+ <property name="expand">False</property>
252
+ <property name="fill">True</property>
253
+ <property name="position">1</property>
254
+ </packing>
255
+ </child>
256
+ </object>
257
+ </child>
258
+ <child type="label">
259
+ <object class="GtkLabel" id="label2">
260
+ <property name="visible">True</property>
261
+ <property name="can_focus">False</property>
262
+ <property name="label" translatable="yes">Overview</property>
263
+ </object>
264
+ </child>
265
+ </object>
266
+ <packing>
267
+ <property name="expand">True</property>
268
+ <property name="fill">True</property>
269
+ <property name="position">2</property>
270
+ </packing>
271
+ </child>
272
+ <child>
273
+ <object class="GtkHButtonBox" id="hbuttonbox1">
274
+ <property name="visible">True</property>
275
+ <property name="can_focus">False</property>
276
+ <property name="layout_style">end</property>
277
+ <child>
278
+ <object class="GtkButton" id="btnSync">
279
+ <property name="label" translatable="yes">Sync</property>
280
+ <property name="visible">True</property>
281
+ <property name="can_focus">True</property>
282
+ <property name="receives_default">True</property>
283
+ <property name="use_action_appearance">False</property>
284
+ <signal name="clicked" handler="on_btnSync_clicked" swapped="no"/>
285
+ </object>
286
+ <packing>
287
+ <property name="expand">False</property>
288
+ <property name="fill">False</property>
289
+ <property name="position">0</property>
290
+ </packing>
291
+ </child>
292
+ </object>
293
+ <packing>
294
+ <property name="expand">False</property>
295
+ <property name="fill">True</property>
296
+ <property name="position">3</property>
297
+ </packing>
298
+ </child>
299
+ </object>
300
+ </child>
301
+ </object>
302
+ </interface>
data/gui/trayicon.rb CHANGED
@@ -4,6 +4,7 @@ class Openall_time_applet::Gui::Trayicon
4
4
 
5
5
  def initialize(args)
6
6
  @args = args
7
+ @debug = @args[:oata].debug
7
8
 
8
9
  @ti = Gtk::StatusIcon.new
9
10
  @ti.signal_connect("popup-menu", &self.method(:on_statusicon_rightclick))
@@ -26,6 +27,8 @@ class Openall_time_applet::Gui::Trayicon
26
27
 
27
28
  #This updates the icon in the system-tray. It draws seconds on the icon, if a timelog is being tracked.
28
29
  def update_icon
30
+ print "Updating icon.\n" if @debug
31
+
29
32
  color = Knj::Opts.get("tray_text_color")
30
33
  color = "black" if color.to_s.strip.length <= 0
31
34
 
@@ -82,15 +85,6 @@ class Openall_time_applet::Gui::Trayicon
82
85
  end
83
86
 
84
87
  def on_statusicon_rightclick(tray, button, time)
85
- #Build rightclick-menu for tray-icon.
86
- timelog_new = Gtk::ImageMenuItem.new(Gtk::Stock::NEW)
87
- timelog_new.label = _("New timelog")
88
- timelog_new.signal_connect("activate", &self.method(:on_timelogNew_activate))
89
-
90
- overview = Gtk::ImageMenuItem.new(Gtk::Stock::EDIT)
91
- overview.label = _("Timelog list")
92
- overview.signal_connect("activate", &self.method(:on_overview_activate))
93
-
94
88
  worktime_overview = Gtk::ImageMenuItem.new(Gtk::Stock::HOME)
95
89
  worktime_overview.label = _("Week view")
96
90
  worktime_overview.signal_connect("activate", &self.method(:on_worktimeOverview_activate))
@@ -106,8 +100,6 @@ class Openall_time_applet::Gui::Trayicon
106
100
  sync.signal_connect("activate", &self.method(:on_sync_activate))
107
101
 
108
102
  menu = Gtk::Menu.new
109
- menu.append(timelog_new)
110
- menu.append(overview)
111
103
  menu.append(worktime_overview)
112
104
  menu.append(Gtk::SeparatorMenuItem.new)
113
105
  menu.append(pref)
@@ -158,19 +150,11 @@ class Openall_time_applet::Gui::Trayicon
158
150
  end
159
151
 
160
152
  def on_statusicon_leftclick(*args)
161
- @args[:oata].show_timelog_new
153
+ @args[:oata].show_main
162
154
  end
163
155
 
164
156
  def on_preferences_activate(*args)
165
- @args[:oata].show_preferences
166
- end
167
-
168
- def on_timelogNew_activate(*args)
169
- @args[:oata].show_timelog_new
170
- end
171
-
172
- def on_overview_activate(*args)
173
- @args[:oata].show_overview
157
+ @args[:oata].show_main
174
158
  end
175
159
 
176
160
  def on_worktimeOverview_activate(*args)
data/gui/win_main.rb ADDED
@@ -0,0 +1,209 @@
1
+ class Openall_time_applet::Gui::Win_main
2
+ attr_reader :args, :gui
3
+
4
+ def initialize(args)
5
+ @args = args
6
+
7
+ @gui = Gtk::Builder.new.add("../glade/win_main.glade")
8
+ @gui.translate
9
+ @gui.connect_signals{|h| method(h)}
10
+
11
+
12
+ #Generate list-store containing tasks for the task-column.
13
+ task_ls = Gtk::ListStore.new(String, String)
14
+ iter = task_ls.append
15
+ iter[0] = _("None")
16
+ iter[1] = 0.to_s
17
+
18
+ tasks = [_("Choose:")]
19
+ @args[:oata].ob.list(:Task, {"orderby" => "title"}) do |task|
20
+ iter = task_ls.append
21
+ iter[0] = task[:title]
22
+ iter[1] = task.id.to_s
23
+ tasks << task
24
+ end
25
+
26
+ #Add the tasks to the combo-box.
27
+ @gui["cbTask"].init(tasks)
28
+
29
+ init_data = @gui["tvTimelogs"].init([
30
+ _("ID"),
31
+ _("Description"),
32
+ _("Timestamp"),
33
+ _("Time"),
34
+ _("Transport"),
35
+ _("Length"),
36
+ _("Transport descr."),
37
+ _("Transport costs"),
38
+ {
39
+ :title => _("Fixed travel"),
40
+ :type => :toggle
41
+ },
42
+ {
43
+ :title => _("Int. work"),
44
+ :type => :toggle
45
+ },
46
+ {
47
+ :title => _("Sync?"),
48
+ :type => :toggle
49
+ },
50
+ {
51
+ :title => _("Task"),
52
+ :type => :combo,
53
+ :model => task_ls,
54
+ :has_entry => false
55
+ }
56
+ ])
57
+
58
+ Knj::Gtk2::Tv.editable_text_renderers_to_model(
59
+ :ob => @args[:oata].ob,
60
+ :tv => @gui["tvTimelogs"],
61
+ :model_class => :Timelog,
62
+ :renderers => init_data[:renderers],
63
+ :change_before => proc{ @dont_reload = true },
64
+ :change_after => proc{ @dont_reload = false },
65
+ :cols => {
66
+ 1 => :descr,
67
+ 2 => {:col => :timestamp, :type => :datetime},
68
+ 3 => {:col => :time, :type => :time_as_sec},
69
+ 4 => {:col => :time_transport, :type => :time_as_sec},
70
+ 5 => {:col => :transportlength, :type => :int},
71
+ 6 => {:col => :transportdescription},
72
+ 7 => {:col => :transportcosts, :type => :human_number, :decimals => 2},
73
+ 8 => {:col => :travelfixed},
74
+ 9 => {:col => :workinternal},
75
+ 10 => {:col => :sync_need},
76
+ 11 => {
77
+ :col => :task_id,
78
+ :value_callback => lambda{ |data|
79
+ task = @args[:oata].ob.get_by(:Task, {"title" => data[:value]})
80
+
81
+ if !task
82
+ return 0
83
+ else
84
+ return task.id
85
+ end
86
+ },
87
+ :value_set_callback => proc{ |data| data[:model].task_name }
88
+ }
89
+ }
90
+ )
91
+
92
+ @gui["tvTimelogs"].columns[0].visible = false
93
+ self.reload_timelogs
94
+
95
+ #Reload the treeview if something happened to a timelog.
96
+ @reload_id = @args[:oata].ob.connect("object" => :Timelog, "signals" => ["add", "update", "delete"], &self.method(:reload_timelogs))
97
+
98
+ @gui["window"].show_all
99
+ end
100
+
101
+ def dont_reload
102
+ @dont_reload = true
103
+ begin
104
+ yield
105
+ ensure
106
+ @dont_reload = false
107
+ end
108
+ end
109
+
110
+ def reload_timelogs
111
+ return nil if @dont_reload or @gui["tvTimelogs"].destroyed?
112
+ @gui["tvTimelogs"].model.clear
113
+ @args[:oata].ob.list(:Timelog, {"orderby" => "id"}) do |timelog|
114
+ @gui["tvTimelogs"].append([
115
+ timelog.id,
116
+ timelog[:descr],
117
+ timelog.timestamp_str,
118
+ timelog.time_as_human,
119
+ timelog.time_transport_as_human,
120
+ Knj::Locales.number_out(timelog[:transportlength], 0),
121
+ timelog.transport_descr_short,
122
+ Knj::Locales.number_out(timelog[:transportcosts], 2),
123
+ Knj::Strings.yn_str(timelog[:travelfixed], true, false),
124
+ Knj::Strings.yn_str(timelog[:workinternal], true, false),
125
+ Knj::Strings.yn_str(timelog[:sync_need], true, false),
126
+ timelog.task_name
127
+ ])
128
+ end
129
+ end
130
+
131
+ def on_tvTimelogs_row_activated(*args)
132
+ row = @gui["tvTimelogs"].sel
133
+ return nil if !row
134
+
135
+ timelog = @args[:oata].ob.get(:Timelog, row[0])
136
+ win_timelog_edit = @args[:oata].show_timelog_edit(timelog)
137
+ win_timelog_edit.gui["window"].modal = @gui["window"]
138
+ win_timelog_edit.gui["window"].transient_for = @gui["window"]
139
+ end
140
+
141
+ def on_imiQuit_activate
142
+ @gui["window"].destroy
143
+ end
144
+
145
+ def on_imiPreferences_activate
146
+ @args[:oata].show_preferences
147
+ end
148
+
149
+ def on_imiWeekview_activate
150
+ @args[:oata].show_worktime_overview
151
+ end
152
+
153
+ def on_window_destroy
154
+ #Unconnect reload-event. Else it will crash on call to destroyed object. Also frees up various ressources.
155
+ @args[:oata].ob.unconnect("object" => :Timelog, "conn_id" => @reload_id)
156
+ end
157
+
158
+ def on_expOverview_activate(expander)
159
+ if !expander.expanded?
160
+ @gui["window"].set_size_request(-1, 480)
161
+ else
162
+ @gui["window"].set_size_request(-1, -1)
163
+ end
164
+ end
165
+
166
+ def on_btnSwitch_clicked
167
+ task = @gui["cbTask"].sel
168
+ if !task.is_a?(Knj::Datarow)
169
+ Knj::Gtk2.msgbox(_("Please choose a task."), "warning")
170
+ return nil
171
+ end
172
+
173
+ @timelog = @args[:oata].ob.add(:Timelog, {
174
+ :task_id => task.id,
175
+ :descr => @gui["txtDescr"].text
176
+ })
177
+ @args[:oata].timelog_active = @timelog
178
+ @gui["txtDescr"].text = ""
179
+ @gui["cbTask"].sel = _("Choose:")
180
+ end
181
+
182
+ def on_btnSync_clicked
183
+ @args[:oata].sync_static do
184
+ @args[:oata].sync
185
+ end
186
+ end
187
+
188
+ def on_btnMinus_clicked
189
+ sel = @gui["tvTimelogs"].sel
190
+ tlog = @args[:oata].ob.get(:Timelog, sel[0]) if sel
191
+
192
+ if !sel or !tlog
193
+ Knj::Gtk2.msgbox(_("Please choose a timelog to delete."), "warning")
194
+ return nil
195
+ end
196
+
197
+ return nil if Knj::Gtk2.msgbox(_("Do you want to remove this timelog?"), "yesno") != "yes"
198
+ @args[:oata].ob.delete(tlog)
199
+ end
200
+
201
+ def on_btnPlus_clicked
202
+ @args[:oata].ob.add(:Timelog)
203
+ end
204
+
205
+ #Redirects 'enter'-events to 'switch'-click-event.
206
+ def on_txtDescr_activate(*args)
207
+ self.on_btnSwitch_clicked
208
+ end
209
+ end
data/gui/win_overview.rb CHANGED
@@ -1,140 +1,5 @@
1
1
  class Openall_time_applet::Gui::Win_overview
2
- attr_reader :args, :gui
3
-
4
2
  def initialize(args)
5
- @args = args
6
3
 
7
- @gui = Gtk::Builder.new.add("../glade/win_overview.glade")
8
- @gui.translate
9
- @gui.connect_signals{|h| method(h)}
10
-
11
-
12
- #Generate list-store containing tasks for the task-column.
13
- task_ls = Gtk::ListStore.new(String, String)
14
- iter = task_ls.append
15
- iter[0] = _("None")
16
- iter[1] = 0.to_s
17
-
18
- @args[:oata].ob.list(:Task, {"orderby" => "title"}) do |task|
19
- iter = task_ls.append
20
- iter[0] = task[:title]
21
- iter[1] = task.id.to_s
22
- end
23
-
24
- init_data = @gui["tvTimelogs"].init([
25
- _("ID"),
26
- _("Description"),
27
- _("Timestamp"),
28
- _("Time"),
29
- _("Transport"),
30
- _("Length"),
31
- _("Transport descr."),
32
- _("Transport costs"),
33
- {
34
- :title => _("Fixed travel"),
35
- :type => :toggle
36
- },
37
- {
38
- :title => _("Int. work"),
39
- :type => :toggle
40
- },
41
- {
42
- :title => _("Sync?"),
43
- :type => :toggle
44
- },
45
- {
46
- :title => _("Task"),
47
- :type => :combo,
48
- :model => task_ls,
49
- :has_entry => false
50
- }
51
- ])
52
-
53
- Knj::Gtk2::Tv.editable_text_renderers_to_model(
54
- :ob => @args[:oata].ob,
55
- :tv => @gui["tvTimelogs"],
56
- :model_class => :Timelog,
57
- :renderers => init_data[:renderers],
58
- :change_before => proc{ @dont_reload = true },
59
- :change_after => proc{ @dont_reload = false },
60
- :cols => {
61
- 1 => :descr,
62
- 2 => {:col => :timestamp, :type => :datetime},
63
- 3 => {:col => :time, :type => :time_as_sec},
64
- 4 => {:col => :time_transport, :type => :time_as_sec},
65
- 5 => {:col => :transportlength, :type => :int},
66
- 6 => {:col => :transportdescription},
67
- 7 => {:col => :transportcosts, :type => :human_number, :decimals => 2},
68
- 8 => {:col => :travelfixed},
69
- 9 => {:col => :workinternal},
70
- 10 => {:col => :sync_need},
71
- 11 => {
72
- :col => :task_id,
73
- :value_callback => lambda{ |data|
74
- task = @args[:oata].ob.get_by(:Task, {"title" => data[:value]})
75
-
76
- if !task
77
- return 0
78
- else
79
- return task.id
80
- end
81
- },
82
- :value_set_callback => proc{ |data| data[:model].task_name }
83
- }
84
- }
85
- )
86
-
87
- @gui["tvTimelogs"].columns[0].visible = false
88
- self.reload_timelogs
89
-
90
- #Reload the treeview if something happened to a timelog.
91
- @reload_id = @args[:oata].ob.connect("object" => :Timelog, "signals" => ["add", "update", "delete"], &self.method(:reload_timelogs))
92
-
93
- @gui["window"].show_all
94
- end
95
-
96
- def dont_reload
97
- @dont_reload = true
98
- begin
99
- yield
100
- ensure
101
- @dont_reload = false
102
- end
103
- end
104
-
105
- def reload_timelogs
106
- return nil if @dont_reload
107
- @gui["tvTimelogs"].model.clear
108
- @args[:oata].ob.list(:Timelog, {"orderby" => "id"}) do |timelog|
109
- @gui["tvTimelogs"].append([
110
- timelog.id,
111
- timelog.descr_short,
112
- timelog.timestamp_str,
113
- timelog.time_as_human,
114
- timelog.time_transport_as_human,
115
- Knj::Locales.number_out(timelog[:transportlength], 0),
116
- timelog.transport_descr_short,
117
- Knj::Locales.number_out(timelog[:transportcosts], 2),
118
- Knj::Strings.yn_str(timelog[:travelfixed], true, false),
119
- Knj::Strings.yn_str(timelog[:workinternal], true, false),
120
- Knj::Strings.yn_str(timelog[:sync_need], true, false),
121
- timelog.task_name
122
- ])
123
- end
124
- end
125
-
126
- def on_tvTimelogs_row_activated(*args)
127
- row = @gui["tvTimelogs"].sel
128
- return nil if !row
129
-
130
- timelog = @args[:oata].ob.get(:Timelog, row[0])
131
- win_timelog_edit = @args[:oata].show_timelog_edit(timelog)
132
- win_timelog_edit.gui["window"].modal = @gui["window"]
133
- win_timelog_edit.gui["window"].transient_for = @gui["window"]
134
- end
135
-
136
- def on_window_destroy
137
- #Unconnect reload-event. Else it will crash on call to destroyed object. Also frees up various ressources.
138
- @args[:oata].ob.unconnect("object" => :Timelog, "conn_id" => @reload_id)
139
4
  end
140
5
  end
@@ -9,23 +9,10 @@ else
9
9
  require "knjrbfw"
10
10
  end
11
11
 
12
- require "gtk2"
13
12
  require "sqlite3"
14
13
  require "gettext"
15
14
  require "base64"
16
15
 
17
- #For msgbox and translation of windows.
18
- require "knj/gtk2"
19
-
20
- #For easy initialization, getting and settings of values on comboboxes.
21
- require "knj/gtk2_cb"
22
-
23
- #For easy initialization, getting and settings of values on treeviews.
24
- require "knj/gtk2_tv"
25
-
26
- #For easy making status-windows with progressbar.
27
- require "knj/gtk2_statuswindow"
28
-
29
16
  #The base class of the applet. Spawns all windows, holds subclasses for models and gui, holds models objects and holds database-objects.
30
17
  class Openall_time_applet
31
18
  #Shortcut to start the application. Used by the Ubuntu-package.
@@ -68,17 +55,23 @@ class Openall_time_applet
68
55
  end
69
56
 
70
57
  #Various readable variables.
71
- attr_reader :db, :ob, :ti, :timelog_active, :timelog_active_time
58
+ attr_reader :db, :debug, :ob, :ti, :timelog_active, :timelog_active_time
72
59
  attr_accessor :reminder_next
73
60
 
74
61
  #Config controlling paths and more.
75
62
  CONFIG = {
76
63
  :settings_path => "#{Knj::Os.homedir}/.openall_time_applet",
77
- :db_path => "#{Knj::Os.homedir}/.openall_time_applet/openall_time_applet.sqlite3"
64
+ :run_path => "#{Knj::Os.homedir}/.openall_time_applet/run",
65
+ :db_path => "#{Knj::Os.homedir}/.openall_time_applet/openall_time_applet.sqlite3",
66
+ :sock_path => "#{Knj::Os.homedir}/.openall_time_applet/sock"
78
67
  }
79
68
 
80
69
  #Initializes config-dir and database.
81
70
  def initialize(args = {})
71
+ self.check_runfile_and_cmds
72
+ self.require_gtk2
73
+
74
+ @debug = args[:debug]
82
75
  Dir.mkdir(CONFIG[:settings_path]) if !File.exists?(CONFIG[:settings_path])
83
76
 
84
77
  #Database-connection.
@@ -118,6 +111,59 @@ class Openall_time_applet
118
111
 
119
112
  #Start reminder.
120
113
  self.reminding
114
+
115
+ #Start unix-socket that listens for remote control.
116
+ @unix_socket = Openall_time_applet::Unix_socket.new(:oata => self)
117
+ end
118
+
119
+ #Creates a runfile or sending a command to the running OpenAll-Time-Applet through the Unix-socket.
120
+ def check_runfile_and_cmds
121
+ if File.exists?(CONFIG[:run_path])
122
+ cmd = nil
123
+ ARGV.each do |val|
124
+ if match = val.match(/^--cmd=(.+)$/)
125
+ cmd = match[1]
126
+ break
127
+ end
128
+ end
129
+
130
+ if cmd
131
+ print "Executing command through sock: #{cmd}\n"
132
+
133
+ require "socket"
134
+ UNIXSocket.open(CONFIG[:sock_path]) do |sock|
135
+ sock.puts(cmd)
136
+ end
137
+ end
138
+
139
+ puts "Already running"
140
+ exit
141
+ end
142
+
143
+ File.open(CONFIG[:run_path], "w") do |fp|
144
+ fp.write(Process.pid)
145
+ end
146
+
147
+ Kernel.at_exit do
148
+ File.unlink(CONFIG[:run_path]) if File.exists?(CONFIG[:run_path]) and File.read(CONFIG[:run_path]).to_i == Process.pid
149
+ end
150
+ end
151
+
152
+ #Requires the heavy Gtk-stuff.
153
+ def require_gtk2
154
+ require "gtk2"
155
+
156
+ #For msgbox and translation of windows.
157
+ require "knj/gtk2"
158
+
159
+ #For easy initialization, getting and settings of values on comboboxes.
160
+ require "knj/gtk2_cb"
161
+
162
+ #For easy initialization, getting and settings of values on treeviews.
163
+ require "knj/gtk2_tv"
164
+
165
+ #For easy making status-windows with progressbar.
166
+ require "knj/gtk2_statuswindow"
121
167
  end
122
168
 
123
169
  #Updates the database according to the db-schema.
@@ -179,6 +225,12 @@ class Openall_time_applet
179
225
  @ti = Openall_time_applet::Gui::Trayicon.new(:oata => self)
180
226
  end
181
227
 
228
+ def show_main
229
+ Knj::Gtk2::Window.unique!("main") do
230
+ Openall_time_applet::Gui::Win_main.new(:oata => self)
231
+ end
232
+ end
233
+
182
234
  #Spawns the preference-window.
183
235
  def show_preferences
184
236
  Knj::Gtk2::Window.unique!("preferences") do
@@ -230,10 +282,10 @@ class Openall_time_applet
230
282
  end
231
283
 
232
284
  #Synchronizes organisations, tasks and worktimes.
233
- def sync_static
285
+ def sync_static(args = nil)
234
286
  sw = Knj::Gtk2::StatusWindow.new
235
287
 
236
- Knj::Thread.new do
288
+ return Knj::Thread.new do
237
289
  begin
238
290
  sw.label = _("Updating organisation-cache.")
239
291
  self.update_organisation_cache
@@ -247,7 +299,8 @@ class Openall_time_applet
247
299
  self.update_worktime_cache
248
300
  sw.percent = 1
249
301
 
250
- sleep 1
302
+ sleep 1 if !block_given?
303
+ yield if block_given?
251
304
  rescue => e
252
305
  Knj::Gtk2.msgbox("msg" => Knj::Errors.error_str(e), "type" => "warning", "title" => _("Error"), "run" => false)
253
306
  ensure
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{openall_time_applet}
8
- s.version = "0.0.11"
8
+ s.version = "0.0.12"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Kasper Johansen"]
12
- s.date = %q{2012-06-12}
12
+ s.date = %q{2012-06-18}
13
13
  s.default_executable = %q{openall_time_applet.rb}
14
14
  s.description = %q{Off-line time-tracking for OpenAll with syncing when online.}
15
15
  s.email = %q{k@spernj.org}
@@ -30,17 +30,20 @@ Gem::Specification.new do |s|
30
30
  "bin/openall_time_applet.rb",
31
31
  "classes/connection.rb",
32
32
  "classes/translations.rb",
33
+ "classes/unix_socket.rb",
33
34
  "conf/db_schema.rb",
34
35
  "gfx/icon_time_black.png",
35
36
  "gfx/icon_time_green_casalogic.png",
36
37
  "gfx/icon_time_orig.png",
37
38
  "gfx/icon_time_white.png",
39
+ "glade/win_main.glade",
38
40
  "glade/win_overview.glade",
39
41
  "glade/win_preferences.glade",
40
42
  "glade/win_sync_overview.glade",
41
43
  "glade/win_timelog_edit.glade",
42
44
  "glade/win_worktime_overview.glade",
43
45
  "gui/trayicon.rb",
46
+ "gui/win_main.rb",
44
47
  "gui/win_overview.rb",
45
48
  "gui/win_preferences.rb",
46
49
  "gui/win_sync_overview.rb",
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: openall_time_applet
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.11
5
+ version: 0.0.12
6
6
  platform: ruby
7
7
  authors:
8
8
  - Kasper Johansen
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2012-06-12 00:00:00 +02:00
13
+ date: 2012-06-18 00:00:00 +02:00
14
14
  default_executable: openall_time_applet.rb
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -155,17 +155,20 @@ files:
155
155
  - bin/openall_time_applet.rb
156
156
  - classes/connection.rb
157
157
  - classes/translations.rb
158
+ - classes/unix_socket.rb
158
159
  - conf/db_schema.rb
159
160
  - gfx/icon_time_black.png
160
161
  - gfx/icon_time_green_casalogic.png
161
162
  - gfx/icon_time_orig.png
162
163
  - gfx/icon_time_white.png
164
+ - glade/win_main.glade
163
165
  - glade/win_overview.glade
164
166
  - glade/win_preferences.glade
165
167
  - glade/win_sync_overview.glade
166
168
  - glade/win_timelog_edit.glade
167
169
  - glade/win_worktime_overview.glade
168
170
  - gui/trayicon.rb
171
+ - gui/win_main.rb
169
172
  - gui/win_overview.rb
170
173
  - gui/win_preferences.rb
171
174
  - gui/win_sync_overview.rb
@@ -195,7 +198,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
195
198
  requirements:
196
199
  - - ">="
197
200
  - !ruby/object:Gem::Version
198
- hash: -4306951825399689854
201
+ hash: 2134031448071051365
199
202
  segments:
200
203
  - 0
201
204
  version: "0"