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.
- data/CHANGES.txt +91 -0
- data/INSTALL.txt +77 -0
- data/LICENCE.txt +339 -0
- data/README.txt +27 -0
- data/UNINSTALL.txt +24 -0
- data/bin/directory_diff +6 -0
- data/bin/ftp_browser +6 -0
- data/bin/piggy +6 -0
- data/lib/directory_diff.rb +35 -0
- data/lib/ftp_browser.rb +33 -0
- data/lib/icons/auto-select-for-del.ico +0 -0
- data/lib/icons/auto-select-right.ico +0 -0
- data/lib/icons/auto-upload-right.ico +0 -0
- data/lib/icons/back.ico +0 -0
- data/lib/icons/checked.ico +0 -0
- data/lib/icons/copy.png +0 -0
- data/lib/icons/cut.png +0 -0
- data/lib/icons/dir.ico +0 -0
- data/lib/icons/dirup.ico +0 -0
- data/lib/icons/file.ico +0 -0
- data/lib/icons/fileopen.png +0 -0
- data/lib/icons/filesave.ico +0 -0
- data/lib/icons/gallery.ico +0 -0
- data/lib/icons/generate.ico +0 -0
- data/lib/icons/minus.png +0 -0
- data/lib/icons/move-right-dir.ico +0 -0
- data/lib/icons/move-right-file.ico +0 -0
- data/lib/icons/newer-file.ico +0 -0
- data/lib/icons/next-image.ico +0 -0
- data/lib/icons/paste.png +0 -0
- data/lib/icons/plus.png +0 -0
- data/lib/icons/preview.png +0 -0
- data/lib/icons/previous-image.ico +0 -0
- data/lib/icons/reload.ico +0 -0
- data/lib/icons/remove-selected.ico +0 -0
- data/lib/icons/rotate.ico +0 -0
- data/lib/icons/slides.ico +0 -0
- data/lib/icons/stop-slides.ico +0 -0
- data/lib/icons/unchecked-dir.ico +0 -0
- data/lib/icons/unchecked.ico +0 -0
- data/lib/icons/upload-selected.ico +0 -0
- data/lib/icons/upload.ico +0 -0
- data/lib/piggy-core/alive_check.rb +44 -0
- data/lib/piggy-core/debug.rb +21 -0
- data/lib/piggy-core/encoding.rb +11 -0
- data/lib/piggy-core/environment.rb +66 -0
- data/lib/piggy-core/exifr_adapter.rb +85 -0
- data/lib/piggy-core/file_info.rb +218 -0
- data/lib/piggy-core/ftp_adapter.rb +106 -0
- data/lib/piggy-core/htmlgen.rb +242 -0
- data/lib/piggy-core/nconvert_thumbsgen.rb +73 -0
- data/lib/piggy-core/options.rb +116 -0
- data/lib/piggy-core/options_persistence.rb +54 -0
- data/lib/piggy-core/progress.rb +48 -0
- data/lib/piggy-core/rmagick_thumbnail_page_generator.rb +30 -0
- data/lib/piggy-core/thumbnail_generator.rb +79 -0
- data/lib/piggy-core/thumbnail_page_generator.rb +542 -0
- data/lib/piggy-core/upload_info.rb +41 -0
- data/lib/piggy-core/version.rb +18 -0
- data/lib/piggy-core/winshell.rb +240 -0
- data/lib/piggy-gui/directory_diff_widget.rb +398 -0
- data/lib/piggy-gui/filtered_file_list.rb +243 -0
- data/lib/piggy-gui/fox_thumbsgen.rb +18 -0
- data/lib/piggy-gui/ftp_browser_widget.rb +395 -0
- data/lib/piggy-gui/html_generation_dialog.rb +157 -0
- data/lib/piggy-gui/image_processor.rb +140 -0
- data/lib/piggy-gui/multiimagecanvas.rb +163 -0
- data/lib/piggy-gui/options_dialog.rb +85 -0
- data/lib/piggy-gui/piggy_image_browser.rb +776 -0
- data/lib/piggy-gui/pipe_log.rb +67 -0
- data/lib/piggy-gui/progress_with_dialog.rb +51 -0
- data/lib/piggy-gui/require-fox.rb +87 -0
- data/lib/piggy.rb +35 -0
- data/lib/templates/fuss.htm +10 -0
- data/lib/templates/kopf.htm +13 -0
- data/lib/templates/navigation.htm +11 -0
- data/lib/templates/slideshow.htm +129 -0
- data/lib/templates/slideshow.js +691 -0
- data/lib/templates/styles/basic/style.css +27 -0
- data/lib/templates/styles/black/style.css +64 -0
- data/lib/templates/styles/roundedbox/roundedbox_lo.gif +0 -0
- data/lib/templates/styles/roundedbox/roundedbox_lu.gif +0 -0
- data/lib/templates/styles/roundedbox/roundedbox_ro.gif +0 -0
- data/lib/templates/styles/roundedbox/roundedbox_ru.gif +0 -0
- data/lib/templates/styles/roundedbox/style.css +70 -0
- data/lib/templates/styles/shadow/lo.gif +0 -0
- data/lib/templates/styles/shadow/lu.gif +0 -0
- data/lib/templates/styles/shadow/ro.gif +0 -0
- data/lib/templates/styles/shadow/ru.gif +0 -0
- data/lib/templates/styles/shadow/style.css +63 -0
- data/test/file_info_test.rb +117 -0
- data/test.rb +8 -0
- data/web/IMAGE_PROCESSING.txt +53 -0
- data/web/INSTALL.txt +74 -0
- data/web/extern.gif +0 -0
- data/web/ftp-browser.png +0 -0
- data/web/index-de.html +60 -0
- data/web/index.html +57 -0
- data/web/piggy.png +0 -0
- data/web/style.css +14 -0
- 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
|
+
|