savant-scenes 0.1.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9143eeadd43302951c43db507ed5340b094970ee
4
+ data.tar.gz: 1ca8e91f8272abb8e11b9663d0c7e7f647d63b3a
5
+ SHA512:
6
+ metadata.gz: 1761df1a223088982ebca964a65875b3e055c967c2d28de0afca2a116f4aa369fa12f460e72c1a0a5f753a295588db33b110e2b941ab321a510844d6b72d296e
7
+ data.tar.gz: d86688aa22863e33de2248cb2a8013989900ced5ef20c88cef5ccc3d5cbaf29f7af0af4629068343a63a4e80f03c3ebd171c6e310f384d7a3e95533bf53bddb5
data/bin/scenes ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'rubygems'
4
+ require "vrlib"
5
+ require 'net/http'
6
+ require 'uri'
7
+ require 'net/scp'
8
+ require 'socket'
9
+ require 'timeout'
10
+ require 'ipaddress'
11
+ require 'sqlite3'
12
+
13
+ # from require_all gem:
14
+ require_rel 'src/'
15
+
16
+
17
+ SceneManager.new.show_glade()
18
+
@@ -0,0 +1,444 @@
1
+ require 'rubygems'
2
+ require 'net/http'
3
+ require 'net/scp'
4
+ require 'uri'
5
+ require 'socket'
6
+ require 'timeout'
7
+ require 'ipaddress'
8
+ require 'sqlite3'
9
+
10
+
11
+ class SceneManager
12
+
13
+ attr_accessor :ftv
14
+ include GladeGUI
15
+
16
+ def initialize
17
+ #Initialize the Scenes List view
18
+ @listviewSavantScenes = VR::ListView.new(:modify => TrueClass, :scene => String, :user => String, :id => String, :image => String, :isGlobal => String, :isActive => String, :isScheduled => String, :hasCustomImage => String, :userSceneOrder => String, :tags => String)
19
+ @listviewSavantScenes.col_sortable(true)
20
+ @listviewSavantScenes.col_sort_column_id(:scene => @listviewSavantScenes.id(:scene), :user => @listviewSavantScenes.id(:user))
21
+ @listviewSavantScenes.col_title(:modify => "", :scene => "Scene Name", :tags => "Zones Affected", :isGlobal => "Global", :isActive => "Active", :isScheduled => "Scheduled", :hasCustomImage => "Custom Image", :userSceneOrder => "User Order")
22
+ @listviewSavantScenes.col_xalign(:isGlobal => 0.5, :isActive => 0.5, :isScheduled => 0.5, :hasCustomImage => 0.5, :userSceneOrder => 0.5)
23
+ @listviewSavantScenes.col_width(:tags => 100, :image => 100)
24
+ @listviewSavantScenes.ren_editable(:scene => true, :isActive => true, :user => true, :id => true)
25
+
26
+ row = @listviewSavantScenes.add_row
27
+ row[:scene] = ""
28
+ @listviewSavantScenes.visible = true
29
+
30
+ #Validate user name change to email address (checks for text before and after @ symbol, as well as 3 chars after the last ".""
31
+ @listviewSavantScenes.renderer(:user).validate_block = Proc.new { |text, model_sym, row, view|
32
+ x = text.length
33
+ suffix = text[x-4..x]
34
+ if text.include?("@") && text.include?(".") && text.split(/[@,.]/).length == 3 && suffix.chr == "."
35
+ true
36
+ else
37
+ false
38
+ alert("Please enter a valid email address.", :parent => self)
39
+ end
40
+ text.include?("@") && text.include?(".") && text.split(/[@,.]/).length == 3 && suffix.chr == "."
41
+ }
42
+
43
+ #Validate id change to allow it to be copied for Bluepritn entry, but not actually changed
44
+ @listviewSavantScenes.renderer(:id).validate_block = Proc.new { |text, model_sym, row, view|
45
+ text == "this is never going to validate"
46
+ }
47
+
48
+ #Validate ACtively Scheduled to only be a 0 or 1
49
+ @listviewSavantScenes.renderer(:isActive).validate_block = Proc.new { |text, model_sym, row, view|
50
+ text == "0" || text == "1"
51
+ }
52
+
53
+ # Capture user name change, save to SQL, and transfer SQL to host
54
+ # @listviewSavantScenes.renderer(:user).edited_callback = Proc.new { |model_sym, row, view |
55
+ # alert "User email changed to : " + row[:user].to_s
56
+ # }
57
+ #
58
+ # Capture scene name change, save to SQL, and transfer SQL to host
59
+ # @listviewSavantScenes.renderer(:scene).edited_callback = Proc.new { |model_sym, row, view |
60
+ # alert "Scene name changed to : " + row[:scene].to_s
61
+ # }
62
+ #
63
+ # @listviewSavantScenes.renderer(:isActive).edited_callback = Proc.new { |model_sym, row, view |
64
+ # alert "Scene is scheduled changed to : " + row[:isScheduled].to_s
65
+ # }
66
+ end
67
+
68
+ #####Set variables before windows load#####
69
+ def before_show()
70
+ @savantURL = "192.168.77.40"
71
+ @login = 'RPM'
72
+ @password = 'RPM'
73
+
74
+ @ftv = VR::FileTreeView.new(Dir.home, File.join(File.dirname(__FILE__), "/../img"), glob = "*", validate_block = nil)
75
+ @builder["scrolledwindow_BackupRestore"].add(@ftv)
76
+ @ftv.set_show_expanders(true)
77
+ end
78
+
79
+ #####Check to see if Racepoint and SCLI bridge ports are open on host#####
80
+ def is_port_open?(ip, port)
81
+ if IPAddress.valid? ip
82
+ begin
83
+ Timeout::timeout(1) do
84
+ begin
85
+ s = TCPSocket.new(ip, port)
86
+ s.close
87
+ return true
88
+ rescue StandardError
89
+ return false
90
+ end
91
+ end
92
+ rescue Timeout::Error
93
+ end
94
+ end
95
+ end
96
+
97
+ #####Checks to see if Savant version is greater than 8.3 to support scene features.
98
+ def savantVersion?(ip)
99
+ begin
100
+ @builder["labelHostInfo"].label = ""
101
+ Net::SSH.start(ip, @login, :password => @password, :paranoid => false, :timeout => 3) do |ssh|
102
+ #Check host type and update sclibridge location for reference, though only Pro Host is supported
103
+ ssh.open_channel do |ch, success|
104
+ ch.exec("uname")
105
+ ch.on_data do |ch, data|
106
+ if data.to_s.include? 'Darwin'
107
+ @scliBridge = "~/Applications/RacePointMedia/sclibridge "
108
+ @dis = "/Users/RPM/Library/Application Support/RacePointMedia/statusfiles/dis/dashboard.sqlite"
109
+ else
110
+ @scliBridge = "/usr/local/bin/sclibridge "
111
+ @dis = "GNUstep/Library/ApplicationSupport/RacePointMedia/statusfiles/dis/dashboard.sqlite"
112
+ end
113
+ end
114
+ end
115
+ ssh.loop
116
+ #parse the rpmSystemInfo.plist form the pro host to get host name
117
+ if @scliBridge == "~/Applications/RacePointMedia/sclibridge "
118
+ ssh.open_channel do |ch, success|
119
+
120
+ ch.exec("plutil -p 'library/application support/racepointmedia/userconfig.rpmconfig/rpmSystemInfo.plist'")
121
+ ch.on_data do |ch, data|
122
+ if data.to_s.include? 'module'
123
+ x = data.split("\"RPMSystemName\" => ")
124
+ x = x[1].split("\n")
125
+ @savantHostName = x[0][1..-2]
126
+ @str = @scliBridge + "readstate \"" + @savantHostName + ".SoftwareVersion\""
127
+ end
128
+ end
129
+ end
130
+ ssh.loop
131
+ #parse the rpmSystemInfo.plist from the smart host to get host name
132
+ elsif @scliBridge == "/usr/local/bin/sclibridge "
133
+ ssh.open_channel do |ch, success|
134
+ ch.exec("strings 'GNUstep/Library/ApplicationSupport/RacePointMedia/userConfig.rpmConfig/rpmSystemInfo.plist'")
135
+ ch.on_data do |ch, data|
136
+ if data.to_s.include? 'DOCTYPE'
137
+ x = data.split("RPMUserDefinedName</key><string>")
138
+ y = x[1].split("</string>")
139
+ x = x[1].split("VERSION</key><integer>")
140
+ x = x[1].split("</integer>")
141
+ alert("Instant host found at specified IP address. Instant hosts are not supported (even by Savant!)", :parent => self)
142
+ return false
143
+ @instantHost = true
144
+ elsif data.to_s.include? 'module'
145
+ x = data.split('module')
146
+ x = x[1].split("\n")
147
+ @savantHostName = x[0][1..-1]
148
+ @str = @scliBridge + "readstate \"" + @savantHostName + ".SoftwareVersion\""
149
+ end
150
+ end
151
+ end
152
+ ssh.loop
153
+ end
154
+ #Use host name to query SoftwareVersion state from host
155
+ ssh.open_channel do |ch, success|
156
+ ch.exec(@str)
157
+ ch.on_data do |ch, data|
158
+ @savantHostVersion = data
159
+ end
160
+ end
161
+ ssh.loop
162
+ end
163
+ @builder["labelHostInfo"].text = @savantHostName + " Version : " + @savantHostVersion
164
+
165
+ #return true if version is 8.3 or later
166
+ if @savantHostVersion.to_r > 8.2 && !@savantHostVersion.empty?
167
+ return true
168
+ else
169
+ return false
170
+ end
171
+
172
+ rescue Net::SSH::ConnectionTimeout, SocketError, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, Errno::EHOSTDOWN
173
+
174
+ end
175
+ end
176
+
177
+ #Enter key scans for hsot from IP address field
178
+ def savantURL__key_press_event(view, evt)
179
+ return unless evt.keyval == 65293
180
+ buttonScanHost__clicked()
181
+ end
182
+
183
+ #Rebuild listview window
184
+ def repaint
185
+ @builder["listviewSavantScenes"].hide
186
+ @builder["window1"].show_all
187
+ unless savantVersion?(@savantURL)
188
+ @builder["buttonActivateScene"].hide
189
+ end
190
+ end
191
+
192
+ #Scan the specified IP for scenes
193
+ def buttonScanHost__clicked(*argv)
194
+ @savantURL = @builder["savantURL"].text
195
+ if is_port_open?(@savantURL,"11263") || is_port_open?(@savantURL,"48664") || is_port_open?(@savantURL,"1124")
196
+ unless savantVersion?(@savantURL)
197
+ @builder["buttonActivateScene"].hide
198
+ end
199
+ begin
200
+ @listviewSavantScenes.model.clear
201
+ Net::SSH.start(@savantURL, @login, :password => @password, :paranoid => false, :timeout => 3) do |ssh|
202
+ # test to see if remote files exist and transfer them if they do
203
+ fileExists = ssh.exec!("[ -f #{@dis} ] && echo 'true' || echo 'false'")
204
+ unless fileExists == 'false'
205
+ ssh.scp.download!(@dis, '/tmp/')
206
+ #read from sqlite database and add to listview
207
+ @db = SQLite3::Database.open('/tmp/dashboard.sqlite')
208
+ @db.execute( "select * from scenes" ) do |rowData|
209
+ row = @listviewSavantScenes.add_row
210
+ row[:modify] = false
211
+ row[:id] = rowData.shift
212
+ row[:scene] = rowData.shift
213
+ row[:image] = rowData.shift
214
+ row[:tags] = rowData.shift
215
+ row[:isGlobal] = rowData.shift.to_s
216
+ row[:isActive] = rowData.shift.to_s
217
+ row[:isScheduled] = rowData.shift.to_s
218
+ row[:hasCustomImage] = rowData.shift.to_s
219
+
220
+ stm = @db.prepare( "select * from sceneusermap where sceneIdentifier=?" )
221
+ stm.bind_param 1, row[:id]
222
+ rs = stm.execute.next
223
+ row[:user] = rs[2]
224
+ row[:userSceneOrder] = rs[3].to_s
225
+ stm.close
226
+ end
227
+ repaint
228
+ end
229
+ end
230
+ rescue Net::SSH::ConnectionTimeout, SocketError, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, Errno::EHOSTDOWN
231
+ alert("Host not reached.", :parent => self)
232
+ end
233
+ else
234
+ alert("A Savant host was not found at the specified IP address.", :parent => self)
235
+ @listviewSavantScenes.model.clear
236
+ repaint
237
+ end
238
+ end
239
+
240
+ #Transfer database from tmp folder to remote host
241
+ def updateDatabase()
242
+ begin
243
+ Net::SSH.start(@savantURL, @login, :password => @password, :paranoid => false, :timeout => 3) do |ssh|
244
+ fileExists = ssh.exec!("[ -f #{@dis} ] && echo 'true' || echo 'false'")
245
+ unless fileExists == 'false'
246
+ ssh.scp.upload!('/tmp/dashboard.sqlite', @dis.chomp("dashboard.sqlite"))
247
+ alert("Please re-open the Savant Pro app to reflect changes.", :parent => self)
248
+ end
249
+ end
250
+ rescue Net::SSH::ConnectionTimeout, SocketError, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, Errno::EHOSTDOWN
251
+ alert("Host not reached.", :parent => self)
252
+ end
253
+ end
254
+
255
+ # #
256
+ # SCENE ACTIONS #
257
+ # #
258
+
259
+ #Activate the selected scene
260
+ def buttonActivateScene__clicked(*argv)
261
+ get_glade_variables()
262
+ activateScenes = []
263
+ activateIDs = []
264
+ activateUsers = []
265
+ @listviewSavantScenes.each_row do |row|
266
+ if row[:modify]
267
+ @str = @scliBridge + "activateScene \'" + row[:scene] + "\' \'" + row[:id] + "\' \'" + row[:user] + "\'"
268
+ begin
269
+ Net::SSH.start(@savantURL, @login, :password => @password, :paranoid => false, :timeout => 3) do |ssh|
270
+ ssh.exec!(@str)
271
+ alert("Scene activated: #{row[:scene]}", :parent => self)
272
+ end
273
+ rescue Net::SSH::ConnectionTimeout, SocketError, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, Errno::EHOSTDOWN
274
+ alert("Host not reached.", :parent => self)
275
+ end
276
+ end
277
+ end
278
+ end
279
+
280
+ #Edit the selected scenes
281
+ def buttonApplyEdits__clicked(*argv)
282
+ get_glade_variables()
283
+ editScenes = []
284
+ editIDs = []
285
+ editUsers = []
286
+ editActive = []
287
+ count = 0
288
+ @listviewSavantScenes.each_row do |row|
289
+ if row[:modify]
290
+ count += 1
291
+ editScenes << row[:scene]
292
+ editIDs << row[:id]
293
+ editUsers << row[:user]
294
+ editActive << row[:isActive]
295
+ end
296
+ end
297
+ #make sure a scene was selected, else alert the user
298
+ if count > 0
299
+ #confirm the edits should be made
300
+ strAlert = "Do you want to apply changes to the following scenes on the Savant host?\n\n" + editScenes.join("\n")
301
+ if alert(strAlert, :headline => "Edit Scenes?", :button_yes => "Apply Changes", :button_cancel => "Cancel", :parent => self)
302
+ count = 0
303
+ #edit the database with the updated info
304
+ editIDs.each do |id|
305
+ stm = @db.prepare( "update sceneusermap set user=? where sceneIdentifier=?" )
306
+ stm.bind_param 1, editUsers[count]
307
+ stm.bind_param 2, id
308
+ stm.execute
309
+ stm.close
310
+ stm = @db.prepare( "update scenes set name=?, isActive=? where identifier=?" )
311
+ stm.bind_param 1, editScenes[count]
312
+ stm.bind_param 2, editActive[count]
313
+ stm.bind_param 3, id
314
+ stm.execute
315
+ stm.close
316
+
317
+ count += 1
318
+ end
319
+ updateDatabase()
320
+ buttonScanHost__clicked()
321
+ end
322
+ else
323
+ alert("Please select at least 1 row to modify.", :parent => self)
324
+ end
325
+ end
326
+
327
+ #Delete the selected scenes
328
+ def buttonDeleteScene__clicked(*argv)
329
+ get_glade_variables()
330
+ deleteScenes = []
331
+ deleteIDs = []
332
+ count = 0
333
+ @listviewSavantScenes.each_row do |row|
334
+ if row[:modify]
335
+ count += 1
336
+ deleteScenes << row[:scene]
337
+ deleteIDs << row[:id]
338
+ end
339
+ end
340
+ #make sure a scene was selected, else alert the user
341
+ if count > 0
342
+ #confirm the edits should be made
343
+ strAlert = "Do you want to delete the following scenes from the Savant host?\n\n" + deleteScenes.join("\n")
344
+ if alert(strAlert, :headline => "Delete Scenes?", :button_yes => "Delete", :button_cancel => "Cancel", :parent => self)
345
+ #edit the database with the updated info
346
+ deleteIDs.each do |id|
347
+ stm = @db.prepare( "delete from sceneusermap where sceneIdentifier=?" )
348
+ stm.bind_param 1, id
349
+ stm.execute
350
+ stm.close
351
+ stm = @db.prepare( "delete from scenes where identifier=?" )
352
+ stm.bind_param 1, id
353
+ stm.execute
354
+ stm.close
355
+ stm = @db.prepare( "delete from scenedefinitions where sceneIdentifier=?" )
356
+ stm.bind_param 1, id
357
+ stm.execute
358
+ stm.close
359
+ end
360
+ updateDatabase()
361
+ buttonScanHost__clicked()
362
+ end
363
+ else
364
+ alert("Please select at least 1 row to modify.", :parent => self)
365
+ end
366
+ end
367
+
368
+ # #
369
+ # BACKUP AND RESTORE #
370
+ # #
371
+
372
+ #FileTreeView expand and collapse for file backup and restore
373
+ def ftv__row_activated(_self, path, col)
374
+ @ftv.expand_or_collapse_folder()
375
+ end
376
+
377
+ #Restore files from local filesystem to remote host
378
+ def buttonRestore__clicked(*a)
379
+ return unless row = @ftv.selected_rows.first
380
+ backupDir = row[:path]
381
+ #Get folder name if a file is selected.
382
+ if File.file?(backupDir)
383
+ backupDir = File.dirname(backupDir)
384
+ end
385
+ #Check that folder contains correct files
386
+ if File.file?(backupDir + "/dashboard.sqlite")
387
+ begin
388
+ Net::SSH.start(@savantURL, @login, :password => @password, :paranoid => false, :timeout => 3) do |ssh|
389
+ # test to see if remote folder exists, if so, transfer files and restart harbridge
390
+ dirExists = ssh.exec!("[ -d #{@dis.chomp("dashboard.sqlite")} ] && echo 'true' || echo 'false'")
391
+ if dirExists
392
+ ssh.scp.upload!(backupDir + "/dashboard.sqlite", @dis.chomp("dashboard.sqlite"))
393
+ alert("File has been restored from " + row[:path] + "\n\nPlease re-open the Savant Pro app to reflect changes.", :parent => self)
394
+ @builder["windowBackupRestore"].hide
395
+ buttonScanHost__clicked()
396
+ else
397
+ alert("Users/RPM/habridge/data folder not found on remote host.", :parent => self)
398
+ end
399
+ end
400
+ end
401
+ else
402
+ alert("Selected directory does not contain dashboard.sqlite.", :parent => self)
403
+ end
404
+ end
405
+
406
+ #Backup files from remote host to local filesystem
407
+ def buttonBackup__clicked(*a)
408
+ return unless row = @ftv.selected_rows.first
409
+ backupDir = row[:path]
410
+ #Get folder name if a file is selected.
411
+ if File.file?(backupDir)
412
+ backupDir = File.dirname(backupDir)
413
+ end
414
+ begin
415
+ Net::SSH.start(@savantURL, @login, :password => @password, :paranoid => false, :timeout => 3) do |ssh|
416
+ # test to see if remote files exist and transfer them if they do
417
+ fileExists = ssh.exec!("[ -f #{@dis} ] && echo 'true' || echo 'false'")
418
+ unless fileExists == 'false'
419
+ ssh.scp.download!(@dis, backupDir)
420
+ end
421
+ repaint
422
+ end
423
+ rescue Net::SSH::ConnectionTimeout, SocketError, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, Errno::EHOSTDOWN
424
+ alert("Host not reached.", :parent => self)
425
+ end
426
+ alert("File backed up to " + row[:path], :parent => self)
427
+ @builder["windowBackupRestore"].hide
428
+ buttonScanHost__clicked()
429
+
430
+ end
431
+
432
+ def buttonBackupRestore__clicked(*argv)
433
+ @builder["windowBackupRestore"].show
434
+ end
435
+
436
+ def buttonBackupRestoreCancel__clicked(*argv)
437
+ @builder["windowBackupRestore"].hide
438
+ end
439
+
440
+ def buttonExit__clicked(*args)
441
+ @builder["window1"].destroy
442
+ end
443
+
444
+ end
@@ -0,0 +1,429 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!-- Generated with glade 3.20.0 -->
3
+ <interface>
4
+ <requires lib="gtk+" version="3.0"/>
5
+ <object class="GtkWindow" id="window1">
6
+ <property name="can_focus">False</property>
7
+ <property name="has_focus">True</property>
8
+ <property name="hexpand">True</property>
9
+ <property name="vexpand">True</property>
10
+ <property name="window_position">center</property>
11
+ <property name="default_width">1200</property>
12
+ <child>
13
+ <object class="GtkGrid">
14
+ <property name="visible">True</property>
15
+ <property name="can_focus">False</property>
16
+ <property name="margin_left">12</property>
17
+ <property name="margin_right">12</property>
18
+ <property name="hexpand">True</property>
19
+ <property name="vexpand">False</property>
20
+ <child>
21
+ <object class="GtkLabel">
22
+ <property name="visible">True</property>
23
+ <property name="can_focus">False</property>
24
+ <property name="margin_top">12</property>
25
+ <property name="margin_bottom">12</property>
26
+ <property name="label" translatable="yes">&lt;big&gt;&lt;b&gt;Savant Scene Manager&lt;/b&gt;&lt;/big&gt;</property>
27
+ <property name="use_markup">True</property>
28
+ </object>
29
+ <packing>
30
+ <property name="left_attach">0</property>
31
+ <property name="top_attach">0</property>
32
+ </packing>
33
+ </child>
34
+ <child>
35
+ <object class="GtkGrid">
36
+ <property name="visible">True</property>
37
+ <property name="can_focus">False</property>
38
+ <property name="margin_left">12</property>
39
+ <property name="margin_right">12</property>
40
+ <property name="column_homogeneous">True</property>
41
+ <child>
42
+ <object class="GtkButtonBox">
43
+ <property name="visible">True</property>
44
+ <property name="can_focus">False</property>
45
+ <property name="margin_right">12</property>
46
+ <property name="margin_top">12</property>
47
+ <property name="margin_bottom">12</property>
48
+ <property name="spacing">7</property>
49
+ <property name="layout_style">end</property>
50
+ <child>
51
+ <object class="GtkButton" id="buttonBackupRestore">
52
+ <property name="label" translatable="yes">Backup/Restore</property>
53
+ <property name="visible">True</property>
54
+ <property name="can_focus">True</property>
55
+ <property name="receives_default">True</property>
56
+ </object>
57
+ <packing>
58
+ <property name="expand">True</property>
59
+ <property name="fill">True</property>
60
+ <property name="position">1</property>
61
+ </packing>
62
+ </child>
63
+ <child>
64
+ <object class="GtkButton" id="buttonExit">
65
+ <property name="label" translatable="yes">Exit</property>
66
+ <property name="visible">True</property>
67
+ <property name="can_focus">True</property>
68
+ <property name="receives_default">True</property>
69
+ </object>
70
+ <packing>
71
+ <property name="expand">True</property>
72
+ <property name="fill">True</property>
73
+ <property name="position">2</property>
74
+ </packing>
75
+ </child>
76
+ </object>
77
+ <packing>
78
+ <property name="left_attach">1</property>
79
+ <property name="top_attach">0</property>
80
+ </packing>
81
+ </child>
82
+ <child>
83
+ <object class="GtkButtonBox">
84
+ <property name="visible">True</property>
85
+ <property name="can_focus">False</property>
86
+ <property name="margin_left">12</property>
87
+ <property name="spacing">9</property>
88
+ <property name="homogeneous">True</property>
89
+ <property name="layout_style">start</property>
90
+ <child>
91
+ <object class="GtkButton" id="buttonApplyEdits">
92
+ <property name="label" translatable="yes">Apply Edits</property>
93
+ <property name="visible">True</property>
94
+ <property name="can_focus">True</property>
95
+ <property name="receives_default">True</property>
96
+ </object>
97
+ <packing>
98
+ <property name="expand">True</property>
99
+ <property name="fill">True</property>
100
+ <property name="position">0</property>
101
+ </packing>
102
+ </child>
103
+ <child>
104
+ <object class="GtkButton" id="buttonDeleteScene">
105
+ <property name="label" translatable="yes">Delete Scene</property>
106
+ <property name="visible">True</property>
107
+ <property name="can_focus">True</property>
108
+ <property name="receives_default">True</property>
109
+ </object>
110
+ <packing>
111
+ <property name="expand">True</property>
112
+ <property name="fill">True</property>
113
+ <property name="position">1</property>
114
+ </packing>
115
+ </child>
116
+ <child>
117
+ <object class="GtkButton" id="buttonActivateScene">
118
+ <property name="label" translatable="yes">Activate Scene</property>
119
+ <property name="visible">True</property>
120
+ <property name="can_focus">True</property>
121
+ <property name="receives_default">True</property>
122
+ </object>
123
+ <packing>
124
+ <property name="expand">True</property>
125
+ <property name="fill">True</property>
126
+ <property name="position">2</property>
127
+ </packing>
128
+ </child>
129
+ </object>
130
+ <packing>
131
+ <property name="left_attach">0</property>
132
+ <property name="top_attach">0</property>
133
+ </packing>
134
+ </child>
135
+ </object>
136
+ <packing>
137
+ <property name="left_attach">0</property>
138
+ <property name="top_attach">3</property>
139
+ </packing>
140
+ </child>
141
+ <child>
142
+ <object class="GtkGrid">
143
+ <property name="visible">True</property>
144
+ <property name="can_focus">False</property>
145
+ <property name="margin_left">12</property>
146
+ <property name="margin_right">12</property>
147
+ <property name="hexpand">True</property>
148
+ <property name="vexpand">True</property>
149
+ <child>
150
+ <object class="GtkScrolledWindow" id="listviewSavantScenes">
151
+ <property name="visible">True</property>
152
+ <property name="can_focus">True</property>
153
+ <property name="margin_bottom">12</property>
154
+ <property name="hexpand">True</property>
155
+ <property name="vexpand">True</property>
156
+ <property name="hscrollbar_policy">always</property>
157
+ <property name="vscrollbar_policy">always</property>
158
+ <property name="shadow_type">in</property>
159
+ <property name="min_content_height">200</property>
160
+ <property name="max_content_height">800</property>
161
+ <child>
162
+ <placeholder/>
163
+ </child>
164
+ </object>
165
+ <packing>
166
+ <property name="left_attach">0</property>
167
+ <property name="top_attach">1</property>
168
+ </packing>
169
+ </child>
170
+ <child>
171
+ <object class="GtkGrid">
172
+ <property name="name">30</property>
173
+ <property name="visible">True</property>
174
+ <property name="can_focus">False</property>
175
+ <property name="margin_left">240</property>
176
+ <property name="margin_top">12</property>
177
+ <property name="margin_bottom">12</property>
178
+ <property name="column_spacing">3</property>
179
+ <child>
180
+ <object class="GtkEntry" id="savantURL">
181
+ <property name="visible">True</property>
182
+ <property name="can_focus">True</property>
183
+ <property name="has_focus">True</property>
184
+ <property name="is_focus">True</property>
185
+ <property name="events">GDK_KEY_PRESS_MASK | GDK_STRUCTURE_MASK</property>
186
+ <property name="halign">start</property>
187
+ <property name="activates_default">True</property>
188
+ <property name="width_chars">50</property>
189
+ </object>
190
+ <packing>
191
+ <property name="left_attach">1</property>
192
+ <property name="top_attach">0</property>
193
+ </packing>
194
+ </child>
195
+ <child>
196
+ <object class="GtkAlignment">
197
+ <property name="visible">True</property>
198
+ <property name="can_focus">False</property>
199
+ <child>
200
+ <object class="GtkLabel">
201
+ <property name="visible">True</property>
202
+ <property name="can_focus">False</property>
203
+ <property name="halign">end</property>
204
+ <property name="label" translatable="yes">Savant Host IP Address: </property>
205
+ <property name="justify">right</property>
206
+ </object>
207
+ </child>
208
+ </object>
209
+ <packing>
210
+ <property name="left_attach">0</property>
211
+ <property name="top_attach">0</property>
212
+ </packing>
213
+ </child>
214
+ <child>
215
+ <object class="GtkButton" id="buttonScanHost">
216
+ <property name="label" translatable="yes">Scan</property>
217
+ <property name="visible">True</property>
218
+ <property name="can_focus">True</property>
219
+ <property name="can_default">True</property>
220
+ <property name="has_default">True</property>
221
+ <property name="receives_default">True</property>
222
+ </object>
223
+ <packing>
224
+ <property name="left_attach">2</property>
225
+ <property name="top_attach">0</property>
226
+ </packing>
227
+ </child>
228
+ <child>
229
+ <object class="GtkAlignment">
230
+ <property name="visible">True</property>
231
+ <property name="can_focus">False</property>
232
+ <property name="halign">end</property>
233
+ <property name="margin_top">20</property>
234
+ <property name="hexpand">True</property>
235
+ <child>
236
+ <object class="GtkLabel" id="labelHostInfo">
237
+ <property name="visible">True</property>
238
+ <property name="can_focus">False</property>
239
+ <property name="margin_left">12</property>
240
+ <property name="justify">center</property>
241
+ </object>
242
+ </child>
243
+ </object>
244
+ <packing>
245
+ <property name="left_attach">3</property>
246
+ <property name="top_attach">0</property>
247
+ </packing>
248
+ </child>
249
+ </object>
250
+ <packing>
251
+ <property name="left_attach">0</property>
252
+ <property name="top_attach">0</property>
253
+ </packing>
254
+ </child>
255
+ <child>
256
+ <object class="GtkLabel">
257
+ <property name="visible">True</property>
258
+ <property name="can_focus">False</property>
259
+ <property name="halign">start</property>
260
+ <property name="margin_left">35</property>
261
+ <property name="margin_bottom">5</property>
262
+ <property name="label" translatable="yes">Check the box next to a scene and choose on option below.</property>
263
+ <property name="use_markup">True</property>
264
+ </object>
265
+ <packing>
266
+ <property name="left_attach">0</property>
267
+ <property name="top_attach">2</property>
268
+ </packing>
269
+ </child>
270
+ </object>
271
+ <packing>
272
+ <property name="left_attach">0</property>
273
+ <property name="top_attach">2</property>
274
+ </packing>
275
+ </child>
276
+ <child>
277
+ <object class="GtkLabel" id="labelDescription">
278
+ <property name="visible">True</property>
279
+ <property name="can_focus">False</property>
280
+ <property name="margin_top">12</property>
281
+ <property name="margin_bottom">12</property>
282
+ <property name="label" translatable="yes"> Savant scene manager copies the dashboard.sqlite file from the host to a temporary folder and lists all scenes from all users on that host.
283
+ You can backup and restore this database, as well as delete scenes or edit certain properties: Scene Name, user email, and whether or not the scene is actively scheduled.
284
+
285
+ If the host is running at least 8.3, you can also activate scenes.</property>
286
+ <property name="justify">center</property>
287
+ <property name="wrap">True</property>
288
+ <property name="wrap_mode">word-char</property>
289
+ <property name="width_chars">60</property>
290
+ <property name="max_width_chars">60</property>
291
+ </object>
292
+ <packing>
293
+ <property name="left_attach">0</property>
294
+ <property name="top_attach">1</property>
295
+ </packing>
296
+ </child>
297
+ </object>
298
+ </child>
299
+ </object>
300
+ <object class="GtkWindow" id="windowBackupRestore">
301
+ <property name="width_request">300</property>
302
+ <property name="height_request">300</property>
303
+ <property name="can_focus">False</property>
304
+ <property name="modal">True</property>
305
+ <property name="window_position">center-on-parent</property>
306
+ <property name="gravity">center</property>
307
+ <property name="transient_for">window1</property>
308
+ <property name="has_resize_grip">True</property>
309
+ <child>
310
+ <object class="GtkBox">
311
+ <property name="visible">True</property>
312
+ <property name="can_focus">False</property>
313
+ <property name="orientation">vertical</property>
314
+ <child>
315
+ <object class="GtkLabel">
316
+ <property name="visible">True</property>
317
+ <property name="can_focus">False</property>
318
+ <property name="margin_top">20</property>
319
+ <property name="margin_bottom">20</property>
320
+ <property name="label" translatable="yes">&lt;big&gt;&lt;b&gt;Backup and Restore&lt;/b&gt;&lt;/big&gt;</property>
321
+ <property name="use_markup">True</property>
322
+ </object>
323
+ <packing>
324
+ <property name="expand">False</property>
325
+ <property name="fill">True</property>
326
+ <property name="position">0</property>
327
+ </packing>
328
+ </child>
329
+ <child>
330
+ <object class="GtkLabel">
331
+ <property name="visible">True</property>
332
+ <property name="can_focus">False</property>
333
+ <property name="margin_left">20</property>
334
+ <property name="margin_right">20</property>
335
+ <property name="margin_bottom">12</property>
336
+ <property name="label" translatable="yes"> This will backup or restore the dashboard.sqlite file.
337
+
338
+ To backup the file, select a destination folder.
339
+
340
+ To restore the backed up file, select the folder that contains the file. </property>
341
+ <property name="wrap">True</property>
342
+ </object>
343
+ <packing>
344
+ <property name="expand">False</property>
345
+ <property name="fill">False</property>
346
+ <property name="position">1</property>
347
+ </packing>
348
+ </child>
349
+ <child>
350
+ <object class="GtkScrolledWindow" id="scrolledwindow_BackupRestore">
351
+ <property name="width_request">300</property>
352
+ <property name="height_request">300</property>
353
+ <property name="visible">True</property>
354
+ <property name="can_focus">True</property>
355
+ <property name="margin_left">20</property>
356
+ <property name="margin_right">20</property>
357
+ <property name="shadow_type">in</property>
358
+ <property name="min_content_width">300</property>
359
+ <property name="min_content_height">300</property>
360
+ <property name="max_content_width">300</property>
361
+ <property name="max_content_height">300</property>
362
+ <child>
363
+ <placeholder/>
364
+ </child>
365
+ </object>
366
+ <packing>
367
+ <property name="expand">False</property>
368
+ <property name="fill">False</property>
369
+ <property name="position">2</property>
370
+ </packing>
371
+ </child>
372
+ <child>
373
+ <object class="GtkButtonBox">
374
+ <property name="visible">True</property>
375
+ <property name="can_focus">False</property>
376
+ <property name="margin_top">20</property>
377
+ <property name="margin_bottom">12</property>
378
+ <property name="layout_style">spread</property>
379
+ <child>
380
+ <object class="GtkButton" id="buttonBackup">
381
+ <property name="label" translatable="yes">Backup</property>
382
+ <property name="visible">True</property>
383
+ <property name="can_focus">True</property>
384
+ <property name="receives_default">True</property>
385
+ </object>
386
+ <packing>
387
+ <property name="expand">True</property>
388
+ <property name="fill">True</property>
389
+ <property name="position">0</property>
390
+ </packing>
391
+ </child>
392
+ <child>
393
+ <object class="GtkButton" id="buttonRestore">
394
+ <property name="label" translatable="yes">Restore</property>
395
+ <property name="visible">True</property>
396
+ <property name="can_focus">True</property>
397
+ <property name="receives_default">True</property>
398
+ </object>
399
+ <packing>
400
+ <property name="expand">True</property>
401
+ <property name="fill">True</property>
402
+ <property name="position">1</property>
403
+ </packing>
404
+ </child>
405
+ <child>
406
+ <object class="GtkButton" id="buttonBackupRestoreCancel">
407
+ <property name="label" translatable="yes">Cancel</property>
408
+ <property name="visible">True</property>
409
+ <property name="can_focus">True</property>
410
+ <property name="receives_default">True</property>
411
+ </object>
412
+ <packing>
413
+ <property name="expand">True</property>
414
+ <property name="fill">True</property>
415
+ <property name="position">2</property>
416
+ </packing>
417
+ </child>
418
+ </object>
419
+ <packing>
420
+ <property name="expand">True</property>
421
+ <property name="fill">True</property>
422
+ <property name="pack_type">end</property>
423
+ <property name="position">3</property>
424
+ </packing>
425
+ </child>
426
+ </object>
427
+ </child>
428
+ </object>
429
+ </interface>
metadata ADDED
@@ -0,0 +1,147 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: savant-scenes
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Corey Miller
8
+ autorequire:
9
+ bindir:
10
+ - bin
11
+ cert_chain: []
12
+ date: 2017-04-28 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: sqlite3
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.3'
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.3.13
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ requirements:
28
+ - - "~>"
29
+ - !ruby/object:Gem::Version
30
+ version: '1.3'
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.3.13
34
+ - !ruby/object:Gem::Dependency
35
+ name: net-scp
36
+ requirement: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.2'
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 1.2.1
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - "~>"
49
+ - !ruby/object:Gem::Version
50
+ version: '1.2'
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 1.2.1
54
+ - !ruby/object:Gem::Dependency
55
+ name: ipaddress
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '0.8'
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 0.8.3
64
+ type: :runtime
65
+ prerelease: false
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - "~>"
69
+ - !ruby/object:Gem::Version
70
+ version: '0.8'
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: 0.8.3
74
+ - !ruby/object:Gem::Dependency
75
+ name: visualruby
76
+ requirement: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: '3.0'
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: 3.0.23
84
+ type: :runtime
85
+ prerelease: false
86
+ version_requirements: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '3.0'
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: 3.0.23
94
+ - !ruby/object:Gem::Dependency
95
+ name: require_all
96
+ requirement: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - "~>"
99
+ - !ruby/object:Gem::Version
100
+ version: '1.2'
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 1.2.0
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.2'
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: 1.2.0
114
+ description: Savant Scene Management
115
+ email: cmiller@premieresystems.com
116
+ executables:
117
+ - scenes
118
+ extensions: []
119
+ extra_rdoc_files: []
120
+ files:
121
+ - bin/scenes
122
+ - bin/src/SceneManager.rb
123
+ - bin/src/glade/SceneManager.glade
124
+ homepage: http://www.yoursite.org/
125
+ licenses: []
126
+ metadata: {}
127
+ post_install_message:
128
+ rdoc_options: []
129
+ require_paths:
130
+ - lib
131
+ required_ruby_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: '2.0'
136
+ required_rubygems_version: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ requirements: []
142
+ rubyforge_project: nowarning
143
+ rubygems_version: 2.4.8
144
+ signing_key:
145
+ specification_version: 4
146
+ summary: Savant Scene Manager
147
+ test_files: []