savant-scenes 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []