Piggy 0.4.2.2

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.
Files changed (101) hide show
  1. data/CHANGES.txt +91 -0
  2. data/INSTALL.txt +77 -0
  3. data/LICENCE.txt +339 -0
  4. data/README.txt +27 -0
  5. data/UNINSTALL.txt +24 -0
  6. data/bin/directory_diff +6 -0
  7. data/bin/ftp_browser +6 -0
  8. data/bin/piggy +6 -0
  9. data/lib/directory_diff.rb +35 -0
  10. data/lib/ftp_browser.rb +33 -0
  11. data/lib/icons/auto-select-for-del.ico +0 -0
  12. data/lib/icons/auto-select-right.ico +0 -0
  13. data/lib/icons/auto-upload-right.ico +0 -0
  14. data/lib/icons/back.ico +0 -0
  15. data/lib/icons/checked.ico +0 -0
  16. data/lib/icons/copy.png +0 -0
  17. data/lib/icons/cut.png +0 -0
  18. data/lib/icons/dir.ico +0 -0
  19. data/lib/icons/dirup.ico +0 -0
  20. data/lib/icons/file.ico +0 -0
  21. data/lib/icons/fileopen.png +0 -0
  22. data/lib/icons/filesave.ico +0 -0
  23. data/lib/icons/gallery.ico +0 -0
  24. data/lib/icons/generate.ico +0 -0
  25. data/lib/icons/minus.png +0 -0
  26. data/lib/icons/move-right-dir.ico +0 -0
  27. data/lib/icons/move-right-file.ico +0 -0
  28. data/lib/icons/newer-file.ico +0 -0
  29. data/lib/icons/next-image.ico +0 -0
  30. data/lib/icons/paste.png +0 -0
  31. data/lib/icons/plus.png +0 -0
  32. data/lib/icons/preview.png +0 -0
  33. data/lib/icons/previous-image.ico +0 -0
  34. data/lib/icons/reload.ico +0 -0
  35. data/lib/icons/remove-selected.ico +0 -0
  36. data/lib/icons/rotate.ico +0 -0
  37. data/lib/icons/slides.ico +0 -0
  38. data/lib/icons/stop-slides.ico +0 -0
  39. data/lib/icons/unchecked-dir.ico +0 -0
  40. data/lib/icons/unchecked.ico +0 -0
  41. data/lib/icons/upload-selected.ico +0 -0
  42. data/lib/icons/upload.ico +0 -0
  43. data/lib/piggy-core/alive_check.rb +44 -0
  44. data/lib/piggy-core/debug.rb +21 -0
  45. data/lib/piggy-core/encoding.rb +11 -0
  46. data/lib/piggy-core/environment.rb +66 -0
  47. data/lib/piggy-core/exifr_adapter.rb +85 -0
  48. data/lib/piggy-core/file_info.rb +218 -0
  49. data/lib/piggy-core/ftp_adapter.rb +106 -0
  50. data/lib/piggy-core/htmlgen.rb +242 -0
  51. data/lib/piggy-core/nconvert_thumbsgen.rb +73 -0
  52. data/lib/piggy-core/options.rb +116 -0
  53. data/lib/piggy-core/options_persistence.rb +54 -0
  54. data/lib/piggy-core/progress.rb +48 -0
  55. data/lib/piggy-core/rmagick_thumbnail_page_generator.rb +30 -0
  56. data/lib/piggy-core/thumbnail_generator.rb +79 -0
  57. data/lib/piggy-core/thumbnail_page_generator.rb +542 -0
  58. data/lib/piggy-core/upload_info.rb +41 -0
  59. data/lib/piggy-core/version.rb +18 -0
  60. data/lib/piggy-core/winshell.rb +240 -0
  61. data/lib/piggy-gui/directory_diff_widget.rb +398 -0
  62. data/lib/piggy-gui/filtered_file_list.rb +243 -0
  63. data/lib/piggy-gui/fox_thumbsgen.rb +18 -0
  64. data/lib/piggy-gui/ftp_browser_widget.rb +395 -0
  65. data/lib/piggy-gui/html_generation_dialog.rb +157 -0
  66. data/lib/piggy-gui/image_processor.rb +140 -0
  67. data/lib/piggy-gui/multiimagecanvas.rb +163 -0
  68. data/lib/piggy-gui/options_dialog.rb +85 -0
  69. data/lib/piggy-gui/piggy_image_browser.rb +776 -0
  70. data/lib/piggy-gui/pipe_log.rb +67 -0
  71. data/lib/piggy-gui/progress_with_dialog.rb +51 -0
  72. data/lib/piggy-gui/require-fox.rb +87 -0
  73. data/lib/piggy.rb +35 -0
  74. data/lib/templates/fuss.htm +10 -0
  75. data/lib/templates/kopf.htm +13 -0
  76. data/lib/templates/navigation.htm +11 -0
  77. data/lib/templates/slideshow.htm +129 -0
  78. data/lib/templates/slideshow.js +691 -0
  79. data/lib/templates/styles/basic/style.css +27 -0
  80. data/lib/templates/styles/black/style.css +64 -0
  81. data/lib/templates/styles/roundedbox/roundedbox_lo.gif +0 -0
  82. data/lib/templates/styles/roundedbox/roundedbox_lu.gif +0 -0
  83. data/lib/templates/styles/roundedbox/roundedbox_ro.gif +0 -0
  84. data/lib/templates/styles/roundedbox/roundedbox_ru.gif +0 -0
  85. data/lib/templates/styles/roundedbox/style.css +70 -0
  86. data/lib/templates/styles/shadow/lo.gif +0 -0
  87. data/lib/templates/styles/shadow/lu.gif +0 -0
  88. data/lib/templates/styles/shadow/ro.gif +0 -0
  89. data/lib/templates/styles/shadow/ru.gif +0 -0
  90. data/lib/templates/styles/shadow/style.css +63 -0
  91. data/test/file_info_test.rb +117 -0
  92. data/test.rb +8 -0
  93. data/web/IMAGE_PROCESSING.txt +53 -0
  94. data/web/INSTALL.txt +74 -0
  95. data/web/extern.gif +0 -0
  96. data/web/ftp-browser.png +0 -0
  97. data/web/index-de.html +60 -0
  98. data/web/index.html +57 -0
  99. data/web/piggy.png +0 -0
  100. data/web/style.css +14 -0
  101. metadata +177 -0
