Completed
Pull Request — master (#52)
by Yoshihiro
04:22
created

processingmenu.ProcessingMenuClass.yahooresult()   B

Complexity

Conditions 2

Size

Total Lines 57
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 39
nop 2
dl 0
loc 57
rs 8.9439
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
import textwrap
2
import webbrowser
3
import tkinter as tk
4
import tkinter.ttk as ttk
5
import tkinter.messagebox as messagebox
6
import xml.etree.ElementTree as ET
7
8
import jaconv
9
import pyttsx3
10
import requests
11
12
13
class ProcessingMenuClass():
14
    """処理メニューバーのクラス
15
16
    ・処理メニューバーにあるプログラム群
17
18
    """
19
    def __init__(self, app, wiki_wiki, tokenizer):
20
        """
21
        Args:
22
            app (instance): lineframeインスタンス
23
            wiki_wiki (instance): wikipediaapi.Wikipediaインスタンス
24
            tokenizer (instance): Tokenizerインスタンス
25
26
        """
27
        # yahooの校正支援
28
        self.KOUSEI = "{urn:yahoo:jp:jlp:KouseiService}"
29
        self.APP = app
30
        self.WIKI_WIKI = wiki_wiki
31
        self.TOKENIZER = tokenizer
32
33
    def ruby_huri(self):
34
        """ルビをふる
35
36
        ・選択文字列に小説家になろうのルビを振る。
37
38
        """
39
        hon = ""
40
        # 選択文字列を切り取る
41
        set_ruby = self.APP.text.get('sel.first', 'sel.last')
42
        # 選択文字列を削除する
43
        self.APP.text.delete('sel.first', 'sel.last')
44
        # 形態素解析を行う
45
        for token in self.tokenizer.tokenize(set_ruby):
46
            # ルビの取得
47
            ruby = ""
48
            ruby = jaconv.kata2hira(token.reading)
49
            # 解析している文字のひらがなの部分を取得
50
            hira = ""
51
            for i in token.surface:
52
                if self.is_hiragana(i):
53
                    hira += i
54
            # ルビがないときと、記号の時の処理
55
            if ruby.replace(
56
                hira, ''
57
            ) == "" or token.part_of_speech.split(
58
                ","
59
            )[0] == u"記号":
60
                hon += token.surface
61
            else:
62
                # ルビ振りを行う
63
                hon += "|{0}≪{1}≫{2}".format(
64
                    token.surface.replace(hira, ''),
65
                    ruby.replace(hira, ''),
66
                    hira
67
                )
68
69
        # テキストを表示する
70
        self.APP.text.insert('insert', hon)
71
72
    def is_hiragana(self, char):
73
        """文字がひらがなか判断
74
75
        ・与えられた文字がひらがなかどうか判断する。
76
77
        Args:
78
            char (str): 判断する文字
79
80
        Returns:
81
            bool: ひらがなならTrue、違うならFalse
82
83
        """
84
        return (0x3040 < ord(char) < 0x3097)
85
86
    def count_moji(self):
87
        """文字数と行数を表示する
88
89
        ・文字数と行数をカウントして表示する。
90
91
        """
92
        # 行数の取得
93
        new_line = int(self.APP.text.index('end-1c').split('.')[0])
94
        # 文字列の取得
95
        moji = self.APP.text.get('1.0', 'end')
96
        # 20文字で区切ったときの行数を数える
97
        gen_mai = 0
98
        for val in moji.splitlines():
99
            gen_mai += len(textwrap.wrap(val, 20))
100
        # メッセージボックスの表示
101
        messagebox.showinfo(
102
            u"文字数と行数、原稿用紙枚数", "文字数 :{0}文字 行数 : {1}行"
103
            u"\n 原稿用紙 : {2}枚".format(
104
                len(moji)-new_line,
105
                new_line,
106
                -(-gen_mai//20)))
107
108
    def find_wikipedia(self):
109
        """意味を検索
110
111
        ・Wikipedia-APIライブラリを使ってWikipediaから選択文字の意味を
112
        検索する。
113
114
        """
115
        # wikipediaから
116
        select_text = self.APP.text.selection_get()
117
        page_py = self.WIKI_WIKI.page(select_text)
118
        # ページがあるかどうか判断
119
        if page_py.exists():
120
            messagebox.showinfo(
121
                "「{0}」の意味".format(select_text),
122
                page_py.summary
123
            )
124
        else:
125
            messagebox.showwarning(
126
                "「{0}」の意味".format(select_text),
127
                u"見つけられませんでした。"
128
            )
129
130
    def open_becoming_novelist_page(self):
131
        """小説家になろうのユーザーページを開く
132
133
        ・インターネットブラウザで小説家になろうのユーザーページを開く。
134
135
        """
136
        webbrowser.open("https://syosetu.com/user/top/")
137
138
    def read_text(self):
139
        """テキストを読み上げる
140
141
        ・pyttsx3ライブラリを使ってテキストボックスに書かれているものを読み上げる。
142
143
        """
144
        self.gyou_su = 0
145
        self.text_len = 0
146
        self.APP.text.focus()
147
        self.read_texts = True
148
        self.engine = pyttsx3.init()
149
        self.engine.connect('started-word', self.pyttsx3_onword)
150
        self.engine.connect('finished-utterance', self.pyttsx3_onend)
151
        self.engine.setProperty('rate', 150)
152
        self.engine.say(self.APP.text.get('1.0', 'end - 1c'))
153
        self.engine.startLoop(False)
154
        self.externalLoop()
155
156
    def externalLoop(self):
157
        """文章読み上げ繰り返し処理
158
159
        ・文章読み上げを繰り返し続ける。
160
161
        """
162
        self.engine.iterate()
163
164
    def pyttsx3_onword(self, name, location, length):
165
        """文章を読み上げ中の処理
166
167
        ・文章読み始めるときに止めるダイアログを出してから読み上げる。
168
        読み上げている最中は読み上げている行を選択状態にする。
169
170
        Args:
171
            name (str): 読み上げに関連付けられた名前
172
            location (int): 現在の場所
173
            length (int): 不明
174
175
        """
176
        # 今読んでいる場所と選択位置を比較する
177
        if location > self.text_len:
178
            # すべての選択一度解除する
179
            self.APP.text.tag_remove('sel', '1.0', 'end')
180
            # 現在読んでいる場所を選択する
181
            self.APP.text.tag_add(
182
                'sel',
183
                "{0}.0".format(self.gyou_su),
184
                "{0}.0".format(self.gyou_su+1)
185
            )
186
            # 次の行の長さをtextlenに入力する
187
            self.text_len += len(
188
                self.APP.text.get(
189
                    '{0}.0'.format(self.gyou_su),
190
                    '{0}.0'.format(self.gyou_su+1)
191
                )
192
            )
193
            # カーソルを文章の一番後ろに持ってくる
194
            self.APP.text.mark_set('insert', '{0}.0'.format(self.gyou_su+1))
195
            self.APP.text.see('insert')
196
            self.APP.text.focus()
197
            # 行を1行増やす
198
            self.gyou_su += 1
199
        # 読み初めての処理
200
        if self.read_texts:
201
            # 読むのを中止するウインドウを作成する
202
            self.sub_read_win = tk.Toplevel(self.APP)
203
            button = ttk.Button(
204
                self.sub_read_win,
205
                text=u'中止する',
206
                width=str(u'中止する'),
207
                padding=(100, 5),
208
                command=self.pyttsx3_onreadend
209
            )
210
            button.grid(row=1, column=1)
211
            # 最前面に表示し続ける
212
            self.sub_read_win.attributes("-topmost", True)
213
            # サイズ変更禁止
214
            self.sub_read_win.resizable(width=0, height=0)
215
            self.sub_read_win.title(u'読み上げ')
216
            self.read_texts = False
217
218
    def pyttsx3_onreadend(self):
219
        """中止するボタンを押したときの処理
220
221
        ・中止ボタンを押したときに読み上げをやめ、中止ウインドウ
222
        を削除する。
223
224
        """
225
        self.engine.stop()
226
        self.engine.endLoop()
227
        self.sub_read_win.destroy()
228
        self.APP.text.tag_remove('sel', '1.0', 'end')
229
230
    def pyttsx3_onend(self, name, completed):
231
        """文章を読み終えた時の処理
232
233
        ・文章を読み終えたら中止ウインドウを削除する。
234
235
        Args:
236
            name (str): 読み上げに関連付けられた名前
237
            completed (bool): 文章が読み上げ終わった(True)
238
239
        """
240
        self.engine.stop()
241
        self.engine.endLoop()
242
        self.sub_read_win.destroy()
243
        self.APP.text.tag_remove('sel', '1.0', 'end')
244
245
    def yahoo(self):
246
        """Yahoo! 校正支援
247
248
        ・Yahoo! 校正支援を呼び出し表示する。
249
250
        Args:
251
            event (instance): tkinter.Event のインスタンス
252
253
        """
254
        html = self.yahoocall(
255
            self.APP.APPID,
256
            self.APP.text.get('1.0', 'end -1c')
257
        )
258
        if not self.APP.APPID == "":
259
            self.yahooresult(html)
260
            self.yahoo_tree.bind("<Double-1>", self.on_double_click_yahoo)
261
262
    def yahoocall(self, appid="", sentence=""):
263
        """yahooの校正支援を呼び出す
264
265
        ・Yahoo! 校正支援をClient IDを使って呼び出す。
266
267
        Args:
268
            appid (str): Yahoo! Client ID
269
            sentence (str): 校正をしたい文字列
270
271
        Returns:
272
            str: 校正結果
273
274
        """
275
        if appid == "":
276
            messagebox.showerror(
277
                "Yahoo! Client ID",
278
                u"Yahoo! Client IDが見つかりません。\n"
279
                "Readme.pdfを読んで、設定し直してください。"
280
            )
281
            return
282
        url = "https://jlp.yahooapis.jp/KouseiService/V1/kousei"
283
        data = {
284
            "appid": appid.rstrip('\n'),
285
            "sentence": sentence,
286
        }
287
        html = requests.post(url, data)
288
        return html.text
289
290
    def yahooresult(self, html):
291
        """校正支援を表示する画面を制作
292
293
        ・校正結果を表示するダイアログを作成する。
294
295
        Args:
296
            html (str): 校正結果
297
298
        """
299
        xml = ET.fromstring(html)
300
        # サブウインドウの表示
301
        sub_win = tk.Toplevel(self.APP)
302
        # ツリービューの表示
303
        self.yahoo_tree = ttk.Treeview(sub_win)
304
        self.yahoo_tree["columns"] = (1, 2, 3, 4, 5)
305
        # 表スタイルの設定(headingsはツリー形式ではない、通常の表形式)
306
        self.yahoo_tree["show"] = "headings"
307
        self.yahoo_tree.column(1, width=100)
308
        self.yahoo_tree.column(2, width=80)
309
        self.yahoo_tree.column(3, width=75)
310
        self.yahoo_tree.column(4, width=150)
311
        self.yahoo_tree.column(5, width=120)
312
        self.yahoo_tree.heading(1, text="先頭からの文字数")
313
        self.yahoo_tree.heading(2, text="対象文字数")
314
        self.yahoo_tree.heading(3, text="対象表記")
315
        self.yahoo_tree.heading(4, text="言い換え候補文字列")
316
        self.yahoo_tree.heading(5, text="指摘の詳細情報")
317
        # 情報を取り出す
318
        for child in list(xml):
319
            StartPos = (child.findtext(self.KOUSEI+"StartPos"))
320
            Length = (child.findtext(self.KOUSEI+"Length"))
321
            Surface = (child.findtext(self.KOUSEI+"Surface"))
322
            ShitekiWord = (child.findtext(self.KOUSEI+"ShitekiWord"))
323
            ShitekiInfo = (child.findtext(self.KOUSEI+"ShitekiInfo"))
324
            self.yahoo_tree.insert(
325
                "",
326
                "end",
327
                values=(StartPos,
328
                        Length,
329
                        Surface,
330
                        ShitekiWord,
331
                        ShitekiInfo
332
                        )
333
                )
334
335
        self.yahoo_tree.grid(row=0, column=0, sticky=(tk.N, tk.S, tk.E, tk.W))
336
        # スクロールバーを表示する
337
        SCRLBAR_Y = ttk.Scrollbar(
338
            sub_win,
339
            orient=tk.VERTICAL,
340
            command=self.yahoo_tree.yview
341
        )
342
        self.yahoo_tree.configure(yscroll=SCRLBAR_Y.set)
343
        SCRLBAR_Y.grid(row=0, column=1, sticky=(tk.N, tk.S))
344
        # 最前面に表示し続ける
345
        sub_win.attributes("-topmost", True)
346
        sub_win.title(u'文章校正')
347
348
    def on_double_click_yahoo(self, event=None):
349
        """Yahoo! 校正支援リストをダブルクリック
350
351
        ・Yahoo! 校正支援ダイアログのリストをダブルクリックすると
352
        その該当箇所を選択する。
353
354
        Args:
355
            event (instance): tkinter.Event のインスタンス
356
357
        """
358
        i = 0
359
        textlen = 0
360
        textforlen = 0
361
        curItem = self.yahoo_tree.focus()
362
        value = self.yahoo_tree.item(curItem)
363
        # 出てくる場所を取得
364
        val = int(value.get("values")[0])
365
        # 出てくる文字数を取得
366
        lenge = value.get("values")[1]
367
        # 何行目になるか確認する
368
        while True:
369
            if val > textlen:
370
                i += 1
371
                textforlen = textlen
372
                textlen += len(
373
                    self.APP.text.get(
374
                        '{0}.0'.format(i),
375
                        '{0}.0'.format(i+1)
376
                    )
377
                )
378
            else:
379
                break
380
        if i == 0:
381
            i = 1
382
        # 選択状態を一旦削除
383
        self.APP.text.tag_remove('sel', '1.0', 'end')
384
        # 選択状態にする
385
        self.APP.text.tag_add(
386
            'sel',
387
            "{0}.{1}".format(i, val-textforlen),
388
            "{0}.{1}".format(i, val-textforlen+lenge)
389
        )
390
        # カーソルの移動
391
        self.APP.text.mark_set('insert', '{0}.{1}'.format(i, val-textforlen))
392
        self.APP.text.see('insert')
393
        # フォーカスを合わせる
394
        self.APP.text.focus()
395
        return
396