Completed
Push — master ( cf4cad...a9d7bc )
by Yoshihiro
01:53
created

novel_editor.LineFrame.onWord()   A

Complexity

Conditions 3

Size

Total Lines 43
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 28
nop 4
dl 0
loc 43
rs 9.208
c 0
b 0
f 0
1
#!/usr/bin/env python3
2
# -*- coding: utf8 -*-
3
import os
4
import re
5
import sys
6
import zipfile
7
import shutil
8
import webbrowser
9
import platform
10
import textwrap
11
import tkinter as tk
12
import tkinter.ttk as ttk
13
import tkinter.messagebox as messagebox
14
import tkinter.filedialog as filedialog
15
import xml.etree.ElementTree as ET
16
17
import jaconv
18
import pyttsx3
19
import wikipediaapi
20
import requests
21
from PIL import Image, ImageTk
22
from janome.tokenizer import Tokenizer
23
24
25
class CustomText(tk.Text):
26
    """Textのイベントを拡張したウィジェット
27
28
    ・textに<<Scroll>>イベントと、<<Change>>イベントを追加する。
29
30
    """
31
32
    def __init__(self, master, **kwargs):
33
        super().__init__(master, **kwargs)
34
        self.tk.eval('''
35
            proc widget_proxy {widget widget_command args} {
36
                set result [uplevel [linsert $args 0 $widget_command]]
37
                if {([lrange $args 0 1] == {xview moveto}) ||
38
                    ([lrange $args 0 1] == {xview scroll}) ||
39
                    ([lrange $args 0 1] == {yview moveto}) ||
40
                    ([lrange $args 0 1] == {yview scroll})} {
41
                    event generate  $widget <<Scroll>> -when tail
42
                }
43
                if {([lindex $args 0] in {insert replace delete})} {
44
                    event generate  $widget <<Change>> -when tail
45
                }
46
                # return the result from the real widget command
47
                return $result
48
            }
49
            ''')
50
        self.tk.eval('''
51
            rename {widget} _{widget}
52
            interp alias {{}} ::{widget} {{}} widget_proxy {widget} _{widget}
53
        '''.format(widget=str(self)))
54
55
56
class Mydialog():
57
    """ダイアログ作成クラス
58
59
    ・自作ダイアログを呼び出し表示する。
60
61
    Attributes:
62
        self.txt (str): インプットボックスの値
63
        self.sub_name_win (instance): ダイアログウインドウインスタンス
64
        self.txt_name (instance): インプットボックスインスタンス
65
66
    """
67
68
    def __init__(self, message, button1, button2, title, text):
69
        """
70
        Args:
71
            message (instance): 親ウインドウインスタンス
72
            button1 (str): ボタンのメッセージ
73
            button2 (bool): キャンセルボタンを表示する(True)
74
            title (str): タイトル
75
            text (bool): 選択状態にする(True)
76
77
        """
78
        self.txt = ""
79
        self.sub_name_win = tk.Toplevel(message)
80
        self.txt_name = ttk.Entry(self.sub_name_win, width=40)
81
        self.txt_name.grid(
82
            row=0,
83
            column=0,
84
            columnspan=2,
85
            padx=5,
86
            pady=5,
87
            sticky=tk.W+tk.E,
88
            ipady=3
89
        )
90
        button = ttk.Button(
91
            self.sub_name_win,
92
            text=button1,
93
            width=str(button1),
94
            padding=(10, 5),
95
            command=self.sub_name_ok
96
        )
97
        button.grid(row=1, column=0)
98
        if button2:
99
            button = ttk.Button(
100
                self.sub_name_win,
101
                text=u'キャンセル',
102
                width=str(u'キャンセル'),
103
                padding=(10, 5),
104
                command=self.sub_name_win.destroy
105
            )
106
107
            button.grid(row=1, column=1)
108
            self.txt_name.focus()
109
            if text is not False:
110
                self.txt_name.insert(tk.END, text)
111
                self.txt_name.select_range(0, 'end')
112
113
        self.sub_name_win.title(title)
114
        self.txt_name.focus()
115
116
    def sub_name_ok(self, event=None):
117
        """ダイアログボタンクリック時の処理
118
119
        ・自作ダイアログのボタンをクリックしたときにインプットボックスに
120
        入力されている値を取得する。
121
122
        Args:
123
            event (instance): tkinter.Event のインスタンス
124
125
        Returns:
126
            str: インプットボックスの値
127
128
        """
129
        self.txt = self.txt_name.get()
130
        self.sub_name_win.destroy()
131
        return self.txt
132
133
134
class LineFrame(ttk.Frame):
135
    """メインフレーム処理
136
137
    ・メインに表示される画面の処理をする。
138
139
    """
140
141
    def __init__(self, master=None, **kwargs):
142
        """初期設定
143
144
        ・初期化、メニューバーの作成、画面の描画、イベントの追加をする。
145
146
        """
147
        super().__init__(master, **kwargs)
148
        self.initialize()
149
150
        self.menu_bar = tk.Menu(self.master)
151
        self.master.config(menu=self.menu_bar)
152
153
        self.create_widgets()
154
        self.create_event()
155
156
    def initialize(self):
157
        """初期化処理
158
159
        ・変数の初期化及び起動準備をする。
160
161
        """
162
        # 今の処理ししているファイルのパス
163
        self.now_path = ""
164
        # 現在開いているファイル
165
        self.file_path = ""
166
        # 検索文字列
167
        self.last_text = ""
168
        # 現在入力中の初期テキスト
169
        self.text_text = ""
170
        # 文字の大きさ
171
        self.int_var = 16
172
        # yahooの校正支援
173
        self.KOUSEI = "{urn:yahoo:jp:jlp:KouseiService}"
174
        self.APPID = ""
175
        if os.path.isfile("./appid.txt"):
176
            f = open("./appid.txt", "r", encoding="utf-8")
177
            self.APPID = f.read()
178
            f.close()
179
        if u"ここを消して、" in self.APPID:
180
            self.APPID = ""
181
        # フォントをOSごとに変える
182
        pf = platform.system()
183
        if pf == 'Windows':
184
            self.font = "メイリオ"
185
        elif pf == 'Darwin':  # MacOS
186
            self.font = "Osaka-等幅"
187
        elif pf == 'Linux':
188
            self.font = "IPAゴシック"
189
        # dataフォルダがあるときは、削除する
190
        if os.path.isdir('./data'):
191
            shutil.rmtree('./data')
192
        # 新しくdataフォルダを作成する
193
        for val in tree_folder:
0 ignored issues
show
introduced by
The variable tree_folder does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
194
            os.makedirs('./{0}'.format(val[0]))
195
196
    def create_widgets(self):
197
        """画面の描画
198
199
        ・メインウインドウにウェジットを配置する。
200
201
        """
202
        # メニューの配置
203
        File_menu = tk.Menu(self.menu_bar, tearoff=0)
204
        Edit_menu = tk.Menu(self.menu_bar, tearoff=0)
205
        List_menu = tk.Menu(self.menu_bar, tearoff=0)
206
        Processing_menu = tk.Menu(self.menu_bar, tearoff=0)
207
        Help_menu = tk.Menu(self.menu_bar, tearoff=0)
208
        # ファイルメニュー
209
        File_menu.add_command(
210
            label=u'新規作成(N)',
211
            under=5,
212
            accelerator='Ctrl+N',
213
            command=self.new_open
214
        )
215
        File_menu.add_command(
216
            label=u'開く(O)',
217
            under=3,
218
            accelerator='Ctrl+E',
219
            command=self.open_file
220
        )
221
        File_menu.add_separator()
222
        File_menu.add_command(
223
            label=u'保存(S)',
224
            under=3,
225
            accelerator='Ctrl+S',
226
            command=self.overwrite_save_file
227
        )
228
        File_menu.add_command(
229
            label=u'名前を付けて保存(W)',
230
            under=9,
231
            accelerator='Ctrl+W',
232
            command=self.save_file
233
        )
234
        File_menu.add_separator()
235
        File_menu.add_command(
236
            label=u'閉じる(C)',
237
            under=4,
238
            accelerator='Ctrl+C',
239
            command=on_closing
240
        )
241
        self.menu_bar.add_cascade(
242
            label=u'ファイル(F)',
243
            under=5,
244
            menu=File_menu
245
        )
246
        # 編集メニュー
247
        Edit_menu.add_command(
248
            label=u'やり直し(R)',
249
            under=5,
250
            accelerator='Ctrl+Z',
251
            command=self.redo
252
        )
253
        Edit_menu.add_command(
254
            label=u'戻る(U)',
255
            under=3,
256
            accelerator='Ctrl+Shift+Z',
257
            command=self.undo
258
        )
259
        Edit_menu.add_separator()
260
        Edit_menu.add_command(
261
            label=u'切り取り(X)',
262
            under=5,
263
            accelerator='Ctrl+X',
264
            command=self.cut
265
        )
266
        Edit_menu.add_command(
267
            label=u'コピー(C)',
268
            under=4,
269
            accelerator='Ctrl+C',
270
            command=self.copy
271
        )
272
        Edit_menu.add_command(
273
            label=u'貼り付け(V)',
274
            under=5,
275
            accelerator='Ctrl+V',
276
            command=self.paste
277
        )
278
        Edit_menu.add_separator()
279
        Edit_menu.add_command(
280
            label=u'検索(F)',
281
            under=3,
282
            accelerator='Ctrl+F',
283
            command=self.find_dialog
284
        )
285
        Edit_menu.add_command(
286
            label=u'置換(L)',
287
            under=3,
288
            accelerator='Ctrl+L',
289
            command=self.replacement_dialog
290
        )
291
        self.menu_bar.add_cascade(
292
            label=u'編集(E)',
293
            under=3,
294
            menu=Edit_menu
295
        )
296
        # 処理メニュー
297
        Processing_menu.add_command(
298
            label=u'ルビをふる(R)',
299
            under=6,
300
            accelerator='Ctrl+R',
301
            command=self.ruby
302
        )
303
        Processing_menu.add_command(
304
            label=u'文字数のカウント(C)',
305
            under=9,
306
            accelerator='Ctrl+Shift+C',
307
            command=self.moji_count
308
        )
309
        Processing_menu.add_command(
310
            label=u'選択文字の意味(M)',
311
            under=8,
312
            accelerator='Ctrl+Shift+F',
313
            command=self.find_dictionaly
314
        )
315
        Processing_menu.add_command(
316
            label=u'文章の読み上げ(B)',
317
            under=8,
318
            accelerator='Ctrl+Shift+R',
319
            command=self.read_text
320
        )
321
        Processing_menu.add_command(
322
            label=u'文章校正(Y)',
323
            under=5,
324
            accelerator='Ctrl+Y',
325
            command=self.yahoo
326
        )
327
        Processing_menu.add_separator()
328
        Processing_menu.add_command(
329
            label=u'フォントサイズの変更(F)',
330
            under=11,
331
            accelerator='Ctrl+Shift+F',
332
            command=self.font_dialog
333
        )
334
        Processing_menu.add_separator()
335
        Processing_menu.add_command(
336
            label=u'「小説家になろう」のページを開く(U)',
337
            under=17,
338
            accelerator='Ctrl+U',
339
            command=self.open_url
340
        )
341
        self.menu_bar.add_cascade(
342
            label=u'処理(P)',
343
            under=3,
344
            menu=Processing_menu
345
        )
346
        # リストメニュー
347
        List_menu.add_command(
348
            label=u'項目を増やす(U)',
349
            under=7,
350
            accelerator='選択右クリック',
351
            command=self.message_window
352
        )
353
        List_menu.add_command(
354
            label=u'項目を削除(D)',
355
            under=6,
356
            accelerator='選択右クリック',
357
            command=self.message_window
358
        )
359
        List_menu.add_command(
360
            label=u'項目の名前を変更(C)',
361
            under=9,
362
            accelerator='Ctrl+G',
363
            command=self.on_name_click
364
        )
365
        self.menu_bar.add_cascade(
366
            label=u'リスト(L)',
367
            under=4,
368
            menu=List_menu
369
        )
370
        # ヘルプメニュー
371
        Help_menu.add_command(
372
            label=u'ヘルプ(H)',
373
            under=4,
374
            accelerator='Ctrl+H',
375
            command=self.open_help
376
        )
377
        Help_menu.add_command(
378
            label=u'バージョン情報(V)',
379
            under=8,
380
            accelerator='Ctrl+Shift+V',
381
            command=self.open_version
382
        )
383
        self.menu_bar.add_cascade(
384
            label=u'ヘルプ(H)',
385
            under=4,
386
            menu=Help_menu
387
        )
388
        # ツリーコントロール、入力欄、行番号欄、スクロール部分を作成
389
        self.tree = ttk.Treeview(self, show="tree")
390
        self.tree.grid(row=0, column=0, sticky=(tk.N, tk.S))
391
        self.frame()
392
        self.tree_get_loop()
393
394
    def frame(self):
395
        """フレーム内にテキストボックスを表示
396
397
        ・メインウインドウの右側に行番号、テキストボックス、スクロールバー
398
        を表示する。
399
400
        """
401
        # f1フレームにテキストエディタを表示
402
        self.f1 = tk.Frame(self, relief=tk.RIDGE, bd=2)
403
        self.text = CustomText(
404
            self.f1,
405
            font=(self.font, self.int_var),
406
            undo=True
407
        )