@@ -0,0 +1,243 @@
1
+ require 'set'
2
+ require 'piggy-core/environment'
3
+ require 'piggy-core/winshell'
4
+ require 'piggy-gui/require-fox'
5
+
6
+ # Allows to choose from a predefined set of files in the list.
7
+ # The definition of choosable files may be given as a block.
8
+ # Chosen, unchosen and unchoosable files are rendered differently.
9
+ class FilteredFileList < Fox::FXFileList
10
+ include Fox
11
+ include Responder
12
+
13
+ attr_reader(:chosenFiles)
14
+ attr_writer(:choosable)
15
+
16
+ def initialize(parent)
17
+ super(parent, nil, 0, ICONLIST_MINI_ICONS|ICONLIST_AUTOSIZE)
18
+ @imageProcessor = ImageProcessor.new(getApp)
19
+ @chosenFiles = Set.new
20
+ @choosable = proc { |file| true }
21
+ @shell = WinShell.instance
22
+ initIcons
23
+ end
24
+
25
+ def initIcons
26
+ @checkedIcon = getIcon("checked.ico")
27
+ @uncheckedIcon = getIcon("unchecked.ico")
28
+ end
29
+
30
+ def getIcon(filename)
31
+ iconPath = File.join(PIGGY_PATH, 'icons', filename)
32
+ @imageProcessor.loadIcon(iconPath)
33
+ end
34
+
35
+ def getItemRubyFilename(index)
36
+ fox2Ruby(getItemFilename(index))
37
+ end
38
+
39
+ def getItemRubyPathname(index)
40
+ fox2Ruby(getItemPathname(index))
41
+ end
42
+
43
+ def replaceFileIcon(index, rubyfile, modus)
44
+ return nil if modus == nil
45
+ icon = (modus == 'add' ? @checkedIcon : @uncheckedIcon)
46
+ if FOXVERSION_GE_1_2
47
+ setItemMiniIcon(index, icon)
48
+ else
49
+ file = ruby2Fox(rubyfile)
50
+ replaceItem(index, file, icon, icon)
51
+ end
52
+ end
53
+
54
+ def chooseAllInFilelist
55
+ (0..getNumItems-1).each do
56
+ |i|
57
+ if(isItemFile(i) && supports(getItemRubyFilename(i)))
58
+ shortName = getItemRubyFilename(i)
59
+ longName = getItemRubyPathname(i)
60
+ @chosenFiles.add(longName)
61
+ replaceFileIcon(i, shortName, 'add')
62
+ end
63
+ end
64
+ end
65
+
66
+ def supports(filename)
67
+ return @choosable.call(filename)
68
+ end
69
+
70
+ def getSelectedImageFiles(fullPath = false, modus = nil)
71
+ selectedInd = (0..getNumItems-1).select do
72
+ |i|
73
+ isItemSelected(i) and
74
+ isItemFile(i) and
75
+ supports(getItemRubyFilename(i))
76
+ end
77
+ selectedFiles = selectedInd.collect do
78
+ |i|
79
+ shortName = getItemRubyFilename(i)
80
+ longName = getItemRubyPathname(i)
81
+ replaceFileIcon(i, shortName, modus)
82
+ fullPath ? longName : shortName
83
+ end
84
+ return selectedFiles
85
+ end
86
+
87
+ def addSelectedFiles
88
+ getSelectedImageFiles(true, 'add').each { |file|
89
+ @chosenFiles.add(file)
90
+ }
91
+ end
92
+
93
+ def removeSelectedFiles
94
+ getSelectedImageFiles(true, 'remove').each { |file|
95
+ @chosenFiles.delete(file)
96
+ }
97
+ end
98
+
99
+ def updateFileList
100
+ scan(true)
101
+ (0..getNumItems-1).each do
102
+ |i|
103
+ if(isItemFile(i))
104
+ shortName = getItemRubyFilename(i)
105
+ if(supports(shortName))
106
+ longName = getItemRubyPathname(i)
107
+ if(@chosenFiles.include?(longName))
108
+ replaceFileIcon(i, shortName, 'add')
109
+ else
110
+ replaceFileIcon(i, shortName, 'remove')
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+
117
+ def addIndex(i)
118
+ longName = getItemRubyPathname(i)
119
+ shortName = getItemRubyFilename(i)
120
+ @chosenFiles.add(longName)
121
+ replaceFileIcon(i, shortName, 'add')
122
+ end
123
+
124
+ def removeIndex(i)
125
+ longName = getItemRubyPathname(i)
126
+ shortName = getItemRubyFilename(i)
127
+ @chosenFiles.delete(longName)
128
+ replaceFileIcon(i, shortName, 'remove')
129
+ end
130
+
131
+ def chooseSavedInstead(original, saved)
132
+ originalIndex = getIndex(original)
133
+ savedIndex = getIndex(saved)
134
+ removeIndex(originalIndex) unless originalIndex < 0
135
+ unless savedIndex < 0
136
+ addIndex(savedIndex)
137
+ selectIndex(savedIndex)
138
+ end
139
+ end
140
+
141
+ def getIndex(path)
142
+ rubyPath = rubyPath(path)
143
+ (0..getNumItems-1).each do
144
+ |i|
145
+ if(isItemFile(i))
146
+ longName = getItemRubyPathname(i)
147
+ if(rubyPath(longName) == rubyPath)
148
+ return i
149
+ end
150
+ end
151
+ end
152
+ return -1
153
+ end
154
+
155
+ def rubyPath(path)
156
+ @shell.rubyPath(path)
157
+ end
158
+
159
+ def assumeSelected(path)
160
+ index = getIndex(path)
161
+ unless index < 0 || itemSelected?(index)
162
+ killSelection()
163
+ selectItem(index)
164
+ end
165
+ end
166
+
167
+ def chosenSequence
168
+ seq = Array.new
169
+ @chosenFiles.each { |file| seq.push(file) }
170
+ seq.sort! { |x, y| x <=> y }
171
+ end
172
+
173
+ def goToDirectory(dirname)
174
+ self.directory = ruby2Fox(rubyPath(dirname))
175
+ @chosenFiles = Set.new
176
+ end
177
+
178
+ def getCurrentDirectory
179
+ fox2Ruby(self.directory)
180
+ end
181
+
182
+ # Return index or -1
183
+ def selectNextChosen
184
+ block = proc { |i|
185
+ if(isItemFile(i) &&
186
+ @chosenFiles.include?(getItemRubyPathname(i)))
187
+ killSelection
188
+ makeItemVisible(i)
189
+ selectItem(i)
190
+ return i
191
+ end
192
+ }
193
+ startingPoint = lastSelectedIndex + 1
194
+ (startingPoint..getNumItems-1).each(&block)
195
+ (0..startingPoint-1).each(&block)
196
+ return -1
197
+ end
198
+
199
+ def selectPreviousChosen
200
+ max = getNumItems - 1
201
+ startingPoint = firstSelectedIndex
202
+ startingPoint = max+1 if(startingPoint < 0 || startingPoint > max)
203
+ (0..max).each do
204
+ |index|
205
+ i = (max - index + startingPoint) % (max + 1)
206
+ if(isItemFile(i) &&
207
+ @chosenFiles.include?(getItemRubyPathname(i)))
208
+ killSelection
209
+ makeItemVisible(i)
210
+ selectItem(i)
211
+ return i
212
+ end
213
+ end
214
+ return -1
215
+ end
216
+
217
+ def firstSelectedIndex
218
+ max = getNumItems-1
219
+ (0..max).each do
220
+ |i|
221
+ return i if(isItemSelected(i))
222
+ end
223
+ -1
224
+ end
225
+
226
+ def lastSelectedIndex
227
+ max = getNumItems-1
228
+ (0..max).each do
229
+ |i|
230
+ r = max - i
231
+ return r if(isItemSelected(r))
232
+ end
233
+ -1
234
+ end
235
+
236
+ def anyFilesChosen?
237
+ return !@chosenFiles.empty?
238
+ end
239
+
240
+ def numFilesChosen
241
+ return @chosenFiles.size
242
+ end
243
+ end
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/ruby
2
+ ## $Id: fox_thumbsgen.rb 181 2007-12-12 23:33:46Z Sascha $
3
+
4
+ require 'piggy-core/thumbnail_page_generator'
5
+ require 'piggy-core/thumbnail_generator'
6
+ require 'piggy-gui/image_processor'
7
+
8
+ class FoxThumbnailPageGenerator < ThumbnailPageGenerator
9
+
10
+ protected
11
+
12
+ def imageProcessing(progress)
13
+ imageProcessor = ImageProcessor.new(client.getApp)
14
+ @imageGenerator = ThumbnailGenerator.new(imageProcessor, @options)
15
+ @imageGenerator.setOutputDirectory(imageOutputPath)
16
+ @imageGenerator.generate(@inputFilenames, progress)
17
+ end
18
+ end
@@ -0,0 +1,395 @@
1
+ #!/usr/bin/ruby
2
+ # $Id: ftp_browser_widget.rb 192 2008-02-02 19:21:34Z Sascha $
3
+
4
+ # FtpBrowserWidget manages FTP transfer for Piggy.
5
+
6
+ require 'piggy-core/options'
7
+ require 'piggy-core/ftp_adapter'
8
+ require 'piggy-core/upload_info'
9
+ require 'piggy-gui/directory_diff_widget'
10
+
11
+ class FtpBrowserDialog < Fox::FXDialogBox
12
+ include Fox
13
+
14
+ def initialize(window, options = PiggyOptions.new)
15
+ super(window, "Piggy FTP Client", DECOR_ALL)
16
+ @frame = FXVerticalFrame.new(self)
17
+ @frame.setLayoutHints(LAYOUT_FILL_X|LAYOUT_FILL_Y)
18
+ @browser = FtpBrowserWidget.new(@frame, options)
19
+ connect(SEL_CLOSE, method(:onCmdClose))
20
+ @browser.quitButton.connect(SEL_COMMAND, method(:onQuitButton))
21
+ end
22
+
23
+ def options
24
+ @browser.options
25
+ end
26
+
27
+ def create
28
+ resize(800, 600)
29
+ place(PIGGY_WINDOW_PLACEMENT)
30
+ super
31
+ end
32
+
33
+ # Send whenever this window is about to close
34
+ def onCmdClose(sender, sel, ptr)
35
+ @browser.prepareClosure
36
+ return 0
37
+ end
38
+
39
+ def onQuitButton(sender, sel, ptr)
40
+ handle(sender, MKUINT(ID_ACCEPT, SEL_COMMAND), nil)
41
+ end
42
+ end
43
+
44
+ class FtpBrowserMainWindow < DirectoryDiffMainWindow
45
+ include Fox
46
+
47
+ def initialize(app, options = PiggyOptions.new)
48
+ super(app, options)
49
+ end
50
+
51
+ def titleString
52
+ "Piggy FTP Browser"
53
+ end
54
+
55
+ def setMainWidget(options)
56
+ @browser = FtpBrowserWidget.new(@frame, options)
57
+ end
58
+ end
59
+
60
+ class FtpBrowserWidget < DirectoryDiffWidget
61
+ include Fox
62
+
63
+ def initialize(window, options = PiggyOptions.new)
64
+ @ftpAdapter = FtpAdapter.new(options)
65
+ @connectionDataVerified = false
66
+ super(window, options)
67
+ end
68
+
69
+ def loadIcons
70
+ super
71
+ @reloadIcon = basicLoadIcon('reload.ico')
72
+ @autoSelectForDelIco = basicLoadIcon('auto-select-for-del.ico')
73
+ @removeSelectedIco = basicLoadIcon('remove-selected.ico')
74
+ @autoSelectRightIcon = basicLoadIcon('auto-select-right.ico')
75
+ @uploadIcon = basicLoadIcon('auto-upload-right.ico')
76
+ @moveRightDirIcon = basicLoadIcon('move-right-dir.ico')
77
+ @moveRightFileIcon = basicLoadIcon('move-right-file.ico')
78
+ end
79
+
80
+ def initializeControlsOL
81
+ @labels.push(FXLabel.new(@leftListPropFrame, "FTP server:"))
82
+ @serverField = FXTextField.new(@leftListPropFrame, 32)
83
+ @labels.push(FXLabel.new(@leftListPropFrame, "User:"))
84
+ @userField = FXTextField.new(@leftListPropFrame, 32)
85
+ @labels.push(FXLabel.new(@leftListPropFrame, "Password:"))
86
+ @passwordField = FXTextField.new(@leftListPropFrame, 32)
87
+ @passwordField.setTextStyle(TEXTFIELD_PASSWD)
88
+ @labels.push(FXLabel.new(@leftListPropFrame, "Destination path:"))
89
+ @leftPathField = FXTextField.new(@leftListPropFrame, 32)
90
+ end
91
+
92
+ def initializeControlsUL
93
+ @updateButton = FXButton.new(@leftButtonsFrame,
94
+ "\tUpdate list",
95
+ @reloadIcon)
96
+ super
97
+ @autoSelectForDelButton = FXButton.new(@leftButtonsFrame,
98
+ "\tChoose files automatically",
99
+ @autoSelectForDelIco)
100
+ @removeSelectedLeftButton = FXButton.new(@leftButtonsFrame,
101
+ "\tRemove selected files",
102
+ @removeSelectedIco)
103
+ end
104
+
105
+ def initializeControlsUR
106
+ super
107
+ @autoSelectRightButton = FXButton.new(@rightButtonsFrame,
108
+ "\tChoose files automatically",
109
+ @autoSelectRightIcon)
110
+ @uploadSelectedButton = FXButton.new(@rightButtonsFrame,
111
+ "\tUpload selected",
112
+ @uploadIcon)
113
+ end
114
+
115
+ def connectEvents
116
+ super
117
+ @serverField.connect(SEL_COMMAND) {
118
+ @options.ftpHost = @serverField.getText
119
+ }
120
+ @userField.connect(SEL_COMMAND) {
121
+ @options.ftpUser = @userField.getText
122
+ }
123
+ @updateButton.connect(SEL_COMMAND, method(:onCmdUpdate))
124
+ @autoSelectForDelButton.connect(SEL_COMMAND, method(:onCmdAutoSelectLeft))
125
+ @removeSelectedLeftButton.connect(SEL_COMMAND, method(:onCmdRemoveSelectedLeft))
126
+ @autoSelectRightButton.connect(SEL_COMMAND, method(:onCmdAutoSelectRight))
127
+ @uploadSelectedButton.connect(SEL_COMMAND, method(:onCmdUpload))
128
+ end
129
+
130
+ def setDefaults
131
+ @serverField.setText(@options.ftpHost)
132
+ @userField.setText(@options.ftpUser)
133
+ @rightPathField.setText(@options.localDestinationPath)
134
+ @leftPathField.setText(@options.remoteDestinationPath)
135
+ end
136
+
137
+ # accessing
138
+
139
+ def leftPath
140
+ @options.remoteDestinationPath
141
+ end
142
+
143
+ def setLeftPath(p)
144
+ @options.remoteDestinationPath = FilePath.internPath(p)
145
+ @leftPathField.setText(leftPath) #fixme winpath
146
+ end
147
+
148
+ def password
149
+ @passwordField.getText
150
+ end
151
+
152
+ def host
153
+ @serverField.getText
154
+ end
155
+
156
+ def user
157
+ @userField.getText
158
+ end
159
+
160
+ # update
161
+
162
+ def updateStatusIconsRight
163
+ (0..@rightFileList.getNumItems - 1).each do
164
+ |index|
165
+ file = itemFilename(@rightFileList, index)
166
+ myInfo = @rightContents[file]
167
+ otherInfo = @leftContents[file]
168
+ icon = if myInfo.directory?
169
+ otherInfo ? @dirIcon : @moveRightDirIcon
170
+ else
171
+ if otherInfo
172
+ otherInfo.mtime < myInfo.mtime ? @newerFileIcon : @fileIcon
173
+ else
174
+ @moveRightFileIcon
175
+ end
176
+ end
177
+ @rightFileList.setItemMiniIcon(index, icon)
178
+ end
179
+ end
180
+
181
+ def updateLeftList
182
+ updateFtpList if @connectionDataVerified
183
+ end
184
+
185
+ def ftpDo(&block) # don't chdir in block
186
+ getApp.beginWaitCursor
187
+ @leftFileList.clearItems
188
+ @leftContents = DirectoryContents.new(leftPath)
189
+ begin
190
+ @connectionDataVerified = false
191
+ @ftpAdapter.connect(host, user, password)
192
+ @connectionDataVerified = true
193
+ @ftpAdapter.chdir(leftPath)
194
+ block.call # <------ the call
195
+ updateList(@ftpAdapter.nlst, @leftFileList, @leftContents) do
196
+ |file, path|
197
+ @ftpAdapter.info(file, path)
198
+ end
199
+ rescue SocketError => ex
200
+ error(ex.message)
201
+ rescue Net::FTPError => ex
202
+ error(ex.message)
203
+ rescue StandardError => ex
204
+ error(ex.message)
205
+ rescue Timeout::Error => ex
206
+ error("Timeout - operation took longer than expected. \nCheck network connection and try again.")
207
+ ensure
208
+ @ftpAdapter.close
209
+ end
210
+ getApp.endWaitCursor
211
+ end
212
+
213
+ def updateFtpList
214
+ ftpDo {} # every ftp action includes an update :-)
215
+ end
216
+
217
+ # actions
218
+
219
+ def autoSelectLeft
220
+ list = @leftFileList
221
+ list.killSelection
222
+ (0..list.getNumItems-1).each do
223
+ |index|
224
+ file = itemFilename(list, index)
225
+ myInfo = @leftContents[file]
226
+ otherInfo = @rightContents[file]
227
+ select = if myInfo.directory?
228
+ false
229
+ elsif otherInfo
230
+ false
231
+ else
232
+ true
233
+ end
234
+ list.selectItem(index) if select
235
+ end
236
+ end
237
+
238
+ def autoSelectRight
239
+ list = @rightFileList
240
+ list.killSelection
241
+ (0..list.getNumItems-1).each do
242
+ |index|
243
+ file = itemFilename(list, index)
244
+ myInfo = @rightContents[file]
245
+ otherInfo = @leftContents[file]
246
+ select = if myInfo.directory?
247
+ false
248
+ elsif otherInfo && otherInfo.directory?
249
+ false
250
+ elsif !otherInfo || otherInfo.mtime < myInfo.mtime
251
+ true
252
+ else
253
+ false
254
+ end
255
+ list.selectItem(index) if select
256
+ end
257
+ end
258
+
259
+ def ftpDeleteLeft(files)
260
+ ftpDo {
261
+ files.each { |file|
262
+ @ftpAdapter.delete(file)
263
+ }
264
+ }
265
+ updateStatusIcons
266
+ end
267
+
268
+ def ftpUploadRight(hash, totalSize)
269
+ ftpDo do
270
+ progressDialog = FXProgressDialog.new(self,
271
+ 'Transferring data',
272
+ 'Transferring data')
273
+ begin
274
+ progressDialog.setProgress(1)
275
+ progressDialog.setTotal(totalSize)
276
+ progressDialog.create
277
+ progressDialog.show
278
+ progressDialog.repaint
279
+ hash.keys.sort.each do
280
+ |file|
281
+ @ftpAdapter.upload(rightPath, file) { |data|
282
+ progressDialog.setMessage(ruby2Fox("Transferring #{File.basename(file)}"))
283
+ progressDialog.increment(data.size)
284
+ progressDialog.repaint
285
+ }
286
+ end
287
+ ensure
288
+ progressDialog.hide
289
+ end
290
+ end
291
+ updateStatusIcons
292
+ end
293
+
294
+ def askAndUploadSelection
295
+ sel = selectionInList(@rightFileList)
296
+ return false if sel.empty?
297
+ files = sel.collect { |e| FilePath.join(rightPath, e) }
298
+ uploadInfo = UploadInfo.new(files)
299
+ num = uploadInfo.numFiles
300
+ if(num < 1)
301
+ FXMessageBox.information(self, MBOX_OK, 'No files',
302
+ 'No files found in selected directories!')
303
+ return false
304
+ end
305
+ answer = FXMessageBox.question(self, MBOX_YES_NO, 'Really upload?',
306
+ "Upload #{num} fil#{num == 1 ? 'e' : 'es'}?")
307
+ ftpUploadRight(uploadInfo.bytesHash, uploadInfo.bytes) if answer == MBOX_CLICKED_YES
308
+ end
309
+
310
+ def askAndFtpDeleteSelection
311
+ sel = selectionInList(@leftFileList)
312
+ dirs = sel.select { |file|
313
+ @leftContents[file].directory?
314
+ }
315
+ return error("Sorry, can't remove directories, yet") unless dirs.empty?
316
+ return false if sel.empty?
317
+ num = sel.size
318
+ answer = FXMessageBox.question(self, MBOX_YES_NO, 'Really delete?',
319
+ "Delete #{num} fil#{num == 1 ? 'e' : 'es'}?")
320
+ ftpDeleteLeft(sel) if answer == MBOX_CLICKED_YES
321
+ end
322
+
323
+ # events
324
+
325
+ def onCmdUpdate(sender, sel, ptr)
326
+ updateFtpList
327
+ updateStatusIcons
328
+ end
329
+
330
+ def onCmdAutoSelectLeft(sender, sel, ptr)
331
+ autoSelectLeft
332
+ end
333
+
334
+ def onCmdRemoveSelectedLeft(sender, sel, ptr)
335
+ askAndFtpDeleteSelection
336
+ end
337
+
338
+ def onCmdAutoSelectRight(sender, sel, ptr)
339
+ autoSelectRight
340
+ end
341
+
342
+ def onCmdUpload(sender, sel, event)
343
+ askAndUploadSelection
344
+ end
345
+
346
+ def onMenuLeftList(sender, sel, event)
347
+ selection = selectionInList(@leftFileList)
348
+ pane = FXMenuPane.new(self)
349
+ # FXMenuSeparator.new(pane)
350
+ item = FXMenuCommand.new(pane, "&Remove selected")
351
+ if(selection.empty?)
352
+ item.disable
353
+ else
354
+ item.connect(SEL_COMMAND){ |sender, sel, event|
355
+ askAndFtpDeleteSelection
356
+ }
357
+ end
358
+ pane.create
359
+ pane.popup(nil, event.root_x, event.root_y)
360
+ getApp.runModalWhileShown(pane)
361
+ return 1
362
+ end
363
+
364
+ def onMenuRightList(sender, sel, event)
365
+ selection = selectionInList(@rightFileList)
366
+ pane = FXMenuPane.new(self)
367
+ item = FXMenuCommand.new(pane, "&Upload selected")
368
+ if(selection.empty?)
369
+ item.disable
370
+ else
371
+ item.connect(SEL_COMMAND){ |sender, sel, event|
372
+ askAndUploadSelection
373
+ }
374
+ end
375
+ # FXMenuSeparator.new(pane)
376
+ pane.create
377
+ pane.popup(nil, event.root_x, event.root_y)
378
+ getApp.runModalWhileShown(pane)
379
+ return 1
380
+ end
381
+
382
+ # open/close
383
+
384
+ def inCreate
385
+ updateRightList
386
+ updateStatusIcons
387
+ @fourSplitter.setVSplit(2450)
388
+ end
389
+
390
+ def prepareClosure
391
+ @ftpAdapter.close
392
+ super
393
+ end
394
+ end
395
+