openall_time_applet 0.0.11 → 0.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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"