408
        self.line_numbers = tk.Canvas(self.f1, width=30)
409
        self.ysb = ttk.Scrollbar(
410
            self.f1,
411
            orient=tk.VERTICAL,
412
            command=self.text.yview
413
        )
414
        # 入力欄にスクロールを紐付け
415
        self.text.configure(yscrollcommand=self.ysb.set)
416
        # 左から行番号、入力欄、スクロールウィジェット
417
        self.line_numbers.grid(row=0, column=0, sticky=(tk.N, tk.S))
418
        self.text.grid(row=0, column=1, sticky=(tk.N, tk.S, tk.W, tk.E))
419
        self.ysb.grid(row=0, column=2, sticky=(tk.N, tk.S))
420
        self.f1.columnconfigure(1, weight=1)
421
        self.f1.rowconfigure(0, weight=1)
422
        self.f1.grid(row=0, column=1, sticky=(tk.N, tk.S, tk.W, tk.E))
423
        # テキスト入力欄のみ拡大されるように
424
        self.columnconfigure(1, weight=1)
425
        self.rowconfigure(0, weight=1)
426
        # テキストを読み取り専用にする
427
        self.text.configure(state='disabled')
428
        # テキストにフォーカスを当てる
429
        self.text.focus()
430
        self.create_event_text()
431
432
    def frame_image(self):
433
        """フレーム内にイメージフレーム表示
434
435
        ・メインウインドウの右側にイメージキャンバス、スクロールバーを表示する。
436
437
        """
438
        self.f1 = tk.Frame(self, relief=tk.RIDGE, bd=2)
439
        self.image_space = tk.Canvas(self.f1, bg="black", width=30)
440
        self.image_ysb = ttk.Scrollbar(
441
            self.f1,
442
            orient=tk.VERTICAL,
443
            command=self.image_space.yview
444
        )
445
        self.image_xsb = ttk.Scrollbar(
446
            self.f1,
447
            orient=tk.HORIZONTAL,
448
            command=self.image_space.xview
449
        )
450
        self.image_space.configure(xscrollcommand=self.image_xsb.set)
451
        self.image_space.configure(yscrollcommand=self.image_ysb.set)
452
        self.image_space.grid(row=0, column=1, sticky=(tk.N, tk.S, tk.W, tk.E))
453
        self.image_ysb.grid(row=0, column=2, sticky=(tk.N, tk.S))
454
        self.image_xsb.grid(row=1, column=1, sticky=(tk.W, tk.E))
455
        self.f1.grid(row=0, column=1, sticky=(tk.N, tk.S, tk.W, tk.E))
456
        self.f1.columnconfigure(1, weight=1)
457
        self.f1.rowconfigure(0, weight=1)
458
        self.f1.grid(row=0, column=1, sticky=(tk.N, tk.S, tk.W, tk.E))
459
        # デフォルトの画像を設定する
460
        self.image_space.photo = tk.PhotoImage(data=original_image)
0 ignored issues
show
introduced by
The variable original_image does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
461
        self.image_on_space = self.image_space.create_image(
462
            0,
463
            0,
464
            anchor='nw',
465
            image=self.image_space.photo
466
        )
467
        self.create_event_image()
468
469
    def frame_character(self):
470
        """フレーム内にイメージフレーム表示
471
472
        ・メインウインドウの右側に呼び名、似顔絵、名前、誕生日、略歴を表示する。
473
474
        """
475
        # チェック有無変数
476
        self.var = tk.IntVar()
477
        # value=0のラジオボタンにチェックを入れる
478
        self.var.set(0)
479
        self.f1 = tk.Frame(self, relief=tk.RIDGE, bd=2)
480
        self.label1 = tk.Label(self.f1, text=u"呼び名")
481
        self.txt_yobi_name = ttk.Entry(
482
            self.f1, width=30,
483
            font=(self.font, self.int_var)
484
        )
485
        self.label2 = tk.Label(self.f1, text=u"名前")
486
        self.txt_name = ttk.Entry(
487
            self.f1, width=40,
488
            font=(self.font, self.int_var)
489
        )
490
        self.f2 = tk.LabelFrame(self.f1, relief=tk.RIDGE, bd=2, text=u"性別")
491
        self.rdo1 = tk.Radiobutton(
492
            self.f2, value=0,
493
            variable=self.var,
494
            text=u'男'
495
        )
496
        self.rdo2 = tk.Radiobutton(
497
            self.f2, value=1,
498
            variable=self.var,
499
            text=u'女'
500
        )
501
        self.rdo3 = tk.Radiobutton(
502
            self.f2, value=2,
503
            variable=self.var,
504
            text=u'その他'
505
        )
506
        self.rdo1.grid(row=0, column=1)
507
        self.rdo2.grid(row=1, column=1)
508
        self.rdo3.grid(row=2, column=1)
509
        self.f3 = tk.LabelFrame(self.f1, relief=tk.RIDGE, bd=2, text=u"似顔絵")
510
        self.cv = self.foto_canvas = tk.Canvas(
511
            self.f3,
512
            bg="black",
513
            width=149,
514
            height=199
515
        )
516
        self.foto_canvas.grid(row=0, column=0)
517
        self.label3 = tk.Label(self.f1, text=u"誕生日")
518
        self.txt_birthday = ttk.Entry(
519
            self.f1, width=40,
520
            font=(self.font, self.int_var)
521
        )
522
        self.f4 = tk.Frame(self.f1)
523
        self.foto_button = ttk.Button(
524
            self.f4,
525
            width=5,
526
            text=u'挿入',
527
            command=self.btn_click
528
        )
529
        self.foto_button_calcel = ttk.Button(
530
            self.f4,
531
            width=5,
532
            text=u'消去',
533
            command=self.clear_btn_click
534
        )
535
        self.foto_button.grid(row=0, column=1)
536
        self.foto_button_calcel.grid(row=1, column=1)
537
        self.label4 = tk.Label(self.f1, text=u"略歴")
538
        self.text_body = tk.Text(
539
            self.f1,
540
            width=80,
541
            font=(self.font, self.int_var)
542
        )
543
        self.label1.grid(row=0, column=1, columnspa=2)
544
        self.txt_yobi_name.grid(row=1, column=1, columnspa=2)
545
        self.f2.grid(row=2, column=1, rowspan=2)
546
        self.f4.grid(row=3, column=2)
547
        self.f3.grid(row=0, column=3, rowspan=4)
548
        self.label2.grid(row=0, column=4, sticky=(tk.N, tk.S, tk.W, tk.E))
549
        self.txt_name.grid(row=1, column=4)
550
        self.label3.grid(row=2, column=4)
551
        self.txt_birthday.grid(row=3, column=4)
552
        self.label4.grid(row=4, column=1, columnspa=4)
553
        self.text_body.grid(
554
            row=5,
555
            column=1,
556
            columnspa=4,
557
            sticky=(tk.N, tk.S, tk.W, tk.E)
558
        )
559
        self.f1.columnconfigure(1, weight=1)
560
        self.f1.columnconfigure(4, weight=1)
561
        self.f1.rowconfigure(5, weight=1)
562
563
        self.f1.grid(row=0, column=1, sticky=(tk.N, tk.S, tk.W, tk.E))
564
        self.columnconfigure(1, weight=1)
565
        self.rowconfigure(0, weight=1)
566
        # デフォルトの画像を設定する
567
        self.cv.photo = tk.PhotoImage(data=original_image)
0 ignored issues
show
introduced by
The variable original_image does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
568
        self.image_on_canvas = self.cv.create_image(
569
            0,
570
            0,
571
            anchor='nw',
572
            image=self.cv.photo
573
        )
574
575
        # キャラクターイベントを追加
576
        self.create_event_character()
577
578
    def create_event_text(self):
579
        """テキストイベントの設定
580
581
        ・テキストボックスにイベントを追加する。
582
583
        """
584
        # テキスト内でのスクロール時
585
        self.text.bind('<<Scroll>>', self.update_line_numbers)
586
        self.text.bind('<Up>', self.update_line_numbers)
587
        self.text.bind('<Down>', self.update_line_numbers)
588
        self.text.bind('<Left>', self.update_line_numbers)
589
        self.text.bind('<Right>', self.update_line_numbers)
590
        # テキストの変更時
591
        self.text.bind('<<Change>>', self.change_setting)
592
        # キー場押されたときの処理
593
        self.text.bind("<Any-KeyPress>", self.push_keys)
594
        # ウィジェットのサイズが変わった際。行番号の描画を行う
595
        self.text.bind('<Configure>', self.update_line_numbers)
596
        # Tab押下時(インデント、又はコード補完)
597
        self.text.bind('<Tab>', self.tab)
598
        # ルビを振る
599
        self.text.bind('<Control-Key-r>', self.ruby)
600
        # 開くダイアロクを表示する
601
        self.text.bind('<Control-Key-e>', self.open_file)
602
        # 保存ダイアロクを表示する
603
        self.text.bind('<Control-Key-w>', self.save_file)
604
        # 小説家になろうを開く
605
        self.text.bind('<Control-Key-u>', self.open_url)
606
        # 検索ダイアログを開く
607
        self.text.bind('<Control-Key-f>', self.find_dialog)
608
        # 置換ダイアログを開く
609
        self.text.bind('<Control-Key-l>', self.replacement_dialog)
610
        # 上書き保存する
611
        self.text.bind('<Control-Key-s>', self.overwrite_save_file)
612
        # 新規作成する
613
        self.text.bind('<Control-Key-n>', self.new_open)
614
        # helpページを開く
615
        self.text.bind('<Control-Key-h>', self.open_help)  # helpページを開く
616
        # Versionページを開く
617
        self.text.bind('<Control-Shift-Key-V>', self.open_version)
618
        # 文字数と行数をカウントすShift-る
619
        self.text.bind('<Control-Shift-Key-C>', self.moji_count)
620
        # redo処理
621
        self.text.bind('<Control-Shift-Key-Z>', self.redo)
622
        # フォントサイズの変更
623
        self.text.bind('<Control-Shift-Key-F>', self.font_dialog)
624
        # 意味を検索
625
        self.text.bind('<Control-Shift-Key-D>', self.find_dictionaly)
626
        # 文章を読み上げ
627
        self.text.bind('<Control-Shift-Key-R>', self.read_text)
628
        # yahoo文字列解析
629
        self.text.bind('<Control-Key-y>', self.yahoo)
630
631
    def create_event_image(self):
632
        """イメージイベントの設定
633
634
        ・イメージキャンバスにイベントを追加する。
635
636
        """
637
        self.image_space.bind('<MouseWheel>', self.mouse_y_scroll)
638
        self.image_space.bind('<Control-MouseWheel>', self.mouse_image_scroll)
639
640
    def create_event_character(self):
641
        """キャラクター欄のイベント設定
642
643
        ・キャラクター関係のボックスにイベントを追加する。
644
645
        """
646
        # 開くダイアロクを表示する
647
        self.txt_yobi_name.bind('<Control-Key-e>', self.open_file)
648
        self.txt_name.bind('<Control-Key-e>', self.open_file)
649
        self.txt_birthday.bind('<Control-Key-e>', self.open_file)
650
        self.text_body.bind('<Control-Key-e>', self.open_file)
651
        # 保存ダイアロクを表示する
652
        self.txt_yobi_name.bind('<Control-Key-w>', self.save_file)
653
        self.txt_name.bind('<Control-Key-w>', self.save_file)
654
        self.txt_birthday.bind('<Control-Key-w>', self.save_file)
655
        self.text_body.bind('<Control-Key-w>', self.save_file)
656
        # 小説家になろうを開く
657
        self.txt_yobi_name.bind('<Control-Key-u>', self.open_url)
658
        self.txt_name.bind('<Control-Key-u>', self.open_url)
659
        self.txt_birthday.bind('<Control-Key-u>', self.open_url)
660
        self.text_body.bind('<Control-Key-u>', self.open_url)
661
        # 検索ダイアログを開く
662
        self.txt_yobi_name.bind('<Control-Key-f>', self.find_dialog)
663
        self.txt_name.bind('<Control-Key-f>', self.find_dialog)
664
        self.txt_yobi_name.bind('<Control-Key-f>', self.find_dialog)
665
        self.text_body.bind('<Control-Key-f>', self.find_dialog)
666
        # 上書き保存する
667
        self.txt_yobi_name.bind('<Control-Key-s>', self.overwrite_save_file)
668
        self.txt_name.bind('<Control-Key-s>', self.overwrite_save_file)
669
        self.txt_birthday.bind('<Control-Key-s>', self.overwrite_save_file)
670
        self.text_body.bind('<Control-Key-s>', self.overwrite_save_file)
671
        # 新規作成する
672
        self.txt_yobi_name.bind('<Control-Key-n>', self.new_open)
673
        self.txt_name.bind('<Control-Key-n>', self.new_open)
674
        self.txt_yobi_name.bind('<Control-Key-n>', self.new_open)
675
        self.text_body.bind('<Control-Key-n>', self.new_open)
676
        # helpページを開く
677
        self.txt_yobi_name.bind('<Control-Key-h>', self.open_help)
678
        self.txt_name.bind('<Control-Key-h>', self.open_help)
679
        self.txt_birthday.bind('<Control-Key-h>', self.open_help)
680
        self.text_body.bind('<Control-Key-h>', self.open_help)
