root/lang/ruby/Chemr/CHMDocument.rb @ 743

Revision 743, 8.4 kB (checked in by cho45, 6 years ago)

lang/ruby/Chemr/AppController.rb,
lang/ruby/Chemr/CHMDocument.rb,
lang/ruby/Chemr/Chemr.xcodeproj/cho45.mode1,
lang/ruby/Chemr/Chemr.xcodeproj/project.pbxproj,
lang/ruby/Chemr/Chemr.xcodeproj/cho45.pbxuser:

.chm バンドルのサポート (独自形式)

Line 
1#!rake ;#
2
3
4require "uri"
5class CHMWindowController < NSWindowController
6        ib_outlet :webview
7        ib_outlet :list
8        ib_outlet :tree
9        ib_outlet :drawer
10        ib_outlet :search
11
12        def windowDidLoad
13                @chm = self.document.chm
14                uri  = URI(self.document.fileURL.absoluteString)
15                browse @chm.home
16                @now = @index = @chm.index.to_a.sort_by {|k,v| k} # cache
17                @list.setDataSource(self)
18                @list.setDoubleAction("clicked_")
19                @list.setAction("clicked_")
20
21                @tree.setAction("treeclicked_")
22
23                @search.setDelegate(self)
24                @drawer.open
25        end
26
27        # OutlineView
28        #    * outlineView:child:ofItem:
29        #    * outlineView:isItemExpandable:
30        #    * outlineView:numberOfChildrenOfItem:
31        #    * outlineView:objectValueForTableColumn:byItem:
32        #    * outlineView:setObjectValue:forTableColumn:byItem:
33
34        def outlineView_child_ofItem(ov, index, item)
35                (item || @topics)[:children][index]
36        end
37
38        def outlineView_isItemExpandable(ov, item)
39                (item || @topics)[:children].length.nonzero?
40        end
41
42        def outlineView_numberOfChildrenOfItem(ov, item)
43                (item || @topics)[:children].length
44        end
45
46        def outlineView_objectValueForTableColumn_byItem(ov, column, item)
47                item[:name]
48        end
49
50        def treeclicked(sender)
51                path = sender.itemAtRow(sender.selectedRow)[:local]
52                log "Tree Clicked: #{path}"
53                browse path unless path.empty?
54        end
55
56
57        # Tableview
58        def numberOfRowsInTableView(table)
59                @now.length
60        end
61
62        def tableView_objectValueForTableColumn_row(table, column, row)
63                @now[row][0]
64        end
65
66        def tableView_setObjectValue_forTableColumn_row(table, value, column, row)
67        end
68
69        def tableView_willDisplayCell_forTableColumn_row(table, cell, column, row)
70        end
71
72        def textShouldBeginEditing(text)
73                true
74        end
75
76        def textShouldEndEditing(text)
77                true
78        end
79
80        def acceptsFirstResponder
81                true
82        end
83
84        # TabView
85        def tabView_willSelectTabViewItem(sender, item)
86                log item.label
87                if item.label == "Tree"
88                        # http://subtech.g.hatena.ne.jp/cho45/20071025#c1193355031
89                        #  > OutlineView は DataSource に、ノードの値が変わらない限り、
90                        #  > 同じ NSString を返すように期待してるようです。
91                        # NSDictionary で保持するように
92                        @topics = NSDictionary.dictionaryWithDictionary(@chm.topics)
93                        @tree.setDataSource(self)
94                end
95        end
96
97        # general
98
99        def controlTextDidChange(anot)
100                filtering @search.stringValue
101                @list.selectRowIndexes_byExtendingSelection(NSIndexSet.alloc.initWithIndex(0), false)
102        end
103
104        def controlTextDidEndEditing(anot)
105                log "end #{@now.first.inspect}"
106        end
107
108        def jumpToCurrent(sender)
109                clicked(sender)
110        end
111
112        def filtering(str)
113                str = str.to_s
114                if str =~ /[A-Z]/
115                        r = /^#{str}/
116                else
117                        r = /^#{str}/i
118                end
119                @now = @index.select {|k,v|
120                        k =~ r
121                }.sort_by {|k,v| k.length }
122                @list.reloadData
123        end
124
125        def clicked(sender)
126                if @now[@list.selectedRow]
127                        browse @now[@list.selectedRow][1].first
128                end
129        end
130
131        def browse(path)
132                if path
133                        path = "/#{path}" unless path[0] == ?/
134                        h = @webview.stringByEvaluatingJavaScriptFromString("location.pathname+location.hash")
135                        unless path == h
136                                r = NSURLRequest.requestWithURL CHMInternalURLProtocol.url_for(@chm, path)
137                                log r
138                                @webview.mainFrame.loadRequest r
139                        end
140                end
141        end
142
143        def completion(sender)
144                return if @search.stringValue.empty?
145                return if @now.empty?
146                common = ""
147                keys = @now.map{|k,v| k.split(//)}
148                if @search.stringValue.to_s =~ /[A-Z]/
149                        keys[0].zip(*keys[1..-1]) do |a|
150                                m = a.first
151                                if a.all? {|v| m == v}
152                                        common << m
153                                else
154                                        break
155                                end
156                        end
157                else
158                        keys[0].zip(*keys[1..-1]) do |a|
159                                m = a.first.downcase
160                                if a.all? {|v| v && (m == v.downcase)}
161                                        common << m
162                                else
163                                        break
164                                end
165                        end
166                end
167                if common.length > @search.stringValue.length
168                        @search.stringValue = common
169                end
170        end
171
172        # from menu
173        def searchActivate(sender)
174                log "activate"
175                @search.window.makeFirstResponder(@search)
176        end
177
178        def nextCandidate(sender)
179                if @list.selectedRow <= @now.size
180                        @list.selectRowIndexes_byExtendingSelection(NSIndexSet.alloc.initWithIndex(@list.selectedRow+1), false)
181                        @list.scrollRowToVisible(@list.selectedRow)
182                        clicked(nil)
183                end
184        end
185
186        def prevCandidate(sender)
187                if @list.selectedRow > 0
188                        @list.selectRowIndexes_byExtendingSelection(NSIndexSet.alloc.initWithIndex(@list.selectedRow-1), false)
189                        @list.scrollRowToVisible(@list.selectedRow)
190                        clicked(nil)
191                end
192        end
193
194        def jumpToHome(sender)
195                browse @chm.home
196        end
197
198        def performFindPanelAction(sender)
199                log "performFindPanelAction"
200                # @webview.performFindPanelAction(sender) # なぜかうごかない
201                text = @search.stringValue
202                @webview.objc_send(
203                        :searchFor, text,
204                        :direction, true,
205                        :caseSensitive, false,
206                        :wrap, false
207                )
208        end
209
210        # from MySearchWindow
211
212        def process_keybinds(e)
213                if NSInputManager.currentInputManager
214                        return false unless NSInputManager.currentInputManager.markedRange.empty?
215                end
216                key = key_string(e)
217                log "keyDown (#{e.characters}:#{e.charactersIgnoringModifiers}) -> '#{key}'"
218                keybinds = {
219                        "C-j" => self.method(:nextCandidate),
220                        "C-n" => self.method(:nextCandidate),
221                        "C-k" => self.method(:prevCandidate),
222                        "C-p" => self.method(:prevCandidate),
223                        "\r"  => self.method(:jumpToCurrent),
224                        "\t"  => self.method(:completion),
225                        " "   => Proc.new {|s|
226                                @webview.stringByEvaluatingJavaScriptFromString <<-JS
227                                        window.scrollBy(0, 200);
228                                JS
229                        },
230                        "S- " => Proc.new {|s|
231                                @webview.stringByEvaluatingJavaScriptFromString <<-JS
232                                        window.scrollBy(0, -200);
233                                JS
234                        },
235                        "C-\r" => Proc.new {|s|
236                                @now = @chm.search(@search.stringValue).map {|title,url|
237                                        [title, [url]]
238                                }
239                                @list.reloadData
240                        },
241                        "C-u" => Proc.new {|s|
242                                @search.stringValue = ""
243                        },
244                        "G-[" => Proc.new {|s|
245                                @webview.goBack
246                        },
247                        "G-]" => Proc.new {|s|
248                                @webview.goForward
249                        },
250                        "G-=" => Proc.new {|s|
251                                @webview.makeTextLarger(self)
252                        },
253                        "G--" => Proc.new {|s|
254                                @webview.makeTextSmaller(self)
255                        },
256                }
257                (1..9).each do |i|
258                        keybinds["G-#{i}"] = Proc.new {|s|
259                                dc = NSDocumentController.sharedDocumentController
260                                if dc.documents[i-1]
261                                        log(dc.documents[i-1].windowControllers)
262                                        dc.documents[i-1].windowControllers.first.showWindow(self)
263                                end
264                        }
265                end
266                if keybinds.key?(key)
267                        keybinds[key].call(self)
268                        true
269                else
270                        false
271                end
272        end
273
274        def key_string(e)
275                key = ""
276                m = e.modifierFlags
277                key << "S-" if m & NSShiftKeyMask > 0
278                key << "C-" if m & NSControlKeyMask > 0
279                key << "M-" if m & NSAlternateKeyMask > 0
280                key << "G-" if m & NSCommandKeyMask > 0 # TODO
281                key << e.charactersIgnoringModifiers.to_s
282                key
283        end
284
285        # webview policyDelegate
286        def webView_decidePolicyForNavigationAction_request_frame_decisionListener(
287                sender,
288                actionInformation,
289                request,
290                frame,
291                listener
292        )
293
294                if CHMInternalURLProtocol.canHandleURL(request.URL)
295                        listener.use
296                else
297                        NSWorkspace.sharedWorkspace.openURL(request.URL)
298                        listener.ignore
299                end
300        end
301
302        def webView_decidePolicyForNewWindowAction_request_newFrameName_decisionListener(
303                sender,
304                actionInformation,
305                request,
306                frameName,
307                listener
308        )
309                if CHMInternalURLProtocol.canHandleURL(request.URL)
310                        listener.use
311                else
312                        NSWorkspace.sharedWorkspace.openURL(request.URL)
313                        listener.ignore
314                end
315        end
316
317        # webview loading delegate
318        def webView_resource_didFinishLoadingFromDataSource(sender, id, datasource)
319#               log "loaded"
320        end
321
322end
323
324class CHMDocument < NSDocument
325        attr_reader :chm
326
327        #- (void)makeWindowControllers
328        def makeWindowControllers
329                c = CHMWindowController.alloc.initWithWindowNibName("CHMDocument")
330                self.addWindowController(c)
331        end
332
333        #- (BOOL)readFromURL:(NSURL *)inAbsoluteURL ofType:(NSString *)inTypeName error:(NSError **)outError
334        def readFromURL_ofType_error(url, type, error)
335                path = Pathname.new(url.path.to_s)
336                if path.directory?
337                        @chm = CHMBundle.new(path)
338                else
339                        @chm = Chmlib::Chm.new(path.to_s)
340                end
341                true
342        end
343
344        #- (BOOL)writeToURL:(NSURL *)inAbsoluteURL ofType:(NSString *)inTypeName error:(NSError **)outError
345        def writeToURL_ofType_error(url, type, error)
346                false
347        end
348
349        #- (void)windowControllerDidLoadWindowNib:(NSWindowController *)windowController
350        def windowControllerDidLoadWindowNib(cont)
351                log "wCDLWN", cont
352        end
353
354#       def dataRepresentationOfType(aType)
355#       end
356#
357#       def loadDataRepresentation_ofType(data, aType)
358#       end
359
360        def displayName
361                dc = NSDocumentController.sharedDocumentController
362                i = dc.documents.index(self) + 1
363                cmd = [8984].pack("U")
364                "#{cmd}#{i}| #{@chm.title}"
365        end
366
367        def windowControllerWillLoadNib(cont)
368                log cont
369        end
370
371        def winwowNibName
372                "CHMDocument"
373        end
374end
375
376class MySearchWindow < NSWindow
377
378        def sendEvent(e)
379                if e.oc_type == NSKeyDown
380                        return if delegate.process_keybinds(e)
381                end
382                super_sendEvent(e)
383        end
384
385end
386
387
Note: See TracBrowser for help on using the browser.