Piggy 0.4.2.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|