681
        # Versionページを開く
682
        self.txt_yobi_name.bind('<Control-Shift-Key-V>', self.open_version)
683
        self.txt_name.bind('<Control-Shift-Key-V>', self.open_version)
684
        self.txt_birthday.bind('<Control-Shift-Key-V>', self.open_version)
685
        self.txt_yobi_name.bind('<Control-Shift-Key-V>', self.open_version)
686
        # redo処理
687
        self.txt_yobi_name.bind('<Control-Shift-Key-Z>', self.redo)
688
        self.txt_name.bind('<Control-Shift-Key-Z>', self.redo)
689
        self.txt_birthday.bind('<Control-Shift-Key-Z>', self.redo)
690
        self.text_body.bind('<Control-Shift-Key-Z>', self.redo)
691
        # フォントサイズの変更
692
        self.txt_yobi_name.bind('<Control-Shift-Key-F>', self.font_dialog)
693
        self.txt_name.bind('<Control-Shift-Key-F>', self.font_dialog)
694
        self.txt_birthday.bind('<Control-Shift-Key-F>', self.font_dialog)
695
        self.text_body.bind('<Control-Shift-Key-F>', self.font_dialog)
696
697
    def create_event(self):
698
        """ツリービューイベントの設定
699
700
        ・ツリービューにイベントを追加する。
701
702
        """
703
        # ツリービューをダブルクリックしたときにその項目を表示する
704
        self.tree.bind("<Double-1>", self.on_double_click)
705
        # ツリービューの名前を変更する
706
        self.tree.bind("<Control-Key-g>", self.on_name_click)
707
        # ツリービューで右クリックしたときにダイアログを表示する
708
        self.tree.bind("<Button-3>", self.message_window)
709
710
    def push_keys(self, event=None):
711
        """キーが押されたときの処理
712
713
        ・何かキーが押されたときに検索処理を中断する。
714
715
        Args:
716
            event (instance): tkinter.Event のインスタンス
717
718
        """
719
        # 検索処理を中断する
720
        self.replacement_dialog = 0
721
722
    def mouse_y_scroll(self, event=None):
723
        """マウスホイール移動の設定
724
725
        ・イメージキャンバスでマウスホイールを回したときにイメージキャンバス
726
        をスクロールする。
727
728
        Args:
729
            event (instance): tkinter.Event のインスタンス
730
731
        """
732
        if event.delta > 0:
733
            self.image_space.yview_scroll(-1, 'units')
734
        elif event.delta < 0:
735
            self.image_space.yview_scroll(1, 'units')
736
737
    def mouse_image_scroll(self, event=None):
738
        """Ctrl+マウスホイールの拡大縮小設定
739
740
        ・イメージキャンバスでCtrl+マウスホイールを回したときに画像を
741
        拡大縮小する。
742
743
        Args:
744
            event (instance): tkinter.Event のインスタンス
745
746
        """
747
        curItem = self.tree.focus()
748
        self.select_list_item = self.tree.item(curItem)["text"]
749
        title = "./{0}/{1}.txt".format(
750
            tree_folder[4][0],
0 ignored issues
show
introduced by
The variable tree_folder does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
751
            self.select_list_item
752
        )
753
        f = open(title, 'r', encoding='utf-8')
754
        zoom = f.read()
755
        self.zoom = int(zoom)
756
        f.close()
757
        if event.delta > 0:
758
            self.zoom -= 5
759
            if self.zoom < 10:
760
                self.zoom = 10
761
        elif event.delta < 0:
762
            self.zoom += 5
763
764
        f = open(title, 'w', encoding='utf-8')
765
        f.write(str(self.zoom))
766
        f.close()
767
        self.path_read_image(
768
                    tree_folder[4][0],
769
                    self.select_list_item,
770
                    self.zoom
771
                )
772
773
    def btn_click(self, event=None):
774
        """似顔絵ボタンを押したとき
775
776
        ・似顔絵ボタンを押したときに画像イメージを似顔絵フレームに
777
        貼り付ける。
778
779
        Args:
780
            event (instance): tkinter.Event のインスタンス
781
782
        """
783
        fTyp = [(u"gif画像", ".gif")]
784
        iDir = os.path.abspath(os.path.dirname(__file__))
785
        self.filepath = filedialog.askopenfilename(
786
            filetypes=fTyp,
787
            initialdir=iDir
788
        )
789
        if not self.filepath == "":
790
            path, ___ = os.path.splitext(os.path.basename(self.now_path))
791
            ____, ext = os.path.splitext(os.path.basename(self.filepath))
792
            title = shutil.copyfile(
793
                self.filepath,
794
                "./{0}/{1}{2}".format(
795
                    tree_folder[0][0],
0 ignored issues
show
introduced by
The variable tree_folder does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
796
                    path,
797
                    ext
798
                )
799
            )
800
            self.print_gif(title)
801
802
    def clear_btn_click(self, event=None):
803
        """消去ボタンをクリックしたとき
804
805
        ・消去ボタンをクリックしたときに画像イメージから画像を
806
        削除する。
807
808
        Args:
809
            event (instance): tkinter.Event のインスタンス
810
811
        """
812
        files = "./{0}/{1}.gif".format(
813
            tree_folder[0][0],
0 ignored issues
show
introduced by
The variable tree_folder does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
814
            self.select_list_item
815
        )
816
        if os.path.isfile(files):
817
            os.remove(files)
818
            self.cv.delete("all")
819
820
    def resize_gif(self, im):
821
        """画像をリサイズする
822
823
        ・イメージファイルを縦が長いときは縦を、横が長いときは横を、
824
        同じときは両方を150pxに設定する。
825
826
        Args:
827
            im (instance): イメージインスタンス
828
829
        Returns:
830
            instance: イメージインスタンス
831
832
        """
833
        if im.size[0] == im.size[1]:
834
            resized_image = im.resize((150, 150))
835
        elif im.size[0] > im.size[1]:
836
            zoom = int(im.size[1] * 150 / im.size[0])
837
            resized_image = im.resize((150, zoom))
838
        elif im.size[0] < im.size[1]:
839
            zoom = int(im.size[0] * 200 / im.size[1])
840
            resized_image = im.resize((zoom, 200))
841
        return resized_image
0 ignored issues
show
introduced by
The variable resized_image does not seem to be defined for all execution paths.
Loading history...
842
843
    def print_gif(self, title):
844
        """gifを表示する
845
846
        ・似顔絵キャンバスに画像を張り付ける。
847
848
        Args:
849
            title (str): タイトル
850
851
        """
852
        if not title == "":
853
            giffile = Image.open(title)
854
            self.cv.photo = ImageTk.PhotoImage(self.resize_gif(giffile))
855
            giffile.close()
856
            self.cv.itemconfig(self.image_on_canvas, image=self.cv.photo)
857
858
    def create_tags(self):
859
        """タグの作成
860
861
        ・キャラクターの名前をJanomeの形態素解析にかかるようにする。
862
        キャラクターの名前を色付きにする。
863
864
        """
865
        i = 0
866
        system_dic = u"喜寛,固有名詞,ヨシヒロ"
867
        # キャラクターから一覧を作る。
868
        children = self.tree.get_children('data/character')
869
        for child in children:
870
            # ユーザー定義辞書の設定
871
            reading = ""
872
            childname = self.tree.item(child, "text")
873
            for token in tokenizer.tokenize(childname):
0 ignored issues
show
introduced by
The variable tokenizer does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
874
                reading += token.phonetic
875
            system_dic += u"\n{0},固有名詞,{1}".format(childname, reading)
876
            # タグの作成
877
            self.text.tag_configure(
878
                childname,
879
                foreground=color[i % len(color)],
0 ignored issues
show
introduced by
The variable color does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
880
                font=(self.font, self.int_var, "bold")
881
            )
882
            i += 1
883
        f = open("./userdic.csv", 'w', encoding='utf-8')
884
        f.write(system_dic)
885
        f.close()
886
        # Janomeを使って日本語の形態素解析
887
        self.t = Tokenizer(
888
            "./userdic.csv",
889
            udic_type="simpledic",
890
            udic_enc="utf8"
891
        )
892
893
    def all_highlight(self, event=None):
894
        """全てハイライト
895
896
        ・開く処理等の時にすべての行をハイライトする。
897
898
        Args:
899
            event (instance): tkinter.Event のインスタンス
900
901
        """
902
        # 全てのテキストを取得
903
        src = self.text.get('1.0', 'end - 1c')
904
        # 全てのハイライトを一度解除する
905
        for tag in self.text.tag_names():
906
            self.text.tag_remove(tag, '1.0', 'end')
907
908
        # ハイライトする
909
        self._highlight('1.0', src, 'end')
910
911
    def line_highlight(self, event=None):
912
        """現在行だけハイライト
913
914
        ・入力等の変更時に現在の行のみをハイライトする。
915
916
        Args:
917
            event (instance): tkinter.Event のインスタンス
918
919
        """
920
        start = 'insert linestart'
921
        end = 'insert lineend'
922
        # 現在行のテキストを取得
923
        src = self.text.get(start, end)
924
        # その行のハイライトを一度解除する
925
        for tag in self.text.tag_names():
926
            self.text.tag_remove(tag, start, end)
927
928
        # ハイライトする
929
        self._highlight(start, src, end)
930
        # 置換処理時に選択する
931
        if self.replacement_dialog == 1:
932
            start = self.next_pos
933
            end = '{0} + {1}c'.format(self.next_pos, len(self.last_text))
934
            self.text.tag_add('sel', start, end)
935
936
    def _highlight(self, start, src, end):
937
        """ハイライトの共通処理
938
939
        ・ハイライトする文字が見つかったらハイライト処理をする。
940
        先頭の文字が全角スペースならば、一文字ずらしてハイライトする。
941
942
        """
943
        self.create_tags()
944
        self.text.mark_set('range_start', start)
945
        space_count = re.match(r"\u3000*", self.text.get(start, end)).end()
946
        # 形態素解析を行う
947
        for token in self.t.tokenize(src):
948
            content = token.surface
949
            self.text.mark_set(
950
                'range_end', 'range_start+{0}c'
951
                .format(len(content))
952
            )
953
            # 全角スペースの時はずらす
954
            if space_count > 0:
955
                self.text.tag_add(
956
                    content,
957
                    'range_start+{0}c'.format(space_count),
958
                    'range_end+{0}c'.format(space_count)
959
                )
960
            else:
961
                self.text.tag_add(content, 'range_start', 'range_end')
962
            self.text.mark_set('range_start', 'range_end')
963
964
    def font_dialog(self, event=None):
965
        """フォントサイズダイアログを作成
966
967
        ・フォントサイズダイアログを作成し表示する。
968
969
        Args:
970
            event (instance): tkinter.Event のインスタンス
971
972
        """
973
        self.sub_wins = tk.Toplevel(self)
974
        self.intSpin = ttk.Spinbox(self.sub_wins, from_=12, to=72)
975
        self.intSpin.grid(
976
            row=0,
977
            column=0,
978
            columnspan=2,
979
            padx=5,
980
            pady=5,
981
            sticky=tk.W+tk.E,
982
            ipady=3
983
        )
984
        button = ttk.Button(
985
            self.sub_wins,
986
            text=u'サイズ変更',
987
            width=str(u'サイズ変更'),
988
            padding=(10, 5),
989
            command=self.font_size_Change
990
        )
991
        button.grid(row=1, column=1)
992
        self.intSpin.set(self.int_var)
993
        self.sub_wins.title(u'フォントサイズの変更')
994
995
    def font_size_Change(self):
996
        """フォントのサイズを変える
997
998
        ・サイズ変更を押されたときにサイズを変更する。
999
        上は72ptまで下は12ptまでにする。
1000
1001
        """
1002
        # 比較のため数値列に変更
1003
        self.int_var = int(self.intSpin.get())
1004
        if self.int_var < 12:  # 12より下の値を入力した時、12にする
1005
            self.int_var = 12
1006
        elif 72 < self.int_var:  # 72より上の値を入力した時、72にする
1007
            self.int_var = 72
1008
        # 文字列にもどす
1009
        self.int_var = str(self.int_var)
1010
        self.sub_wins.destroy()
1011
        # フォントサイズの変更
1012
        self.text.configure(font=(self.font, self.int_var))
1013
        # ハイライトのやり直し
1014
        self.all_highlight()
1015
1016
    def open_url(self, event=None):
1017
        """小説家になろうのユーザーページを開く
1018
1019
        ・インターネットブラウザで小説家になろうのユーザーページを開く。
1020
1021
        Args:
1022
            event (instance): tkinter.Event のインスタンス
1023
1024
        """
1025
        webbrowser.open("https://syosetu.com/user/top/")
1026
1027
    def find_dictionaly(self, event=None):
1028
        """意味を検索
1029
1030
        ・Wikipedia-APIライブラリを使ってWikipediaから選択文字の意味を
1031
        検索する。
1032
1033
        Args:
1034
            event (instance): tkinter.Event のインスタンス
1035
1036
        """
1037
        # wikipediaから
1038
        select_text = self.text.selection_get()
1039
        page_py = wiki_wiki.page(select_text)
0 ignored issues
show
introduced by
The variable wiki_wiki does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
1040
        # ページがあるかどうか判断
1041
        if page_py.exists():
1042
            messagebox.showinfo(
1043
                "「{0}」の意味".format(select_text),
1044
                page_py.summary
1045
            )
