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

Revision 745, 8.8 kB (checked in by cho45, 6 years ago)

lang/ruby/Chemr/CHMBundle.rb:

add しわすれ……

lang/ruby/Chemr/CHMDocument.rb:

候補がないときに自動的に fuzzy モードになるように

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
123                if @now.length.zero?
124                        r = /#{str.split(//).map {|c| Regexp.escape(c) }.join(".*")}/i
125                        @now = @index.select {|k,v|
126                                k =~ r
127                        }.sort_by {|k,v|
128                                r.match(k).begin(0)
129                        }
130                        @list.usesAlternatingRowBackgroundColors = false
131                        @list.backgroundColor = NSColor.objc_send(
132                                :colorWithCalibratedRed, 0.95,
133                                :green, 0.90,
134                                :blue, 0.90,
135                                :alpha, 1
136                        )
137                else
138                        @list.usesAlternatingRowBackgroundColors = true
139                end
140
141                @list.reloadData
142        end
143
144        def clicked(sender)
145                if @now[@list.selectedRow]
146                        browse @now[@list.selectedRow][1].first
147                end
148        end
149
150        def browse(path)
151                if path
152                        path = "/#{path}" unless path[0] == ?/
153                        h = @webview.stringByEvaluatingJavaScriptFromString("location.pathname+location.hash")
154                        unless path == h
155                                r = NSURLRequest.requestWithURL CHMInternalURLProtocol.url_for(@chm, path)
156                                log r
157                                @webview.mainFrame.loadRequest r
158                        end
159                end
160        end
161
162        def completion(sender)
163                return if @search.stringValue.empty?
164                return if @now.empty?
165                common = ""
166                keys = @now.map{|k,v| k.split(//)}
167                if @search.stringValue.to_s =~ /[A-Z]/
168                        keys[0].zip(*keys[1..-1]) do |a|
169                                m = a.first
170                                if a.all? {|v| m == v}
171                                        common << m
172                                else
173                                        break
174                                end
175                        end
176                else
177                        keys[0].zip(*keys[1..-1]) do |a|
178                                m = a.first.downcase
179                                if a.all? {|v| v && (m == v.downcase)}
180                                        common << m
181                                else
182                                        break
183                                end
184                        end
185                end
186                if common.length > @search.stringValue.length
187                        @search.stringValue = common
188                end
189        end
190
191        # from menu
192        def searchActivate(sender)
193                log "activate"
194                @search.window.makeFirstResponder(@search)
195        end
196
197        def nextCandidate(sender)
198                if @list.selectedRow <= @now.size
199                        @list.selectRowIndexes_byExtendingSelection(NSIndexSet.alloc.initWithIndex(@list.selectedRow+1), false)
200                        @list.scrollRowToVisible(@list.selectedRow)
201                        clicked(nil)
202                end
203        end
204
205        def prevCandidate(sender)
206                if @list.selectedRow > 0
207                        @list.selectRowIndexes_byExtendingSelection(NSIndexSet.alloc.initWithIndex(@list.selectedRow-1), false)
208                        @list.scrollRowToVisible(@list.selectedRow)
209                        clicked(nil)
210                end
211        end
212
213        def jumpToHome(sender)
214                browse @chm.home
215        end
216
217        def performFindPanelAction(sender)
218                log "performFindPanelAction"
219                # @webview.performFindPanelAction(sender) # なぜかうごかない
220                text = @search.stringValue
221                @webview.objc_send(
222                        :searchFor, text,
223                        :direction, true,
224                        :caseSensitive, false,
225                        :wrap, false
226                )
227        end
228
229        # from MySearchWindow
230
231        def process_keybinds(e)
232                if NSInputManager.currentInputManager
233                        return false unless NSInputManager.currentInputManager.markedRange.empty?
234                end
235                key = key_string(e)
236                log "keyDown (#{e.characters}:#{e.charactersIgnoringModifiers}) -> '#{key}'"
237                keybinds = {
238                        "C-j" => self.method(:nextCandidate),
239                        "C-n" => self.method(:nextCandidate),
240                        "C-k" => self.method(:prevCandidate),
241                        "C-p" => self.method(:prevCandidate),
242                        "\r"  => self.method(:jumpToCurrent),
243                        "\t"  => self.method(:completion),
244                        " "   => Proc.new {|s|
245                                @webview.stringByEvaluatingJavaScriptFromString <<-JS
246                                        window.scrollBy(0, 200);
247                                JS
248                        },
249                        "S- " => Proc.new {|s|
250                                @webview.stringByEvaluatingJavaScriptFromString <<-JS
251                                        window.scrollBy(0, -200);
252                                JS
253                        },
254                        "C-\r" => Proc.new {|s|
255                                @now = @chm.search(@search.stringValue).map {|title,url|
256                                        [title, [url]]
257                                }
258                                @list.reloadData
259                        },
260                        "C-u" => Proc.new {|s|
261                                @search.stringValue = ""
262                        },
263                        "G-[" => Proc.new {|s|
264                                @webview.goBack
265                        },
266                        "G-]" => Proc.new {|s|
267                                @webview.goForward
268                        },
269                        "G-=" => Proc.new {|s|
270                                @webview.makeTextLarger(self)
271                        },
272                        "G--" => Proc.new {|s|
273                                @webview.makeTextSmaller(self)
274                        },
275                }
276                (1..9).each do |i|
277                        keybinds["G-#{i}"] = Proc.new {|s|
278                                dc = NSDocumentController.sharedDocumentController
279                                if dc.documents[i-1]
280                                        log(dc.documents[i-1].windowControllers)
281                                        dc.documents[i-1].windowControllers.first.showWindow(self)
282                                end
283                        }
284                end
285                if keybinds.key?(key)
286                        keybinds[key].call(self)
287                        true
288                else
289                        false
290                end
291        end
292
293        def key_string(e)
294                key = ""
295                m = e.modifierFlags
296                key << "S-" if m & NSShiftKeyMask > 0
297                key << "C-" if m & NSControlKeyMask > 0
298                key << "M-" if m & NSAlternateKeyMask > 0
299                key << "G-" if m & NSCommandKeyMask > 0 # TODO
300                key << e.charactersIgnoringModifiers.to_s
301                key
302        end
303
304        # webview policyDelegate
305        def webView_decidePolicyForNavigationAction_request_frame_decisionListener(
306                sender,
307                actionInformation,
308                request,
309                frame,
310                listener
311        )
312
313                if CHMInternalURLProtocol.canHandleURL(request.URL)
314                        listener.use
315                else
316                        NSWorkspace.sharedWorkspace.openURL(request.URL)
317                        listener.ignore
318                end
319        end
320
321        def webView_decidePolicyForNewWindowAction_request_newFrameName_decisionListener(
322                sender,
323                actionInformation,
324                request,
325                frameName,
326                listener
327        )
328                if CHMInternalURLProtocol.canHandleURL(request.URL)
329                        listener.use
330                else
331                        NSWorkspace.sharedWorkspace.openURL(request.URL)
332                        listener.ignore
333                end
334        end
335
336        # webview loading delegate
337        def webView_resource_didFinishLoadingFromDataSource(sender, id, datasource)
338#               log "loaded"
339        end
340
341end
342
343class CHMDocument < NSDocument
344        attr_reader :chm
345
346        #- (void)makeWindowControllers
347        def makeWindowControllers
348                c = CHMWindowController.alloc.initWithWindowNibName("CHMDocument")
349                self.addWindowController(c)
350        end
351
352        #- (BOOL)readFromURL:(NSURL *)inAbsoluteURL ofType:(NSString *)inTypeName error:(NSError **)outError
353        def readFromURL_ofType_error(url, type, error)
354                path = Pathname.new(url.path.to_s)
355                if path.directory?
356                        @chm = CHMBundle.new(path)
357                else
358                        @chm = Chmlib::Chm.new(path.to_s)
359                end
360                true
361        end
362
363        #- (BOOL)writeToURL:(NSURL *)inAbsoluteURL ofType:(NSString *)inTypeName error:(NSError **)outError
364        def writeToURL_ofType_error(url, type, error)
365                false
366        end
367
368        #- (void)windowControllerDidLoadWindowNib:(NSWindowController *)windowController
369        def windowControllerDidLoadWindowNib(cont)
370                log "wCDLWN", cont
371        end
372
373#       def dataRepresentationOfType(aType)
374#       end
375#
376#       def loadDataRepresentation_ofType(data, aType)
377#       end
378
379        def displayName
380                dc = NSDocumentController.sharedDocumentController
381                i = dc.documents.index(self) + 1
382                cmd = [8984].pack("U")
383                "#{cmd}#{i}| #{@chm.title}"
384        end
385
386        def windowControllerWillLoadNib(cont)
387                log cont
388        end
389
390        def winwowNibName
391                "CHMDocument"
392        end
393end
394
395class MySearchWindow < NSWindow
396
397        def sendEvent(e)
398                if e.oc_type == NSKeyDown
399                        return if delegate.process_keybinds(e)
400                end
401                super_sendEvent(e)
402        end
403
404end
405
406
Note: See TracBrowser for help on using the browser.