Piggy 0.4.2.2

Sign up to get free protection for your applications and to get access to all the features.
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,240 @@
1
+ #!/usr/bin/ruby
2
+ ## $Id: winshell.rb 176 2007-11-21 21:35:51Z Sascha $
3
+
4
+ require 'singleton'
5
+
6
+ # Windows oriented but platform independent file system abstraction.
7
+ class ShellInterface
8
+ def initialize
9
+ @specialFolderIds = {
10
+ "ALTSTARTUP" => 0x1d,
11
+ "APPDATA" => 0x1a,
12
+ "BITBUCKET" => 0xa,
13
+ "COMMONALTSTARTUP" => 0x1e,
14
+ "COMMONAPPDATA" => 0x23,
15
+ "COMMONDESKTOPDIR" => 0x19,
16
+ "COMMONFAVORITES" => 0x1f,
17
+ "COMMONPROGRAMS" => 0x17,
18
+ "COMMONSTARTMENU" => 0x16,
19
+ "COMMONSTARTUP" => 0x18,
20
+ "CONTROLS" => 0x3,
21
+ "COOKIES" => 0x21,
22
+ "DESKTOP" => 0x0,
23
+ "DESKTOPDIRECTORY" => 0x10,
24
+ "DRIVES" => 0x11,
25
+ "FAVORITES" => 0x6,
26
+ "FONTS" => 0x14,
27
+ "HISTORY" => 0x22,
28
+ "INTERNETCACHE" => 0x20,
29
+ "LOCALAPPDATA" => 0x1c,
30
+ "MYPICTURES" => 0x27,
31
+ "NETHOOD" => 0x13,
32
+ "NETWORK" => 0x12,
33
+ "PERSONAL" => 0x5,
34
+ "PRINTERS" => 0x4,
35
+ "PRINTHOOD" => 0x1b,
36
+ "PROFILE" => 0x28,
37
+ "PROGRAMFILES" => 0x26,
38
+ "PROGRAMS" => 0x2,
39
+ "RECENT" => 0x8,
40
+ "SENDTO" => 0x9,
41
+ "STARTMENU" => 0xb,
42
+ "STARTUP" => 0x7,
43
+ "SYSTEM" => 0x25,
44
+ "TEMPLATES" => 0x15,
45
+ "WINDOWS" => 0x24
46
+ }
47
+ end
48
+
49
+ # try to provide a platform independent default
50
+ def pathForSpecialFolder(name)
51
+ home = ENV['HOME']
52
+ home = ENV['HOMEPATH'] unless home
53
+ home = '/' unless home
54
+ return home
55
+ end
56
+
57
+ def tmpPath
58
+ tmp = ENV['TEMP']
59
+ tmp = ENV['TMP'] unless tmp
60
+ tmp = '/' unless tmp
61
+ return tmp
62
+ end
63
+
64
+ # platform dependent path (no better default possible)
65
+ def osPath(pathString)
66
+ return winPath(pathString)
67
+ end
68
+
69
+ # for use in commandline execution
70
+ def escape(pathString)
71
+ return pathString
72
+ end
73
+
74
+ # old name, use osPath instead
75
+ def winPath(pathString)
76
+ return pathString
77
+ end
78
+
79
+ # Get a path string usable by common ruby classes such as Dir and File.
80
+ # Default: convert '\' to '/' on all systems, even on Unix
81
+ def rubyPath(pathString)
82
+ return pathString.gsub(/\\/, separator)
83
+ end
84
+
85
+ def pictureDirectory
86
+ return pathForSpecialFolder("MYPICTURES")
87
+ end
88
+
89
+ def desktopDirectory
90
+ return pathForSpecialFolder("DESKTOPDIRECTORY")
91
+ end
92
+
93
+ def specialFolderListing
94
+ @specialFolderIds.keys.sort.each do |aFolder|
95
+ printf "#{aFolder}: "
96
+ puts "#{pathForSpecialFolder aFolder}"
97
+ end
98
+ end
99
+
100
+ # Get the path separator used by common ruby classes such as Dir and File.
101
+ def separator
102
+ return File::SEPARATOR
103
+ end
104
+
105
+ def removePath(filenameWithPath)
106
+ return rubyPath(filenameWithPath).split(separator)[-1]
107
+ end
108
+
109
+ # Is filename a Windows shortcut? - Default: no file is a shortcut
110
+ def link?(filename)
111
+ return false
112
+ end
113
+
114
+ # Has filename the Extension ext (e. g. ".jpg")
115
+ def hasExtension?(filename, ext)
116
+ raise ArgumentError, "Extension missing" if ext.empty?
117
+ pExt = (ext[0] == '.'[0] ? ext : '.' + ext).downcase
118
+ dcFilename = filename.downcase
119
+ return File.basename(dcFilename, pExt) != File.basename(dcFilename)
120
+ end
121
+ end
122
+
123
+
124
+ # Default access to file system abstraction.
125
+ # A platform dependent singleton will be instantiated.
126
+ class WinShell < ShellInterface
127
+ include Singleton
128
+ end
129
+
130
+ if RUBY_PLATFORM =~ /win32/
131
+ require 'win32ole'
132
+
133
+ class WinShell < ShellInterface
134
+
135
+ def initialize
136
+ @shell = WIN32OLE.new('Shell.application')
137
+ super
138
+ end
139
+
140
+ def pathForSpecialFolder(name)
141
+ return desktopDirectory if name=="DESKTOP"
142
+ oleFolder = specialFolder(name)
143
+ return "" if !oleFolder
144
+ return pathForFolder(specialFolder(name))
145
+ end
146
+
147
+ # Is filename a Windows shortcut?
148
+ def link?(filename)
149
+ return hasExtension?(filename, '.lnk')
150
+ end
151
+
152
+ # Get a path string usable by Windows systems.
153
+ def winPath(pathString)
154
+ return pathString.gsub(separator, "\\")
155
+ end
156
+
157
+ # Get a path string usable by common ruby classes such as Dir and File.
158
+ def rubyPath(pathString)
159
+ return pathString.gsub(/\\/, separator)
160
+ end
161
+
162
+ # for use in commandline execution
163
+ def escape(pathString)
164
+ return "\"#{pathString}\""
165
+ end
166
+
167
+ #Get the path stored in the Windows shortcut filename. PRE: link?(filename)
168
+ def getLinkTarget(filename, pathString = Dir.getwd)
169
+ raise(ArgumentError, "Kein Link") if !link?(filename)
170
+ filenameOnly = removePath(filename) # avoid errors ignore performance
171
+ ext = '.' + filenameOnly.split('.')[-1]
172
+ linkdef = File.basename(filenameOnly, ext)
173
+ raise ArgumentError, "Linkname leer" if linkdef.empty?
174
+ item = getFolderItems(pathString).find { |fi|
175
+ linkdef == (fi.Name.to_s) }
176
+ return item ? rubyPath(item.GetLink.Path.to_s) : ''
177
+ end
178
+
179
+ def pathForFolder(folder)
180
+ current = folder.ParentFolder
181
+ path = folder.Title
182
+ while current do
183
+ title = current.Title
184
+ if title == "Desktop" # winXP, nicht win2000
185
+ current = specialFolder("DESKTOPDIRECTORY").ParentFolder
186
+ title = current.Title
187
+ end
188
+ if title =~ /(.):/
189
+ title.gsub!(/.*\((\w:)\)/, '\1')
190
+ return title + separator + path
191
+ end
192
+ path = title + separator + path
193
+ current = current.ParentFolder
194
+ end
195
+ return path
196
+ end
197
+
198
+ # private; public for better testing only
199
+
200
+ # My shell is the ole object "Shell" as described in the Windows SDK.
201
+ def shell
202
+ return @shell
203
+ end
204
+
205
+ def specialFolder(name)
206
+ id = @specialFolderIds[name]
207
+ return shell.NameSpace(id)
208
+ end
209
+
210
+ # Get Directory entries as ole-objects, not as strings!
211
+ def getFolderItems(directoryPathString)
212
+ folder = shell.NameSpace(winPath(directoryPathString))
213
+ raise "Folderermittlung fehlgeschlagen" if !folder
214
+ items = folder.items
215
+ return (0..items.Count-1).collect { |i| items.item(i) }
216
+ end
217
+ end
218
+ end
219
+ # Example
220
+
221
+ if $0 == __FILE__
222
+ def example
223
+ aShell = WinShell.instance
224
+ h = "Example 1: WinShell.new.specialFolderListing"
225
+ hLine = (1..h.size).collect { |c| '*'}
226
+ puts "#{hLine}\n#{h}\n#{hLine}"
227
+ aShell.specialFolderListing
228
+ h = "Example 2. Links on Desktop"
229
+ hLine = (1..h.size).collect { |c| '*'}
230
+ puts "#{hLine}\n#{h}\n#{hLine}"
231
+ desktopDir = aShell.desktopDirectory
232
+ links = Dir[desktopDir + '/*'].select { |p| aShell.link?(File.basename(p)) }
233
+ links.each do |l|
234
+ lName = File.basename l
235
+ puts "#{lName} => \"#{aShell.getLinkTarget lName, desktopDir}\""
236
+ end
237
+ end
238
+ example
239
+ end
240
+
@@ -0,0 +1,398 @@
1
+ #!/usr/bin/ruby
2
+ # $Id: directory_diff_widget.rb 190 2008-02-02 18:52:57Z Sascha $
3
+
4
+ require 'piggy-core/environment'
5
+ require 'piggy-core/options'
6
+ require 'piggy-core/file_info'
7
+ require 'piggy-gui/require-fox'
8
+ require 'piggy-gui/image_processor'
9
+
10
+ # DirectoryDiffWidget shows differences between two directories.
11
+ class DirectoryDiffMainWindow < Fox::FXMainWindow
12
+ include Fox
13
+ def initialize(app, options = PiggyOptions.new)
14
+ super(app, titleString, nil, nil, DECOR_ALL,
15
+ 0, 0, 200, 700, 0, 0)
16
+ @frame = FXVerticalFrame.new(self)
17
+ @frame.setLayoutHints(LAYOUT_FILL_X|LAYOUT_FILL_Y)
18
+ setMainWidget(options)
19
+ @browser.quitButton.connect(SEL_COMMAND, method(:onTerminate))
20
+ end
21
+
22
+ def titleString
23
+ "Piggy Directory Diff"
24
+ end
25
+
26
+ def setMainWidget(options)
27
+ @browser = DirectoryDiffWidget.new(@frame, options)
28
+ end
29
+
30
+ def create
31
+ resize(800, 600)
32
+ place(PIGGY_WINDOW_PLACEMENT)
33
+ super
34
+ end
35
+
36
+ def onTerminate(sender, sel, ptr)
37
+ @browser.prepareClosure
38
+ getApp.exit(0)
39
+ end
40
+ end
41
+
42
+ class DirectoryDiffWidget < Fox::FXScrollWindow
43
+ include Fox
44
+ Placement = PIGGY_WINDOW_PLACEMENT
45
+ MsgStyle = MBOX_OK|DECOR_TITLE|DECOR_CLOSE|PIGGY_WINDOW_PLACEMENT
46
+
47
+ attr_reader(:options, :quitButton)
48
+
49
+ def initialize(window, options = PiggyOptions.new)
50
+ super(window)
51
+ @options = options
52
+ @iconLoader = ImageProcessor.new(getApp)
53
+ loadIcons
54
+ initializeFrames
55
+ initializeControls
56
+ initializeLayout
57
+ setDefaults
58
+ connectEvents
59
+ @rightContents = DirectoryContents.new(rightPath)
60
+ @leftContents = DirectoryContents.new(leftPath)
61
+ @excludeFilters = ['~$', '#$', '^\.']
62
+ end
63
+
64
+ def loadIcons
65
+ @dirIcon = basicLoadIcon('dir.ico')
66
+ @fileIcon = basicLoadIcon('file.ico')
67
+ @dirupIcon = basicLoadIcon('dirup.ico')
68
+ @fileAbsentIcon = basicLoadIcon('unchecked.ico')
69
+ @dirAbsentIcon = basicLoadIcon('unchecked-dir.ico')
70
+ @newerFileIcon = basicLoadIcon('newer-file.ico')
71
+ end
72
+
73
+ def basicLoadIcon(filename)
74
+ fileWithPath = File.join(PIGGY_PATH, 'icons', filename)
75
+ @iconLoader.loadIcon(fileWithPath)
76
+ end
77
+
78
+ def spaceInto(frame)
79
+ space = FXHorizontalFrame.new(frame)
80
+ space.setLayoutHints(LAYOUT_FILL_X|LAYOUT_FILL_Y)
81
+ end
82
+
83
+ def hSepInto(frame)
84
+ sep = FXHorizontalSeparator.new(frame, SEPARATOR_GROOVE)
85
+ sep.setLayoutHints(LAYOUT_FILL_X|LAYOUT_FILL_Y)
86
+ end
87
+
88
+ def initializeFrames
89
+ @frame = FXVerticalFrame.new(self)
90
+ @fourSplitter = FX4Splitter.new(@frame, FOURSPLITTER_TRACKING)
91
+ @splitOL = FXVerticalFrame.new(@fourSplitter)
92
+ @splitOR = FXVerticalFrame.new(@fourSplitter)
93
+ @splitUL = FXVerticalFrame.new(@fourSplitter)
94
+ @splitUR = FXVerticalFrame.new(@fourSplitter)
95
+ @leftListPropFrame = FXMatrix.new(@splitOL, 2, MATRIX_BY_COLUMNS)
96
+ @rightListPropFrame = FXMatrix.new(@splitOR, 2, MATRIX_BY_COLUMNS)
97
+ @leftButtonsFrame = FXHorizontalFrame.new(@splitUL)
98
+ @rightButtonsFrame = FXHorizontalFrame.new(@splitUR)
99
+ @leftListFrame = FXHorizontalFrame.new(@splitUL)
100
+ @rightListFrame = FXHorizontalFrame.new(@splitUR)
101
+ @separator = FXHorizontalSeparator.new(@frame, SEPARATOR_GROOVE)
102
+ @buttonsFrame = FXHorizontalFrame.new(@frame)
103
+ end
104
+
105
+ def initializeControls
106
+ @labels = Array.new
107
+ initializeControlsOL
108
+ initializeControlsOR
109
+ initializeControlsUL
110
+ initializeControlsUR
111
+ initializeButtons
112
+ end
113
+
114
+ def initializeControlsOL
115
+ @labels.push(FXLabel.new(@leftListPropFrame,
116
+ "Dir:"))
117
+ @leftPathField = FXTextField.new(@leftListPropFrame, 32)
118
+ end
119
+
120
+ def initializeControlsOR
121
+ @labels.push(FXLabel.new(@rightListPropFrame, "Dir:"))
122
+ @rightPathField = FXTextField.new(@rightListPropFrame, 32)
123
+ end
124
+
125
+ def initializeControlsUL
126
+ @dirLeftUpButton = FXButton.new(@leftButtonsFrame,
127
+ "\tGo up to higher directory",
128
+ @dirupIcon)
129
+ @leftFileList = FXIconList.new(@leftListFrame)
130
+ @leftFileList.setListStyle(ICONLIST_DETAILED)
131
+ @leftFileList.appendHeader("Name", nil, 200)
132
+ @leftFileList.appendHeader("Date", nil, 200)
133
+ end
134
+
135
+ def initializeControlsUR
136
+ @dirRightUpButton = FXButton.new(@rightButtonsFrame,
137
+ "\tGo up to higher directory",
138
+ @dirupIcon)
139
+ @rightFileList = FXIconList.new(@rightListFrame)
140
+ @rightFileList.setListStyle(ICONLIST_DETAILED)
141
+ @rightFileList.appendHeader("Name", nil, 200)
142
+ @rightFileList.appendHeader("Date", nil, 200)
143
+ end
144
+
145
+ def initializeButtons
146
+ @quitButton = FXButton.new(@buttonsFrame, "&Quit")
147
+ end
148
+
149
+ def initializeLayout
150
+ @labels.each { |label| label.setLayoutHints LAYOUT_CENTER_Y }
151
+ [
152
+ self, @frame,
153
+ @fourSplitter,
154
+ # @leftListPropFrame, @rightListPropFrame,
155
+ # @splitUL, @splitUR,
156
+ # @leftButtonsFrame, @rightButtonsFrame,
157
+ @leftListFrame, @rightListFrame,
158
+ # @serverField, @userField, @passwordField, @leftPathField,
159
+ # @rightPathField,
160
+ @leftFileList, @rightFileList
161
+ ].each { |w| w.setLayoutHints(LAYOUT_FILL_X|LAYOUT_FILL_Y) }
162
+ [
163
+ @splitOL, @splitOR, @splitUL, @splitUR,
164
+ @leftButtonsFrame, @rightButtonsFrame,
165
+ @leftListFrame, @rightListFrame
166
+ ].each { |w| w.setFrameStyle(FRAME_NONE) }
167
+ @buttonsFrame.setLayoutHints(LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X)
168
+ @buttonsFrame.setPackingHints(PACK_UNIFORM_WIDTH)
169
+ @quitButton.setLayoutHints(LAYOUT_RIGHT)
170
+ end
171
+
172
+ def connectEvents
173
+ @rightPathField.connect(SEL_COMMAND) {
174
+ setRightPath(@rightPathField.getText)
175
+ updateRightList
176
+ updateStatusIcons
177
+ }
178
+ @leftPathField.connect(SEL_COMMAND) {
179
+ setLeftPath(@leftPathField.getText)
180
+ updateLeftList
181
+ updateStatusIcons
182
+ }
183
+ @dirLeftUpButton.connect(SEL_COMMAND, method(:onDirUpLeftList))
184
+ @dirRightUpButton.connect(SEL_COMMAND, method(:onDirUpRightList))
185
+
186
+ @leftFileList.connect(SEL_DOUBLECLICKED,
187
+ method(:onDoubleclickLeftFileList))
188
+ @rightFileList.connect(SEL_DOUBLECLICKED,
189
+ method(:onDoubleclickRightFileList))
190
+ @leftFileList.connect(SEL_RIGHTBUTTONRELEASE,
191
+ method(:onMenuLeftList))
192
+ @rightFileList.connect(SEL_RIGHTBUTTONRELEASE,
193
+ method(:onMenuRightList))
194
+ end
195
+
196
+ def setDefaults
197
+ @rightPathField.setText(@options.localDestinationPath)
198
+ @leftPathField.setText(@options.localDestinationPath)
199
+ end
200
+
201
+ # accessing
202
+
203
+ def rightPath
204
+ @options.localDestinationPath
205
+ end
206
+
207
+ def setRightPath(p)
208
+ @options.localDestinationPath = FilePath.internPath(p)
209
+ @rightPathField.setText(p) # fixme winpath
210
+ end
211
+
212
+ def leftPath
213
+ FilePath.internPath(@leftPathField.getText)
214
+ end
215
+
216
+ def setLeftPath(p)
217
+ @leftPathField.setText(p) # fixme winpath
218
+ end
219
+
220
+ def selectionInList(list)
221
+ selectedInd = (0..list.getNumItems-1).select { |i|
222
+ list.isItemSelected(i)
223
+ }
224
+ return selectedInd.collect { |i| itemFilename(list, i) }
225
+ end
226
+
227
+ def itemFilename(list, index)
228
+ txt = fox2Ruby(list.getItemText(index))
229
+ return txt.split(Regexp.compile("\t"))[0]
230
+ end
231
+
232
+ # update
233
+
234
+ def updateLeftList
235
+ @leftContents = updateLocalList(@leftFileList, leftPath)
236
+ end
237
+
238
+ def updateRightList
239
+ @rightContents = updateLocalList(@rightFileList, rightPath)
240
+ end
241
+
242
+ def updateLocalList(listWidget, newPath)
243
+ listWidget.clearItems
244
+ contents = DirectoryContents.new(newPath)
245
+ return contents unless newPath && File.directory?(newPath)
246
+ getApp.beginWaitCursor
247
+ begin
248
+ updateList(Dir.entries(newPath), listWidget, contents) do
249
+ |file, path|
250
+ info = FileInfo.new(file, path)
251
+ info.mtime = File.stat(info.nameWithPath).mtime
252
+ info.directory! if File.directory?(info.nameWithPath)
253
+ info
254
+ end
255
+ rescue StandardError => ex
256
+ error(ex.message)
257
+ end
258
+ getApp.endWaitCursor
259
+ return contents
260
+ end
261
+
262
+ def includeFile?(filename)
263
+ @excludeFilters.select { |pattern|
264
+ Regexp.compile(pattern) =~ filename
265
+ }.empty?
266
+ end
267
+
268
+ def updateList(dirEntries, listWidget, contents, &getInfoblock)
269
+ listWidget.clearItems
270
+ items = Hash.new
271
+ dirEntries.each do
272
+ |file|
273
+ if includeFile?(file)
274
+ info = getInfoblock.call(file, contents.path)
275
+ text = ruby2Fox("#{info.name}\t#{info.mtimeString}")
276
+ if info.directory?
277
+ items[file] = FXIconItem.new(text, nil, @dirIcon)
278
+ else
279
+ items[file] = FXIconItem.new(text, nil, @fileIcon)
280
+ end
281
+ contents.add(info)
282
+ end
283
+ end
284
+ contents.directories.each { |n| listWidget.appendItem(items[n]) }
285
+ contents.files.each { |n| listWidget.appendItem(items[n]) }
286
+ end
287
+
288
+ def updateStatusIconsFor(listWidget, myContents, otherContents)
289
+ (0..listWidget.getNumItems - 1).each do
290
+ |index|
291
+ file = itemFilename(listWidget, index)
292
+ myInfo = myContents[file]
293
+ otherInfo = otherContents[file]
294
+ icon = if myInfo.directory?
295
+ otherInfo ? @dirIcon : @dirAbsentIcon
296
+ else
297
+ if otherInfo
298
+ otherInfo.mtime < myInfo.mtime ? @newerFileIcon : @fileIcon
299
+ else
300
+ @fileAbsentIcon
301
+ end
302
+ end
303
+ listWidget.setItemMiniIcon(index, icon)
304
+ end
305
+ end
306
+
307
+ def updateStatusIconsLeft
308
+ updateStatusIconsFor(@leftFileList, @leftContents, @rightContents)
309
+ end
310
+
311
+ def updateStatusIconsRight
312
+ updateStatusIconsFor(@rightFileList, @rightContents, @leftContents)
313
+ end
314
+
315
+ def updateStatusIcons
316
+ updateStatusIconsLeft
317
+ updateStatusIconsRight
318
+ end
319
+
320
+ # messages
321
+
322
+ def error(msg, title = 'Error')
323
+ FXMessageBox::warning(self, MsgStyle, title, msg)
324
+ return false
325
+ end
326
+
327
+ # actions
328
+
329
+ # events
330
+
331
+ def onDirUpLeftList(sender, sel, ptr)
332
+ return false unless leftPath
333
+ suggestion = FilePath.oneDirUp(leftPath)
334
+ return false if leftPath == suggestion
335
+ setLeftPath(suggestion)
336
+ updateLeftList
337
+ updateStatusIcons
338
+ return true
339
+ end
340
+
341
+ def onDirUpRightList(sender, sel, ptr)
342
+ return false unless rightPath
343
+ suggestion = FilePath.oneDirUp(rightPath)
344
+ return false if rightPath == suggestion
345
+ setRightPath(suggestion)
346
+ updateRightList
347
+ updateStatusIcons
348
+ return true
349
+ end
350
+
351
+ def onDoubleclickLeftFileList(sender, sel, index)
352
+ fileOrFolder = @leftFileList.getItemText(index)
353
+ file = fileOrFolder.split(Regexp.compile("\t"))[0]
354
+ info = @leftContents[file]
355
+ return false unless info && info.directory?
356
+ fileWithPath = FilePath.join(leftPath, file)
357
+ setLeftPath(fileWithPath)
358
+ updateLeftList
359
+ updateStatusIcons
360
+ return true
361
+ end
362
+
363
+ def onDoubleclickRightFileList(sender, sel, index)
364
+ fileOrFolder = @rightFileList.getItemText(index)
365
+ file = fileOrFolder.split(Regexp.compile("\t"))[0]
366
+ info = @rightContents[file]
367
+ return false unless info && info.directory?
368
+ fileWithPath = FilePath.join(rightPath, file)
369
+ setRightPath(fileWithPath)
370
+ updateRightList
371
+ updateStatusIcons
372
+ return true
373
+ end
374
+
375
+ def onMenuLeftList(sender, sel, event)
376
+ end
377
+
378
+ def onMenuRightList(sender, sel, event)
379
+ end
380
+
381
+ # open/close
382
+
383
+ def inCreate
384
+ updateLeftList
385
+ updateRightList
386
+ updateStatusIcons
387
+ @fourSplitter.setVSplit(600)
388
+ end
389
+
390
+ def create
391
+ inCreate
392
+ super
393
+ end
394
+
395
+ def prepareClosure
396
+ end
397
+ end
398
+