1046
        else:
1047
            messagebox.showwarning(
1048
                "「{0}」の意味".format(select_text),
1049
                u"見つけられませんでした。"
1050
            )
1051
1052
    def open_help(self, event=None):
1053
        """helpページを開く
1054
1055
        ・ウエブブラウザを使ってREADME.htmlを表示する。
1056
1057
        Args:
1058
            event (instance): tkinter.Event のインスタンス
1059
1060
        """
1061
        webbrowser.open(
1062
            'file://' + os.path.dirname(
1063
                os.path.abspath(os.path.dirname(__file__))
1064
            )
1065
            + "/README.html"
1066
        )
1067
1068
    def open_version(self, event=None):
1069
        """バージョン情報を表示
1070
1071
        ・バージョン情報表示ダイアログを表示する。
1072
        ×を押すまで消えないようにする。
1073
1074
        Args:
1075
            event (instance): tkinter.Event のインスタンス
1076
1077
        """
1078
        img2 = tk.PhotoImage(data=datas)
0 ignored issues
show
introduced by
The variable datas does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
1079
        window = tk.Toplevel(root)
0 ignored issues
show
introduced by
The variable root does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
1080
        self.pack()
1081
        self.canvas = tk.Canvas(window, width=600, height=300)
1082
        self.canvas.create_image(0, 0, anchor='nw', image=img2)
1083
        self.canvas.create_text(
1084
            550,
1085
            290,
1086
            anchor='se',
1087
            text='Copyright (C) 2019-2020 Yamahara Yoshihiro',
1088
            font=('', 12)
1089
        )
1090
        self.canvas.create_text(
1091
            420,
1092
            120,
1093
            anchor='nw',
1094
            text='Ver 0.6.0 Beta',
1095
            font=('', 12)
1096
        )
1097
        self.canvas.pack()
1098
        window.resizable(width=0, height=0)
1099
        window.mainloop()
1100
1101
    def read_text(self, event=None):
1102
        """テキストを読み上げる
1103
1104
        ・pyttsx3ライブラリを使ってテキストボックスに書かれているものを読み上げる。
1105
1106
        Args:
1107
            event (instance): tkinter.Event のインスタンス
1108
1109
        """
1110
        self.text.focus()
1111
        self.read_texts = True
1112
        self.engine = pyttsx3.init()
1113
        self.engine.connect('started-word', self.pyttsx3_onword)
1114
        self.engine.connect('finished-utterance', self.pyttsx3_onend)
1115
        self.engine.setProperty('rate', 150)
1116
        self.engine.say(self.text.get('1.0', 'end - 1c'))
1117
        self.i = 0
1118
        self.textlen = 0
1119
        self.engine.startLoop(False)
1120
        self.externalLoop()
1121
1122
    def externalLoop(self):
1123
        """文章読み上げ繰り返し処理
1124
1125
        ・文章読み上げを繰り返し続ける。
1126
1127
        """
1128
        self.engine.iterate()
1129
1130
    def pyttsx3_onword(self, name, location, length):
1131
        """文章を読み上げ中の処理
1132
1133
        ・文章読み始めるときに止めるダイアログを出してから読み上げる。
1134
        読み上げている最中は読み上げている行を選択状態にする。
1135
1136
        Args:
1137
            name (str): 読み上げに関連付けられた名前
1138
            location (int): 現在の場所
1139
            length (int): 不明
1140
1141
        """
1142
        # 今読んでいる場所と選択位置を比較する
1143
        if location > self.textlen:
1144
            # すべての選択一度解除する
1145
            self.text.tag_remove('sel', '1.0', 'end')
1146
            # 現在読んでいる場所を選択する
1147
            self.text.tag_add(
1148
                'sel',
1149
                "{0}.0".format(self.i),
1150
                "{0}.0".format(self.i+1)
1151
            )
1152
            # 次の行の長さをtextlenに入力する
1153
            self.textlen += len(
1154
                self.text.get(
1155
                    '{0}.0'.format(self.i),
1156
                    '{0}.0'.format(self.i+1)
1157
                )
1158
            )
1159
            # カーソルを文章の一番後ろに持ってくる
1160
            self.text.mark_set('insert', '{0}.0'.format(self.i+1))
1161
            self.text.see('insert')
1162
            self.text.focus()
1163
            # 行を1行増やす
1164
            self.i += 1
1165
        # 読み初めての処理
1166
        if self.read_texts:
1167
            # 読むのを中止するウインドウを作成する
1168
            self.sub_read_win = tk.Toplevel(self)
1169
            button = ttk.Button(
1170
                self.sub_read_win,
1171
                text=u'中止する',
1172
                width=str(u'中止する'),
1173
                padding=(100, 5),
1174
                command=self.pyttsx3_onreadend
1175
            )
1176
            button.grid(row=1, column=1)
1177
            # 最前面に表示し続ける
1178
            self.sub_read_win.attributes("-topmost", True)
1179
            # サイズ変更禁止
1180
            self.sub_read_win.resizable(width=0, height=0)
1181
            self.sub_read_win.title(u'読み上げ')
1182
            self.read_texts = False
1183
1184
    def pyttsx3_onreadend(self):
1185
        """中止するボタンを押したときの処理
1186
1187
        ・中止ボタンを押したときに読み上げをやめ、中止ウインドウ
1188
        を削除する。
1189
1190
        """
1191
        self.engine.stop()
1192
        self.engine.endLoop()
1193
        self.sub_read_win.destroy()
1194
        self.text.tag_remove('sel', '1.0', 'end')
1195
1196
    def pyttsx3_onend(self, name, completed):
1197
        """文章を読み終えた時の処理
1198
1199
        ・文章を読み終えたら中止ウインドウを削除する。
1200
1201
        Args:
1202
            name (str): 読み上げに関連付けられた名前
1203
            completed (bool): 文章が読み上げ終わった(True)
1204
1205
        """
1206
        self.engine.stop()
1207
        self.engine.endLoop()
1208
        self.sub_read_win.destroy()
1209
        self.text.tag_remove('sel', '1.0', 'end')
1210
1211
    def is_hiragana(self, char):
1212
        """文字がひらがなか判断
1213
1214
        ・与えられた文字がひらがなかどうか判断する。
1215
1216
        Args:
1217
            char (str): 判断する文字
1218
1219
        Returns:
1220
            bool: ひらがなならTrue、違うならFalse
1221
1222
        """
1223
        return (0x3040 < ord(char) < 0x3097)
1224
1225
    def ruby(self, event=None):
1226
        """ルビをふる
1227
1228
        ・選択文字列に小説家になろうのルビを振る。
1229
1230
        Args:
1231
            event (instance): tkinter.Event のインスタンス
1232
1233
        """
1234
        hon = ""
1235
        # 選択文字列を切り取る
1236
        set_ruby = self.text.get('sel.first', 'sel.last')
1237
        # 選択文字列を削除する
1238
        self.text.delete('sel.first', 'sel.last')
1239
        # 形態素解析を行う
1240
        for token in tokenizer.tokenize(set_ruby):
0 ignored issues
show
introduced by
The variable tokenizer does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
1241
            # ルビの取得
1242
            ruby = ""
1243
            ruby = jaconv.kata2hira(token.reading)
1244
            # 解析している文字のひらがなの部分を取得
1245
            hira = ""
1246
            for i in token.surface:
1247
                if self.is_hiragana(i):
1248
                    hira += i
1249
            # ルビがないときと、記号の時の処理
1250
            if ruby.replace(
1251
                hira, ''
1252
            ) == "" or token.part_of_speech.split(
1253
                ","
1254
            )[0] == u"記号":
1255
                hon += token.surface
1256
            else:
1257
                # ルビ振りを行う
1258
                hon += "|{0}≪{1}≫{2}".format(
1259
                    token.surface.replace(hira, ''),
1260
                    ruby.replace(hira, ''),
1261
                    hira
1262
                )
1263
1264
        # テキストを表示する
1265
        self.text.insert('insert', hon)
1266
1267
    def redo(self, event=None):
1268
        """Redo
1269
1270
        ・Redo処理を行う。
1271
1272
        Args:
1273
            event (instance): tkinter.Event のインスタンス
1274
1275
        """
1276
        self.text.edit_redo()
1277
1278
    def undo(self, event=None):
1279
        """Undo
1280
1281
        ・Uedo処理を行う。
1282
1283
        Args:
1284
            event (instance): tkinter.Event のインスタンス
1285
1286
        """
1287
        self.text.edit_undo()
1288
1289
    def copy(self, event=None):
1290
        """Copy
1291
1292
        ・Copy処理を行う。
1293
1294
        Args:
1295
            event (instance): tkinter.Event のインスタンス
1296
1297
        """
1298
        self.clipboard_clear()
1299
        self.clipboard_append(self.text.selection_get())
1300
1301
    def cut(self, event=None):
1302
        """Cut
1303
1304
        ・Cut処理を行う。
1305
1306
        Args:
1307
            event (instance): tkinter.Event のインスタンス
1308
1309
        """
1310
        self.copy()
1311
        self.text.delete("sel.first", "sel.last")
1312
1313
    def paste(self, event=None):
1314
        """Paste
1315
1316
        ・Paste処理を行う。
1317
1318
        Args:
1319
            event (instance): tkinter.Event のインスタンス
1320
1321
        """
1322
        self.text.insert('insert', self.clipboard_get())
1323
1324
    def moji_count(self, event=None):
1325
        """文字数と行数を表示する
1326
1327
        ・文字数と行数をカウントして表示する。
1328
1329
        Args:
1330
            event (instance): tkinter.Event のインスタンス
1331
1332
        """
1333
        # 行数の取得
1334
        new_line = int(self.text.index('end-1c').split('.')[0])
1335
        # 文字列の取得
1336
        moji = self.text.get('1.0', 'end')
1337
        # 20文字で区切ったときの行数を数える
1338
        gen_mai = 0
1339
        for val in moji.splitlines():
1340
            gen_mai += len(textwrap.wrap(val, 20))
1341
        # メッセージボックスの表示
