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

Revision 1030, 9.3 kB (checked in by cho45, 6 years ago)

lang/ruby/Chemr/CHMDocument.rb:

http も内部表示するように
ローカルに保存しないでキーワードインデックスだけつけるとき便利かも

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