Test Failed
Push — master ( 705b0f...728f1f )
by Yoshihiro
03:24
created

neditor.pm.ProcessingMenuClass.yahooresult()   B

Complexity

Conditions 2

Size

Total Lines 56
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

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