1342
        messagebox.showinfo(
1343
            u"文字数と行数、原稿用紙枚数", "文字数 :{0}文字 行数 : {1}行"
1344
            u"\n 原稿用紙 : {2}枚".format(
1345
                len(moji)-new_line,
1346
                new_line,
1347
                -(-gen_mai//20)))
1348
1349
    def new_file(self):
1350
        """新規作成をするための準備
1351
1352
        ・ファイルの新規作成をするための準備処理をおこなう。
1353
1354
        """
1355
        self.initialize()
1356
        for val in tree_folder:
0 ignored issues
show
introduced by
The variable tree_folder does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
1357
            self.tree.delete(val[0])
1358
1359
        # ツリービューを表示する
1360
        self.tree_get_loop()
1361
        self.frame()
1362
        self.winfo_toplevel().title(u"小説エディタ")
1363
        # テキストを読み取り専用にする
1364
        self.text.configure(state='disabled')
1365
        # テキストにフォーカスを当てる
1366
        self.text.focus()
1367
1368
    def new_open(self, event=None):
1369
        """新規作成
1370
1371
        ・変更があれば、ファイル保存するか尋ねて、新規作成する。
1372
1373
        Args:
1374
            event (instance): tkinter.Event のインスタンス
1375
1376
        """
1377
        if not self.text.get('1.0', 'end - 1c') == self.text_text:
1378
            if messagebox.askokcancel(
1379
                u"小説エディタ",
1380
                u"上書き保存しますか?"
1381
            ):
1382
                self.overwrite_save_file()
1383
                self.new_file()
1384
1385
            elif messagebox.askokcancel(u"小説エディタ", u"今の編集を破棄して新規作成しますか?"):
1386
                self.new_file()
1387
        else:
1388
            self.new_file()
1389
1390
    def overwrite_save_file(self, event=None):
1391
        """上書き保存処理
1392
1393
        ・上書き保存するための処理。ファイルがあれば保存して、
1394
        なければ保存ダイアログを出す。
1395
1396
        Args:
1397
            event (instance): tkinter.Event のインスタンス
1398
1399
        """
1400
        # ファイルパスが存在するとき
1401
        if not self.file_path == "":
1402
            # 編集中のファイルを保存する
1403
            self.open_file_save(self.now_path)
1404
            # zipファイルにまとめる
1405
            shutil.make_archive(self.file_path, "zip", "./data")
1406
            # 拡張子の変更を行う
1407
            shutil.move(
1408
                "{0}.zip".format(self.file_path),
1409
                "{0}.ned".format(self.file_path)
1410
            )
1411
        # ファイルパスが存在しないとき
1412
        else:
1413
            # 保存ダイアログを開く
1414
            self.save_file()
1415
1416
    def save_file(self, event=None):
1417
        """ファイルを保存処理
1418
1419
        ・ファイルを保存する。ファイル保存ダイアログを作成し保存をおこなう。
1420
1421
        Args:
1422
            event (instance): tkinter.Event のインスタンス
1423
1424
        """
1425
        # ファイル保存ダイアログを表示する
1426
        fTyp = [(u"小説エディタ", ".ned")]
1427
        iDir = os.path.abspath(os.path.dirname(__file__))
1428
        filepath = filedialog.asksaveasfilename(
1429
            filetypes=fTyp,
1430
            initialdir=iDir
1431
        )
1432
        # ファイルパスが決まったとき
1433
        if not filepath == "":
1434
            # 拡張子を除いて保存する
1435
            self.file_path, ___ = os.path.splitext(filepath)
1436
            # 上書き保存処理
1437
            self.overwrite_save_file()
1438
1439
    def open_file(self, event=None):
1440
        """ファイルを開く処理
1441
1442
        ・ファイルを開くダイアログを作成しファイルを開く。
1443
1444
        Args:
1445
            event (instance): tkinter.Event のインスタンス
1446
1447
        """
1448
        # ファイルを開くダイアログを開く
1449
        fTyp = [(u'小説エディタ', '*.ned')]
1450
        iDir = os.path.abspath(os.path.dirname(__file__))
1451
        filepath = filedialog.askopenfilename(
1452
            filetypes=fTyp,
1453
            initialdir=iDir
1454
        )
1455
        # ファイル名があるとき
1456
        if not filepath == "":
1457
            # 初期化する
1458
            self.initialize()
1459
            # ファイルを開いてdataフォルダに入れる
1460
            with zipfile.ZipFile(filepath) as existing_zip:
1461
                existing_zip.extractall('./data')
1462
            # ツリービューを削除する
1463
            for val in tree_folder:
0 ignored issues
show
introduced by
The variable tree_folder does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
1464
                self.tree.delete(val[0])
1465
1466
            # ツリービューを表示する
1467
            self.tree_get_loop()
1468
            # ファイルパスを拡張子抜きで表示する
1469
            filepath, ___ = os.path.splitext(filepath)
1470
            self.file_path = filepath
1471
            self.now_path = ""
1472
            # テキストビューを新にする
1473
            self.frame()
1474
1475
    def tree_get_loop(self):
1476
        """ツリービューに挿入
1477
1478
        ・保存データからファイルを取得してツリービューに挿入する。
1479
1480
        """
1481
        for val in tree_folder:
0 ignored issues
show
introduced by
The variable tree_folder does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
1482
            self.tree.insert('', 'end', val[0], text=val[1])
1483
            # フォルダのファイルを取得
1484
            path = "./{0}".format(val[0])
1485
            files = os.listdir(path)
1486
            for filename in files:
1487
                if os.path.splitext(filename)[1] == ".txt":
1488
                    self.tree.insert(
1489
                        val[0],
1490
                        'end',
1491
                        text=os.path.splitext(filename)[0]
1492
                    )
1493
1494
    def find_dialog(self, event=None):
1495
        """検索ダイアログを作成
1496
1497
        ・検索ダイアログを作成する。
1498
1499
        Args:
1500
            event (instance): tkinter.Event のインスタンス
1501
1502
        """
1503
        search_win = tk.Toplevel(self)
1504
        self.text_var = ttk.Entry(search_win, width=40)
1505
        self.text_var.grid(
1506
            row=0,
1507
            column=0,
1508
            columnspan=2,
1509
            padx=5,
1510
            pady=5,
1511
            sticky=tk.W+tk.E,
1512
            ipady=3
1513
        )
1514
        button = ttk.Button(
1515
            search_win,
1516
            text=u'検索',
1517
            width=str(u'検索'),
1518
            padding=(10, 5),
1519
            command=self.search
1520
        )
1521
        button.grid(row=1, column=0)
1522
        button2 = ttk.Button(
1523
            search_win,
1524
            text=u'昇順検索',
1525
            width=str(u'昇順検索'),
1526
            padding=(10, 5),
1527
            command=self.search_forward
1528
        )
1529
        button2.grid(row=1, column=1)
1530
        # 最前面に表示し続ける
1531
        search_win.attributes("-topmost", True)
1532
        search_win.title(u'検索')
1533
        self.text_var.focus()
1534
1535
    def replacement_dialog(self, event=None):
1536
        """置換ダイアログを作成
1537
1538
        ・置換ダイアログを作成する。
1539
1540
        Args:
1541
            event (instance): tkinter.Event のインスタンス
1542
1543
        """
1544
        self.replacement_win = tk.Toplevel(self)
1545
        self.text_var = ttk.Entry(self.replacement_win, width=40)
1546
        self.text_var.grid(
1547
            row=0,
1548
            column=0,
1549
            columnspan=2,
1550
            padx=5,
1551
            pady=5,
1552
            sticky=tk.W+tk.E,
1553
            ipady=3
1554
        )
1555
        self.replacement_var = ttk.Entry(self.replacement_win, width=40)
1556
        self.replacement_var.grid(
1557
            row=1,
1558
            column=0,
1559
            columnspan=2,
1560
            padx=5,
1561
            pady=5,
1562
            sticky=tk.W+tk.E,
1563
            ipady=3
1564
        )
1565
        button = ttk.Button(
1566
            self.replacement_win,
1567
            text=u'検索',
1568
            width=str(u'検索'),
1569
            padding=(10, 5),
1570
            command=self.search
1571
        )
1572
        button.grid(row=2, column=0)
1573
        button2 = ttk.Button(
1574
            self.replacement_win,
1575
            text=u'置換',
1576
            width=str(u'置換'),
1577
            padding=(10, 5),
1578
            command=self.replacement
1579
        )
1580
        button2.grid(row=2, column=1)
1581
        # 最前面に表示し続ける
1582
        self.replacement_win.attributes("-topmost", True)
1583
        self.replacement_win.title(u'置換')
1584
        self.text_var.focus()
1585
        # ウインドウが閉じられたときの処理
1586
        self.replacement_win.protocol(
1587
            "WM_DELETE_WINDOW",
1588
            self.replacement_dialog_on_closing
1589
            )
1590
1591
    def replacement_dialog_on_closing(self):
1592
        """検索ウインドウが閉じられたときの処理
1593
1594
        ・検索ダイアログが閉じられたことがわかるようにする。
1595
1596
        """
1597
        self.replacement_dialog = 0
1598
        self.replacement_win.destroy()
1599
1600
    def search(self, event=None):
1601
        """検索処理
1602
1603
        ・検索処理をする。空欄なら処理しない、違うなら最初から、
1604
        同じなら次のを検索する。
1605
1606
        Args:
1607
            event (instance): tkinter.Event のインスタンス
1608
1609
        """
1610
        # 現在選択中の部分を解除
1611
        self.text.tag_remove('sel', '1.0', 'end')
1612
1613
        # 現在検索ボックスに入力されてる文字
1614
        now_text = self.text_var.get()
1615 View Code Duplication
        if not now_text:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1616
            # 空欄だったら処理しない
1617
            pass
1618
        elif now_text != self.last_text:
1619
            # 前回の入力と違う文字なら、検索を最初から行う
1620
            index = '0.0'
1621
            self.search_next(now_text, index, 0)
1622
        else:
1623
            # 前回の入力と同じなら、検索の続きを行う
1624
            self.search_next(now_text, self.next_pos, 1)
1625
1626
        # 今回の入力を、「前回入力文字」にする
1627
        self.last_text = now_text
1628
1629
    def replacement(self, event=None):
1630
        """置換処理
1631
1632
        ・置換処理をする。空欄なら処理しない、違うなら初めから、
1633
        同じなら次を検索する。
1634
1635
        Args:
1636
            event (instance): tkinter.Event のインスタンス
1637
1638
        """
1639
        # 現在選択中の部分を解除
1640
        self.text.tag_remove('sel', '1.0', 'end')
1641
1642
        # 現在検索ボックスに入力されてる文字
1643
        now_text = self.text_var.get()
1644
        replacement_text = self.replacement_var.get()
1645
        if not now_text or not replacement_text:
1646
            # 空欄だったら処理しない
1647
            pass
1648
        elif now_text != self.last_text:
1649
            # 前回の入力と違う文字なら、検索を最初から行う
1650
            self.replacement_dialog = 1
1651
            index = '0.0'
1652
            self.search_next(now_text, index, 0)
1653
        else:
1654
            # 前回の入力と同じなら、検索の続きを行う
1655
            self.replacement_dialog = 1
1656
            # 検索文字の置換を行なう
1657
            start = self.next_pos
1658
            end = '{0} + {1}c'.format(self.next_pos, len(now_text))
1659
            self.text.delete(start, end)
1660
            self.text.insert(start, replacement_text)
1661
            self.search_next(now_text, self.next_pos, 1)
1662
1663
        # 今回の入力を、「前回入力文字」にする
1664
        self.last_text = now_text
1665
1666
    def search_forward(self, event=None):
1667
        """昇順検索処理
1668
1669
        ・昇順検索をする。空欄なら処理しない、違うなら初めから、
1670
        同じなら次を検索する。
1671
1672
        Args:
1673
            event (instance): tkinter.Event のインスタンス
1674
1675
        """
1676
        # 現在選択中の部分を解除
1677
        self.text.tag_remove('sel', '1.0', 'end')
1678
1679
        # 現在検索ボックスに入力されてる文字
1680
        now_text = self.text_var.get()
1681 View Code Duplication
        if not now_text:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1682
            # 空欄だったら処理しない
1683
            pass
1684
        elif now_text != self.last_text:
1685
            # 前回の入力と違う文字なら、検索を最初から行う
1686
            index = 'end'
1687
            self.search_next(now_text, index, 2)
1688
        else:
1689
            # 前回の入力と同じなら、検索の続きを行う
1690
            self.search_next(now_text, self.next_pos, 2)
1691
1692
        # 今回の入力を、「前回入力文字」にする
1693
        self.last_text = now_text
1694
1695
    def search_next(self, search, index, case):
1696
        """検索のメイン処理
1697
1698
        ・検索できれば選択をする。できなければ、ダイアログを出して終了。
1699
1700
        Args:
1701
            search (str): 検索文字列
1702
            index (str): 検索位置 ex. (1.0)
1703
            case (int): 0.初めから検索 1.次に検索 2.昇順検索
1704
1705
        """
1706
        if case == 2:
1707
            backwards = True
1708
            stopindex = '0.0'
1709
            index = '{0}'.format(index)
1710
        elif case == 0:
1711
            backwards = False
1712
            stopindex = 'end'
1713
            index = '{0}'.format(index)
1714
        else:
1715
            backwards = False
1716
            stopindex = 'end'
1717
            index = '{0} + 1c'.format(index)
1718
1719
        pos = self.text.search(
1720
            search, index,
1721
            stopindex=stopindex,
1722
            backwards=backwards
1723
        )
1724
        if not pos:
1725
            if case == 2:
1726
                index = "end"
1727
            else:
1728
                index = "0.0"
1729
1730
            pos = self.text.search(
1731
                search, index,
1732
                stopindex=stopindex,
1733
                backwards=backwards
1734
            )
1735
            if not pos:
1736
                messagebox.showinfo(
1737
                    "検索",
1738
                    "最後まで検索しましたが検索文字はありませんでした。"
1739
                )
1740
                self.replacement_dialog = 0
1741
                return
1742
1743
        self.next_pos = pos
1744
        start = pos
1745
        end = '{0} + {1}c'.format(pos, len(search))
1746
        self.text.tag_add('sel', start, end)
1747
        self.text.mark_set('insert', start)
1748
        self.text.see('insert')
1749
        self.text.focus()
1750
1751
    def message_window(self, event=None):
1752
        """ツリービューを右クリックしたときの処理
1753
1754
        ・子アイテムならば削除ダイアログを表示する。
1755
        親アイテムならば追加を行う。
1756
1757
        Args:
1758
            event (instance): tkinter.Event のインスタンス
1759
1760
        """
1761
        curItem = self.tree.focus()              # 選択アイテムの認識番号取得
1762
        parentItem = self.tree.parent(curItem)   # 親アイテムの認識番号取得
1763
        # 親アイテムをクリックしたとき
1764
        if self.tree.item(curItem)["text"] == tree_folder[4][1]:
0 ignored issues
show
introduced by
The variable tree_folder does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
1765
            # imageタグを選択したとき
1766
            fTyp = [(u'小説エディタ', '*.gif')]
1767
            iDir = os.path.abspath(os.path.dirname(__file__))
1768
            filepath = filedialog.askopenfilename(
1769
                filetypes=fTyp,
1770
                initialdir=iDir
1771
            )
1772
            # ファイル名があるとき
1773
            if not filepath == "":
1774
                file_name = os.path.splitext(os.path.basename(filepath))[0]
1775
                path = "./{0}/{1}.gif".format(tree_folder[4][0], file_name)
1776
                shutil.copy2(filepath, path)
1777
                self.frame_image()
1778
                path = "./{0}/{1}.txt".format(tree_folder[4][0], file_name)
1779
                tree = self.tree.insert(
1780
                    tree_folder[4][0],
1781
                    'end',
1782
                    text=file_name
1783
                )
1784
                self.tree.see(tree)
1785
                self.tree.selection_set(tree)
1786
                self.tree.focus(tree)
1787
                self.select_list_item = file_name
1788
                self.now_path = path
1789
                f = open(path, 'w', encoding='utf-8')
1790
                self.zoom = 100
1791
                f.write(str(self.zoom))
1792
                f.close()
1793
                self.frame_image()
1794
                self.path_read_image(
1795
                    tree_folder[4][0],
1796
                    file_name,
1797
                    0
1798
                )
1799
1800
        else:
1801
            if str(
1802
                self.tree.item(curItem)["text"]
1803
            ) and (not str(
1804
                    self.tree.item(parentItem)["text"]
1805
                )
1806
            ):
1807
                # サブダイヤログを表示する
1808
                title = u'{0}に挿入'.format(self.tree.item(curItem)["text"])
1809
                dialog = Mydialog(self, "挿入", True, title, False)
1810
                root.wait_window(dialog.sub_name_win)
0 ignored issues
show
introduced by
The variable root does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
1811
                file_name = dialog.txt
1812
                del dialog
1813
                if not file_name == "":
1814
                    self.open_file_save(self.now_path)
1815
                    curItem = self.tree.focus()              # 選択アイテムの認識番号取得
1816
                    text = self.tree.item(curItem)["text"]
1817
                    path = ""
1818
                    # 選択されているフォルダを見つける
1819
                    for val in tree_folder:
1820
                        if text == val[1]:
1821
                            if val[0] == tree_folder[0][0]:
1822
                                self.frame_character()
1823
                                self.txt_yobi_name.insert(tk.END, file_name)
1824
                            else:
1825
                                self.frame()
1826
1827
                            path = "./{0}/{1}.txt".format(val[0], file_name)
1828
                            tree = self.tree.insert(
1829
                                val[0],
1830
                                'end',
1831
                                text=file_name
1832
                            )
1833
                            self.now_path = path
1834
                            break
1835
1836
                    # パスが存在すれば新規作成する
1837
                    if not path == "":
1838
                        f = open(path, 'w', encoding='utf-8')
1839
                        f.write("")
1840
                        f.close()
1841
                        # ツリービューを選択状態にする
1842
                        self.tree.see(tree)
0 ignored issues
show
introduced by
The variable tree does not seem to be defined for all execution paths.
Loading history...
1843
                        self.tree.selection_set(tree)
1844
                        self.tree.focus(tree)
1845
                        self.select_list_item = file_name
1846
                        self.winfo_toplevel().title(
1847
                            u"小説エディタ\\{0}\\{1}"
1848
                            .format(text, file_name)
1849
                        )
1850
                        self.text.focus()
1851
                        # テキストを読み取り専用を解除する
1852
                        self.text.configure(state='normal')
1853
                        self.create_tags()
1854
            # 子アイテムを右クリックしたとき
1855
            else:
1856
                if str(self.tree.item(curItem)["text"]):
1857
                    # 項目を削除する
1858
                    file_name = self.tree.item(curItem)["text"]
1859
                    text = self.tree.item(parentItem)["text"]
1860
                    # OK、キャンセルダイアログを表示し、OKを押したとき
1861
                    if messagebox.askokcancel(
1862
                        u"項目削除",
1863
                        "{0}を削除しますか?".format(file_name)
1864
                    ):
1865
                        # パスを取得する
1866
                        for val in tree_folder:
1867
                            if text == val[1]:
1868
                                path = "./{0}/{1}.txt".format(
1869
                                    val[0],
1870
                                    file_name
1871
                                )
1872
                                image_path = "./{0}/{1}.gif".format(
1873
                                    val[0],
1874
                                    file_name
1875
                                )
1876
                                self.tree.delete(curItem)
1877
                                self.now_path = ""
1878
                                break
1879
                        # imageパスが存在したとき
1880
                        if os.path.isfile(image_path):
0 ignored issues
show
introduced by
The variable image_path does not seem to be defined for all execution paths.
Loading history...
1881
                            os.remove(image_path)
1882
1883
                        # パスが存在したとき
1884
                        if not path == "":
0 ignored issues
show
introduced by
The variable path does not seem to be defined for all execution paths.
Loading history...
1885
                            os.remove(path)
1886
                            self.frame()
1887
                            self.text.focus()
1888
1889
    def save_charactor_file(self):
1890
        """キャラクターファイルの保存準備
1891
1892
        ・それぞれの項目をxml形式で保存する。
1893
1894
        """
1895
        return '<?xml version="1.0"?>\n<data>\n\t<call>{0}</call>\
1896
        \n\t<name>{1}</name>\n\t<sex>{2}</sex>\n\t<birthday>{3}</birthday>\
1897
        \n\t<body>{4}</body>\n</data>'.format(
1898
            self.txt_yobi_name.get(),
1899
            self.txt_name.get(),
1900
            self.var.get(),
1901
            self.txt_birthday.get(),
1902
            self.text_body.get(
1903
                '1.0',
1904
                'end -1c'
1905
            )
1906
        )
1907
1908
    def open_file_save(self, path):
1909
        """開いてるファイルを保存する
1910
1911
        ・開いてるファイルをそれぞれの保存形式で保存する。
1912
1913
        Args:
1914
            path (str): 保存ファイルのパス
1915
1916
        """
1917
        # 編集ファイルを保存する
1918
        if not path == "":
1919
            f = open(path, 'w', encoding='utf-8')
1920
            if not path.find(tree_folder[0][0]) == -1:
0 ignored issues
show
introduced by
The variable tree_folder does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
1921
                f.write(self.save_charactor_file())
1922
                self.charactor_file = ""
1923
            elif not path.find(tree_folder[4][0]) == -1:
1924
                f.write(str(self.zoom))
1925
            else:
1926
                f.write(self.text.get("1.0", tk.END+'-1c'))
1927
1928
            f.close()
1929
            self.now_path = path
1930
1931
    def on_double_click(self, event=None):
1932
        """ツリービューをダブルクリック
1933
1934
        ・ファイルを保存して閉じて、選択されたアイテムを表示する。
1935
1936
        Args:
1937
            event (instance): tkinter.Event のインスタンス
1938
1939
        """
1940
        curItem = self.tree.focus()              # 選択アイテムの認識番号取得
1941
        parentItem = self.tree.parent(curItem)   # 親アイテムの認識番号取得
1942
        text = self.tree.item(parentItem)["text"]
1943
        # 開いているファイルを保存
1944
        self.open_file_save(self.now_path)
1945
        # テキストを読み取り専用を解除する
1946
        self.frame()
1947
        self.text.configure(state='disabled')
1948
        # 条件によって分離
1949
        self.select_list_item = self.tree.item(curItem)["text"]
1950
        path = ""
1951
        for val in tree_folder:
0 ignored issues
show
introduced by
The variable tree_folder does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
1952
            if text == val[1]:
1953
                if val[0] == tree_folder[4][0]:
1954
                    path = "./{0}/{1}.txt".format(
1955
                        val[0],
1956
                        self.select_list_item
1957
                    )
1958
                    f = open(path, 'r', encoding='utf-8')
1959
                    zoom = f.read()
1960
                    self.zoom = int(zoom)
1961
                    self.now_path = path
1962
                    self.frame_image()
1963
                    self.path_read_image(
1964
                        tree_folder[4][0],
1965
                        self.select_list_item,
1966
                        self.zoom
1967
                    )
1968
                else:
1969
                    path = "./{0}/{1}.txt".format(
1970
                        val[0],
1971
                        self.select_list_item
1972
                    )
1973
                    self.now_path = path
1974
                    if val[0] == tree_folder[0][0]:
1975
                        self.frame_character()
1976
                    else:
1977
                        # テキストを読み取り専用を解除する
1978
                        self.text.configure(state='normal')
1979
                        self.text.focus()
1980
1981
                    self.path_read_text(text, self.select_list_item)
1982
1983
                return
1984
1985
        self.now_path = ""
1986
        self.winfo_toplevel().title(u"小説エディタ")
1987
1988
    def path_read_image(self, image_path, image_name, scale):
1989
        """イメージを読み込んで表示
1990
1991
        ・パスが存在すればイメージファイルを読み込んで表示する。
1992
1993
        Args:
1994
            image_path (str): イメージファイルの相対パス
1995
            image_name (str): イメージファイルの名前
1996
            scale (int): 拡大率(%)
1997
1998
        """
1999
        if not self.now_path == "":
2000
            title = "{0}/{1}.gif".format(
2001
                image_path,
2002
                image_name
2003
            )
2004
            giffile = Image.open(title)
2005
            if scale > 0:
2006
                giffile = giffile.resize(
2007
                    (
2008
                        int(giffile.width / 100*scale),
2009
                        int(giffile.height / 100*scale)
2010
                    ),
2011
                    resample=Image.LANCZOS
2012
                )
2013
2014
            self.image_space.photo = ImageTk.PhotoImage(giffile)
2015
            self.image_space.itemconfig(
2016
                self.image_on_space,
2017
                image=self.image_space.photo
2018
            )
2019
            # イメージサイズにキャンバスサイズを合わす
2020
            self.image_space.config(
2021
                scrollregion=(
2022
                    0,
2023
                    0,
2024
                    giffile.size[0],
2025
                    giffile.size[1]
2026
                )
2027
            )
2028
            giffile.close()
2029
2030
        self.winfo_toplevel().title(
2031
                u"小説エディタ\\{0}\\{1}".format(tree_folder[4][1], image_name)
0 ignored issues
show
introduced by
The variable tree_folder does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
2032
            )
2033
2034
    def path_read_text(self, text_path, text_name):
2035
        """テキストを読み込んで表示
2036
2037
        ・パスが存在すればテキストを読み込んで表示する。
2038
2039
        Args:
2040
            text_path (str): テキストファイルの相対パス
2041
            text_name (str): テキストファイルの名前
2042
2043
        """
2044
        if not self.now_path == "":
2045
            if not self.now_path.find(tree_folder[0][0]) == -1:
0 ignored issues
show
introduced by
The variable tree_folder does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
2046
                self.txt_yobi_name.delete('0', tk.END)
2047
                self.txt_name.delete('0', tk.END)
2048
                self.txt_birthday.delete('0', tk.END)
2049
                self.text_body.delete('1.0', tk.END)
2050
                tree = ET.parse(self.now_path)
2051
                elem = tree.getroot()
2052
                self.txt_yobi_name.insert(tk.END, elem.findtext("call"))
2053
                self.txt_name.insert(tk.END, elem.findtext("name"))
2054
                self.var.set(elem.findtext("sex"))
2055
                self.txt_birthday.insert(tk.END, elem.findtext("birthday"))
2056
                self.text_body.insert(tk.END, elem.findtext("body"))
2057
                title = "{0}/{1}.gif".format(
2058
                    tree_folder[0][0],
2059
                    elem.findtext("call")
2060
                )
2061
                if os.path.isfile(title):
2062
                    self.print_gif(title)
2063
            else:
2064
                self.text.delete('1.0', tk.END)
2065
                f = open(self.now_path, 'r', encoding='utf-8')
2066
                self.text_text = f.read()
2067
                self.text.insert(tk.END, self.text_text)
2068
                f.close()
2069
2070
            self.winfo_toplevel().title(
2071
                u"小説エディタ\\{0}\\{1}".format(text_path, text_name)
2072
            )
2073
            # シンタックスハイライトをする
2074
            self.all_highlight()
2075
2076
    def on_name_click(self, event=None):
2077
        """名前の変更
2078
2079
        ・リストボックスの名前を変更する。
2080
2081
        Args:
2082
            event (instance): tkinter.Event のインスタンス
2083
2084
        """
2085
        curItem = self.tree.focus()              # 選択アイテムの認識番号取得
2086
        parentItem = self.tree.parent(curItem)   # 親アイテムの認識番号取得
2087
        text = self.tree.item(parentItem)["text"]
2088
        if not text == "":
2089
            sub_text = self.tree.item(curItem)["text"]
2090
            title = u'{0}の名前を変更'.format(sub_text)
2091
            dialog2 = Mydialog(self, u"変更", True, title, sub_text)
2092
            root.wait_window(dialog2.sub_name_win)
0 ignored issues
show
introduced by
The variable root does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
2093
            # テキストを読み取り専用を解除する
2094
            self.text.configure(state='normal')
2095
            co_text = dialog2.txt
2096
            del dialog2
2097
            for val in tree_folder:
0 ignored issues
show
introduced by
The variable tree_folder does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
2098
                if text == val[1]:
2099
                    path1 = "./{0}/{1}.txt".format(val[0], sub_text)
2100
                    path2 = "./{0}/{1}.txt".format(val[0], co_text)
2101
                    self.now_path = path2
2102
                    # テキストの名前を変更する
2103
                    os.rename(path1, path2)
2104
                    self.tree.delete(curItem)
2105
                    Item = self.tree.insert(parentItem, 'end', text=co_text)
2106
                    self.tree.selection_set(Item)
2107
                    self.path_read_text(val[0], co_text)
2108
                    return
2109
2110
    def update_line_numbers(self, event=None):
2111
        """行番号の描画
2112
2113
        ・行番号をつけて表示する。
2114
2115
        Args:
2116
            event (instance): tkinter.Event のインスタンス
2117
2118
        """
2119
        # 現在の行番号を全て消す
2120
        self.line_numbers.delete(tk.ALL)
2121
2122
        # Textの0, 0座標、つまり一番左上が何行目にあたるかを取得
2123
        i = self.text.index("@0,0")
2124
        while True:
2125
            # dlineinfoは、その行がどの位置にあり、どんなサイズか、を返す
2126
            # (3, 705, 197, 13, 18) のように帰る(x,y,width,height,baseline)
2127
            dline = self.text.dlineinfo(i)
2128
            # dlineinfoに、存在しない行や、スクロールしないと見えない行を渡すとNoneが帰る
2129
            if dline is None:
2130
                break
2131
            else:
2132
                y = dline[1]  # y座標を取得
2133
2134
            # (x座標, y座標, 方向, 表示テキスト)を渡して行番号のテキストを作成
2135
            linenum = str(i).split(".")[0]
2136
            self.line_numbers.create_text(
2137
                3,
2138
                y,
2139
                anchor=tk.NW,
2140
                text=linenum,
2141
                font=("", 12)
2142
            )
2143
            i = self.text.index("%s+1line" % i)
2144
2145
    def change_setting(self, event=None):
2146
        """テキストの変更時
2147
2148
        ・テキストを変更したときに行番号とハイライトを変更する。
2149
2150
        Args:
2151
            event (instance): tkinter.Event のインスタンス
2152
2153
        """
2154
        self.update_line_numbers()
2155
        # その行のハイライトを行う
2156
        self.line_highlight()
2157
2158
    def tab(self, event=None):
2159
        """タブ押下時の処理
2160
2161
        ・タブキーを押したときに補完リストを出す。
2162
2163
        Args:
2164
            event (instance): tkinter.Event のインスタンス
2165
2166
        """
2167
        # 文字を選択していないとき
2168
        sel_range = self.text.tag_ranges('sel')
2169
        if not sel_range:
2170
            return self.auto_complete()
2171
        else:
2172
            return
2173
2174
    def auto_complete(self):
2175
        """補完リストの設定
2176
2177
        ・補完リストの設定をする。
2178
2179
        """
2180
        auto_complete_list = tk.Listbox(self.text)
2181
        # エンターでそのキーワードを選択
2182
        auto_complete_list.bind('<Return>', self.selection)
2183
        auto_complete_list.bind('<Double-1>', self.selection)
2184
        # エスケープ、タブ、他の場所をクリックで補完リスト削除
2185
        auto_complete_list.bind('<Escape>', self.remove_list)
2186
        auto_complete_list.bind('<Tab>', self.remove_list)
2187
        auto_complete_list.bind('<FocusOut>', self.remove_list)
2188
        # (x,y,width,height,baseline)
2189
        x, y, width, height, _ = self.text.dlineinfo(
2190
            'insert'
2191
        )
2192
        # 現在のカーソル位置のすぐ下に補完リストを貼る
2193
        auto_complete_list.place(x=x+width, y=y+height)
2194
        # 補完リストの候補を作成
2195
        for word in self.get_keywords():
2196
            auto_complete_list.insert(tk.END, word)
2197
2198
        # 補完リストをフォーカスし、0番目を選択している状態に
2199
        auto_complete_list.focus_set()
2200
        auto_complete_list.selection_set(0)
2201
        self.auto_complete_list = auto_complete_list  # self.でアクセスできるように
2202
        return 'break'
2203
2204
    def get_keywords(self):
2205
        """補完リストの候補キーワードを作成
2206
2207
        ・補完リストに表示するキーワードを得る。
2208
2209
        """
2210
        text = ''
2211
        text, _, _ = self.get_current_insert_word()
2212
        my_func_and_class = set()
2213
        # コード補完リストをTreeviewにある'名前'から得る
2214
        children = self.tree.get_children('data/character')
2215
        for child in children:
2216
            childname = self.tree.item(child, "text")
2217
            # 前列の文字列と同じものを選び出す
2218
            if childname.startswith(text) or childname.startswith(
2219
                text.title()
2220
            ):
2221
                my_func_and_class.add(childname)
2222
2223
        result = list(my_func_and_class)
2224
        return result
2225
2226
    def remove_list(self, event=None):
2227
        """補完リストの削除処理
2228
2229
        ・補完リストを削除し、テキストボックスにフォーカスを戻す。
2230
2231
        Args:
2232
            event (instance): tkinter.Event のインスタンス
2233
2234
        """
2235
        self.auto_complete_list.destroy()
2236
        self.text.focus()  # テキストウィジェットにフォーカスを戻す
2237
2238
    def selection(self, event=None):
2239
        """補完リストでの選択後の処理
2240
2241
        ・補完リストを選択したときにその文字を入力する。
2242
2243
        Args:
2244
            event (instance): tkinter.Event のインスタンス
2245
2246
        """
2247
        # リストの選択位置を取得
2248
        select_index = self.auto_complete_list.curselection()
2249
        if select_index:
2250
            # リストの表示名を取得
2251
            value = self.auto_complete_list.get(select_index)
2252
2253
            # 現在入力中の単語位置の取得
2254
            _, start, end = self.get_current_insert_word()
2255
            self.text.delete(start, end)
2256
            self.text.insert('insert', value)
2257
            self.remove_list()
2258
2259
    def get_current_insert_word(self):
2260
        """現在入力中の単語と位置を取得
2261
2262
        ・現在入力している単語とその位置を取得する。
2263
2264
        """
2265
        text = ''
2266
        start_i = 1
2267
        end_i = 0
2268
        while True:
2269
            start = 'insert-{0}c'.format(start_i)
2270
            end = 'insert-{0}c'.format(end_i)
2271
            text = self.text.get(start, end)
2272
            # 1文字ずつ見て、スペース、改行、タブ、空文字、句読点にぶつかったら終わり
2273
            if text in (' ', ' ', '\t', '\n', '', '、', '。'):
2274
                text = self.text.get(end, 'insert')
2275
2276
                # 最終単語を取得する
2277
                pri = [token.surface for token in tokenizer.tokenize(text)]
0 ignored issues
show
introduced by
The variable tokenizer does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
2278
                hin = [
2279
                    token.part_of_speech.split(',')[0] for token
2280
                    in tokenizer.tokenize(text)
2281
                ]
2282
                if len(pri) > 0:
2283
                    if hin[len(pri)-1] == u'名詞':
2284
                        text = pri[len(pri)-1]
2285
                    else:
2286
                        text = ""
2287
                else:
2288
                    text = ""
2289
2290
                end = 'insert-{0}c'.format(len(text))
2291
                return text, end, 'insert'
2292
2293
            start_i += 1
2294
            end_i += 1
2295
2296
    def yahoocall(self, appid="", sentence=""):
2297
        """yahooの校正支援を呼び出す
2298
2299
        ・Yahoo! 校正支援をClient IDを使って呼び出す。
2300
2301
        Args:
2302
            appid (str): Yahoo! Client ID
2303
            sentence (str): 校正をしたい文字列
2304
2305
        Returns:
2306
            str: 校正結果
2307
2308
        """
2309
        if appid == "":
2310
            messagebox.showerror(
2311
                "Yahoo! Client ID",
2312
                u"Yahoo! Client IDが見つかりません。\n"
2313
                "Readme.pdfを読んで、設定し直してください。"
2314
            )
2315
            return
2316
        url = "https://jlp.yahooapis.jp/KouseiService/V1/kousei"
2317
        data = {
2318
            "appid": appid.rstrip('\n'),
2319
            "sentence": sentence,
2320
        }
2321
        html = requests.post(url, data)
2322
        return html.text
2323
2324
    def yahooresult(self, html):
2325
        """校正支援を表示する画面を制作
2326
2327
        ・校正結果を表示するダイアログを作成する。
2328
2329
        Args:
2330
            html (str): 校正結果
2331
2332
        """
2333
        xml = ET.fromstring(html)
2334
        # サブウインドウの表示
2335
        sub_win = tk.Toplevel(self)
2336
        # ツリービューの表示
2337
        self.yahoo_tree = ttk.Treeview(sub_win)
2338
        self.yahoo_tree["columns"] = (1, 2, 3, 4, 5)
2339
        # 表スタイルの設定(headingsはツリー形式ではない、通常の表形式)
2340
        self.yahoo_tree["show"] = "headings"
2341
        self.yahoo_tree.column(1, width=100)
2342
        self.yahoo_tree.column(2, width=80)
2343
        self.yahoo_tree.column(3, width=75)
2344
        self.yahoo_tree.column(4, width=150)
2345
        self.yahoo_tree.column(5, width=120)
2346
        self.yahoo_tree.heading(1, text="先頭からの文字数")
2347
        self.yahoo_tree.heading(2, text="対象文字数")
2348
        self.yahoo_tree.heading(3, text="対象表記")
2349
        self.yahoo_tree.heading(4, text="言い換え候補文字列")
2350
        self.yahoo_tree.heading(5, text="指摘の詳細情報")
2351
        # 情報を取り出す
2352
        for child in list(xml):
2353
            StartPos = (child.findtext(self.KOUSEI+"StartPos"))
2354
            Length = (child.findtext(self.KOUSEI+"Length"))
2355
            Surface = (child.findtext(self.KOUSEI+"Surface"))
2356
            ShitekiWord = (child.findtext(self.KOUSEI+"ShitekiWord"))
2357
            ShitekiInfo = (child.findtext(self.KOUSEI+"ShitekiInfo"))
2358
            self.yahoo_tree.insert(
2359
                "",
2360
                "end",
2361
                values=(StartPos,
2362
                        Length,
2363
                        Surface,
2364
                        ShitekiWord,
2365
                        ShitekiInfo
2366
                        )
2367
                )
2368
2369
        self.yahoo_tree.grid(row=0, column=0, sticky=(tk.N, tk.S, tk.E, tk.W))
2370
        # スクロールバーを表示する
2371
        SCRLBAR_Y = ttk.Scrollbar(
2372
            sub_win,
2373
            orient=tk.VERTICAL,
2374
            command=self.yahoo_tree.yview
2375
        )
2376
        self.yahoo_tree.configure(yscroll=SCRLBAR_Y.set)
2377
        SCRLBAR_Y.grid(row=0, column=1, sticky=(tk.N, tk.S))
2378
        # 最前面に表示し続ける
2379
        sub_win.attributes("-topmost", True)
2380
        sub_win.title(u'文章校正')
2381
2382
    def yahoo(self, event=None):
2383
        """Yahoo! 校正支援
2384
2385
        ・Yahoo! 校正支援を呼び出し表示する。
2386
2387
        Args:
2388
            event (instance): tkinter.Event のインスタンス
2389
2390
        """
2391
        html = self.yahoocall(
2392
            self.APPID,
2393
            self.text.get('1.0', 'end -1c')
2394
        )
2395
        if not self.APPID == "":
2396
            self.yahooresult(html)
2397
            self.yahoo_tree.bind("<Double-1>", self.on_double_click_yahoo)
2398
2399
    def on_double_click_yahoo(self, event=None):
2400
        """Yahoo! 校正支援リストをダブルクリック
2401
2402
        ・Yahoo! 校正支援ダイアログのリストをダブルクリックすると
2403
        その該当箇所を選択する。
2404
2405
        Args:
2406
            event (instance): tkinter.Event のインスタンス
2407
2408
        """
2409
        curItem = self.yahoo_tree.focus()
2410
        value = self.yahoo_tree.item(curItem)
2411
        i = 0
2412
        textlen = 0
2413
        textforlen = 0
2414
        # 出てくる場所を取得
2415
        val = int(value.get("values")[0])
2416
        # 出てくる文字数を取得
2417
        lenge = value.get("values")[1]
2418
        # 何行目になるか確認する
2419
        while True:
2420
            if val > textlen:
2421
                i += 1
2422
                textforlen = textlen
2423
                textlen += len(
2424
                    self.text.get(
2425
                        '{0}.0'.format(i),
2426
                        '{0}.0'.format(i+1)
2427
                    )
2428
                )
2429
            else:
2430
                break
2431
        if i == 0:
2432
            i = 1
2433
        # 選択状態を一旦削除
2434
        self.text.tag_remove('sel', '1.0', 'end')
2435
        # 選択状態にする
2436
        self.text.tag_add(
2437
            'sel',
2438
            "{0}.{1}".format(i, val-textforlen),
2439
            "{0}.{1}".format(i, val-textforlen+lenge)
2440
        )
2441
        # カーソルの移動
2442
        self.text.mark_set('insert', '{0}.{1}'.format(i, val-textforlen))
2443
        self.text.see('insert')
2444
        # フォーカスを合わせる
2445
        self.text.focus()
2446
        return
2447
2448
2449
def on_closing():
2450
    """終了時の処理
2451
2452
    ・ソフトを閉じるか確認してから閉じる。
2453
2454
    """
2455
    if messagebox.askokcancel(u"小説エディタ", u"終了してもいいですか?"):
2456
        shutil.rmtree("./data")
2457
        if os.path.isfile("./userdic.csv"):
2458
            os.remove("./userdic.csv")
2459
2460
        root.destroy()
0 ignored issues
show
introduced by
The variable root does not seem to be defined in case __name__ == "__main__" on line 2463 is False. Are you sure this can never be the case?
Loading history...
2461
2462
2463
if __name__ == "__main__":
2464
    root = tk.Tk()
2465
    root.withdraw()
2466
    if os.path.isdir("./data"):
2467
        messagebox.showerror(u"小説エディタ", u"二重起動はできません")
2468
        sys.exit()
2469
2470
    # タイトル横の画像ファイルのbase 64データ
2471
    data = '''R0lGODlhgACAAPcAAAAAAAQEBAcHBwkJCQoKCg8PDxAQEBERERMTExUVFRgYGBkZ
2472
        GRoaGhwcHB0dHR4eHh8fHyAgICEhISIiIiMjIyQkJCUlJSYmJicnJygoKCkpKSoq
2473
        KisrKywsLC0tLS4uLi8vLzAwMDExMTIyMjMzMzQ0NDU1NTc3Nzg4ODo6Ojs7Ozw8
2474
        PD4+Pj8/P0BAQEFBQUJCQkNDQ0REREVFRUZGRkdHR0hISElJSUpKSktLS0xMTE1N
2475
        TU5OTk9PT1BQUFJSUlNTU1RUVFVVVVZWVldXV1lZWVpaWltbW1xcXF1dXV5eXl9f
2476
        X2BgYGFhYWJiYmNjY2RkZGVlZWZmZmdnZ2hoaGlpaWpqamtra21tbW5ubm9vb3Bw
2477
        cHFxcXJycnNzc3R0dHV1dXZ2dnd3d3h4eHl5eXp6ent7e3x8fH19fX5+fn9/f4CA
2478
        gIGBgYKCgoODg4SEhIWFhYaGhoeHh4iIiImJiYqKiouLi4yMjI2NjY6Ojo+Pj5CQ
2479
        kJGRkZKSkpOTk5SUlJWVlZaWlpeXl5iYmJmZmZqampubm5ycnJ2dnZ6enp+fn6Cg
2480
        oKGhoaKioqOjo6SkpKWlpaampqenp6ioqKmpqaqqqqurq6ysrK2tra6urq+vr7Cw
2481
        sLGxsbKysrOzs7S0tLW1tba2tre3t7i4uLm5ubq6uru7u7y8vL29vb6+vr+/v8DA
2482
        wMHBwcLCwsPDw8TExMXFxcbGxsfHx8jIyMnJycrKysvLy8zMzM3Nzc7Ozs/Pz9DQ
2483
        0NHR0dLS0tPT09TU1NXV1dbW1tfX19jY2NnZ2dra2tvb29zc3N3d3d7e3t/f3+Dg
2484
        4OHh4eLi4uPj4+Tk5OXl5ebm5ufn5+jo6Onp6erq6uvr6+zs7O3t7e7u7u/v7/Dw
2485
        8PHx8fLy8vPz8/T09PX19fb29vf39/j4+Pn5+fr6+vv7+/z8/P39/f7+/v///wAA
2486
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
2487
        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
2699
        8AzX8A3n8A738A8H8RDP8IAAADs=
2700
        '''
2701
    # アイコンを設定
2702
    root.geometry('600x300')
2703
    root.tk.call('wm', 'iconphoto', root._w, tk.PhotoImage(data=data))
2704
    root.title(u"小説エディタ")
2705
    # タイトルの画像ファイルのbase 64データ
2706
    datas = '''R0lGODlhWAIsAfcAAAAAAQ0AAwAABQAAC0oXCzQMEC0VFBAAFQAAGFIfHQ0KHhIT
2707
        IAAAISQBJgBuJwBuKSUkKgAAKzEbK3hBLTwYLh0bMWAyMYZZMRcAMwEMMw0SM2s/
2708
        M1c5NEooNZdlNYNJNyESODQyOHlIOhcYOxwoO5FTOzw7PTovQQAGQh4NQkwvQqt4
2709
        QwAQRCEgRKJnRC0oSUk/SQAYTHNRTD9DTQcbTj88TpJuUV1KUiIzU1FQU0ZGVDY1
2710
        Vqp6V1dXWahzWVpaWgAcW7eIW3lfXsOXZRElZ2hoaCs2ajVBaxkubD1LbAAibWFg
2711
        bcuccXZzckNSc86hdhlAd6OEeAsze3l6e1BffNWpgX9+gyNFhR5JhjFPhtuwhiBM
2712
        iq6Si+O6jI6Ojl6/j1/AjypUkXFwkZOTk+7Bk5aWljVfl8CSmW97m4aFnNq5nZyb
2713
        n3+/n4DAoDxqoaGhocSpo+XEoy5opKWlpXzTp6ioqHvSqDxsrDBxrICRra6urrW1
2714
        tVl6tse1tsG2t7e3t//ht42Rubm5uUp8u7u7u/XQu/fYu0J4vcu+vlyNv7+/v/rf
2715
        wk6HxMTExMbGxm+bycnJyYChymKWy8zMzKezzeHNzc7Ozs/Pz2eZ0NDQ0P/m0NHR
2716
        0aCu0tTU1P/u1NbW1uPW1oOv2NjY2G6j2nqs2tra2tzc3L+/3d3d3f/13b3/3t/f
2717
        3/Di4Yi44r7H4uPj4+Xl5cX/5f//5ufn58j/53u16Ojo6P/w6erq6v//6uvr6+zs
2718
        7O3t7ZrG7vXr7u7u7v/z7v//7pHD7+/v78XX8PDw8PHx8fLy8v//8rTS8+Do8/Pz
2719
        887c9PT09PX19f/59f/79f//9fb29rng9/f39///9/j4+Pn5+f//+YW++vr6+ubt
2720
        +/v7+///+/z8/P39/f///f7+/v///p7N/6vZ/6Lb/7nh/8Dn/8rp/77v/+fz/9H2
2721
        /9v3//H6//v6/+v8///+/9P//9z//+X//+v//+7///D///P///T///n///r///z/
2722
        //3///7//////wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQAAAAAACwAAAAAWAIs
2723
        AQAI/gBVCRxIsKDBgwZj2XkAhhbChxAjSpxIsaLFixgzatzIsaPHjyBDihxJsqRJ
2724
        jrTAPLAT66RLVQoZOnxJs6bNmzhz6tzJs6fPlylXtvypMWZDokiTKl3KtKnTp02D
2725
        soQa0ehMqlizat3KtatXkVKHfrX6tazZs2jTqr0Z1izZtXDjyp1L12zbsm/r6t3L
2726
        t6/fknfHLjz6t7Dhw4gLB/aaN7Hjx5AjY13ctbHky5gzaz5JmavlzaBDix59sPPW
2727
        z6RTq16d2LRW1Kxjy5691nVW2LRz69791DZW3LyDCx/OVuVUvIOvEl/OvPlI31SB
2728
        O59OvbpB6FClW9/OnTj2p9q7/osfL/u70/Dk06sHbb4p+vXw4ztuz/S9/Pv499Jf
2729
        aj+///9p7adUfwAWaKBWAiZF4IEMNqhUgkgt6OCEFOYEIVESVqjhhoAZJxZjyXEo
2730
        4og6XfhThiSmqKJEJvqE4oowxihQiz29KOONJNLIk4049qihjjvx6OOQDQKpk5BE
2731
        JgmgkQfF4uSTUEYp5ZRS0kKHTFRmqeWWXHbp5ZdghinmmGSWaeaZaKap5ppstunm
2732
        m3CaGRQdtMQZCx145qnnnnz22ecXD3zh56CEFmrooYgmquiijDbq6KOQRirppJRW
2733
        aumlmGaqqaSACrrplQ+EKuqopJZq6qkPOKDqqqy26uqr/rDGKuustNZq66245qrr
2734
        rrz26uuvwAYr7LDEFmvsscSiquyyp37h7LPQRivttNKCAagTbbCh7bbcduvtt+CG
2735
        K+645JZr7rnopqvuuuy26+678MYr77z01mvvvfK24USg1lLr77/S0iLwwAQXbPDB
2736
        B9PhQBv+NOzwwxBHLPHEFFds8cUYZ6zxxhx37PHHIIcs8sgkl2zyySinrPLJbThA
2737
        J8Iwx3ywSwotvPLNOOes88489+zzz0AHLXTKLR8nmM1DJ6300kw37fTTUEfNsgNG
2738
        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
3075
        '''
3076
    img = tk.PhotoImage(data=datas)
3077
    label = tk.Label(image=img)
3078
    # タイトルを表示する
3079
    label.pack()
3080
    # センターに表示する
3081
    root.update_idletasks()
3082
    ww = root.winfo_screenwidth()
3083
    lw = root.winfo_width()
3084
    wh = root.winfo_screenheight()
3085
    lh = root.winfo_height()
3086
    root.geometry(
3087
        "{0}x{1}+{2}+{3}".format(
3088
            str(lw),
3089
            str(lh),
3090
            str(int(ww/2-lw/2)),
3091
            str(int(wh/2-lh/2))
3092
        )
3093
    )
3094
    root.deiconify()
3095
3096
    # windowsのみタイトルバーを削除
3097
    # OS別判断
3098
    if os.name == 'nt':
3099
        root.overrideredirect(True)
3100
    elif os.name == 'posix':
3101
        root.wm_attributes('-type', 'splash')
3102
    # 描画するが処理は止めない
3103
    root.update()
3104
    # Janomeを使って日本語の形態素解析を起動
3105
    tokenizer = Tokenizer()
3106
    wiki_wiki = wikipediaapi.Wikipedia('ja')
3107
    # メイン画面を削除
3108
    root.destroy()
3109
    # 初期処理
3110
    original_image = '''R0lGODlhHgAeAPcAAAAAAAAAMwAAZgAAmQAAzAAA/wAzAAAzMwAzZgAzmQAzzAAz
3111
        /wBmAABmMwBmZgBmmQBmzABm/wCZAACZMwCZZgCZmQCZzACZ/wDMAADMMwDMZgDM
3112
        mQDMzADM/wD/AAD/MwD/ZgD/mQD/zAD//zMAADMAMzMAZjMAmTMAzDMA/zMzADMz
3113
        MzMzZjMzmTMzzDMz/zNmADNmMzNmZjNmmTNmzDNm/zOZADOZMzOZZjOZmTOZzDOZ
3114
        /zPMADPMMzPMZjPMmTPMzDPM/zP/ADP/MzP/ZjP/mTP/zDP//2YAAGYAM2YAZmYA
3115
        mWYAzGYA/2YzAGYzM2YzZmYzmWYzzGYz/2ZmAGZmM2ZmZmZmmWZmzGZm/2aZAGaZ
3116
        M2aZZmaZmWaZzGaZ/2bMAGbMM2bMZmbMmWbMzGbM/2b/AGb/M2b/Zmb/mWb/zGb/
3117
        /5kAAJkAM5kAZpkAmZkAzJkA/5kzAJkzM5kzZpkzmZkzzJkz/5lmAJlmM5lmZplm
3118
        mZlmzJlm/5mZAJmZM5mZZpmZmZmZzJmZ/5nMAJnMM5nMZpnMmZnMzJnM/5n/AJn/
3119
        M5n/Zpn/mZn/zJn//8wAAMwAM8wAZswAmcwAzMwA/8wzAMwzM8wzZswzmcwzzMwz
3120
        /8xmAMxmM8xmZsxmmcxmzMxm/8yZAMyZM8yZZsyZmcyZzMyZ/8zMAMzMM8zMZszM
3121
        mczMzMzM/8z/AMz/M8z/Zsz/mcz/zMz///8AAP8AM/8AZv8Amf8AzP8A//8zAP8z
3122
        M/8zZv8zmf8zzP8z//9mAP9mM/9mZv9mmf9mzP9m//+ZAP+ZM/+ZZv+Zmf+ZzP+Z
3123
        ///MAP/MM//MZv/Mmf/MzP/M////AP//M///Zv//mf//zP///8DAwICAgIAAAACA
3124
        AAAAgICAAIAAgACAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
3125
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
3126
        AAAAAAAAAAAAAAAAACwAAAAAHgAeAAAIMgABCBxIsKDBgwgTKlzIsKHDhxAjSpxI
3127
        saLFixgzatzIsaPHjyBDihxJsqTJkyhTngwIADs=
3128
        '''
3129
    tree_folder = [
3130
        ['data/character', u'キャラクター'],
3131
        ['data/occupation', u'職種'],
3132
        ['data/space', u'場所'],
3133
        ['data/event', u'イベント'],
3134
        ['data/image', u'イメージ'],
3135
        ['data/nobel', u'小説']
3136
    ]
3137
    color = [
3138
        'sky blue',
3139
        'yellow green',
3140
        'gold',
3141
        'salmon',
3142
        'orange',
3143
        'red',
3144
        'hot pink',
3145
        'dark orchid',
3146
        'purple',
3147
        'midnight blue',
3148
        'light slate blue',
3149
        'dodger blue',
3150
        'dark turquoise',
3151
        'cadet blue',
3152
        'maroon',
3153
        'tan1',
3154
        'rosy brown',
3155
        'indian red',
3156
        'orange red',
3157
        'violet red'
3158
    ]
3159
    # 再度メイン画面を作成
3160
    root = tk.Tk()
3161
    # アイコンを設定
3162
    root.tk.call('wm', 'iconphoto', root._w, tk.PhotoImage(data=data))
3163
    # タイトルの表示
3164
    root.title(u"小説エディタ")
3165
    # フレームを表示する
3166
    app = LineFrame(root)
3167
    app.grid(column=0, row=0, sticky=(tk.N, tk.S, tk.E, tk.W))
3168
    # 終了時にon_closingを行う
3169
    root.protocol("WM_DELETE_WINDOW", on_closing)
3170
    root.columnconfigure(0, weight=1)
3171
    root.rowconfigure(0, weight=1)
3172
    pf = platform.system()
3173
    if pf == 'Windows':
3174
        root.state('zoomed')
3175
    else:
3176
        root.attributes("-zoomed", "1")
3177
3178
# テスト環境ではループを抜ける
3179
    value = sys.argv
3180
    if len(value) > 1:
3181
        for arg in value:
3182
            if arg == "test":
3183
                root.update_idletasks()
3184
3185
    else:
3186
        root.mainloop()
3187