Passed
Push — master ( 63399a...705b0f )
by Yoshihiro
02:57
created

NovelEditor.LM   A

Complexity

Total Complexity 37

Size/Duplication

Total Lines 435
Duplicated Lines 0 %

Test Coverage

Coverage 89.05%

Importance

Changes 0
Metric Value
eloc 274
dl 0
loc 435
ccs 179
cts 201
cp 0.8905
rs 9.44
c 0
b 0
f 0
wmc 37

8 Methods

Rating   Name   Duplication   Size   Complexity  
A ListMenuClass.path_read_text() 0 40 4
A ListMenuClass.on_name_click() 0 38 4
A ListMenuClass.__init__() 0 6 1
F ListMenuClass.message_window() 0 150 16
A ListMenuClass.path_read_image() 0 43 3
B ListMenuClass.on_double_click() 0 57 5
A MyDialogClass.sub_name_ok() 0 15 1
A MyDialogClass.__init__() 0 38 3
1
#!/usr/bin/env python3
2 1
import os
3 1
import shutil
4 1
import tkinter as tk
5 1
import tkinter.ttk as ttk
6 1
import tkinter.filedialog as filedialog
7 1
import tkinter.messagebox as messagebox
8 1
import xml.etree.ElementTree as ET
9
10 1
from PIL import Image, ImageTk
11
12
13 1
class ListMenuClass():
14
    """リストメニューバーのクラス.
15
16
    ・リストメニューバーにあるプログラム群
17
18
    Args:
19
        app (instance): MainProcessingClass のインスタンス
20
        master (instance): toplevel のインスタンス
21
        tree_folder (list): ツリーフォルダの配列
22
23
    Attributes:
24
        text_text (str): 現在入力中の初期テキスト
25
        self.select_list_item (str): 選択中のリストボックスアイテム名
26
    """
27 1
    def __init__(self, app, master, tree_folder):
28 1
        self.text_text = ""
29 1
        self.select_list_item = ""
30 1
        self.APP = app
31 1
        self.MASTER = master
32 1
        self.tree_folder = tree_folder
33
34 1
    def message_window(self, event=None):
35
        """ツリービューを右クリックしたときの処理.
36
37
        ・子アイテムならば削除ダイアログを表示する。
38
        親アイテムならば追加を行う。
39
40
        Args:
41
            event (instance): tkinter.Event のインスタンス
42
        """
43
        # 選択アイテムの認識番号取得
44 1
        curItem = self.APP.tree.focus()
45
        # 親アイテムの認識番号取得
46 1
        parentItem = self.APP.tree.parent(curItem)
47
        # 親アイテムをクリックしたとき
48 1
        if self.APP.tree.item(curItem)["text"] == self.tree_folder[4][1]:
49
            # imageタグを選択したとき
50 1
            fTyp = [(u'小説エディタ', '*.gif')]
51 1
            iDir = os.path.abspath(os.path.dirname(__file__))
52 1
            filepath = filedialog.askopenfilename(
53
                filetypes=fTyp,
54
                initialdir=iDir
55
            )
56
            # ファイル名があるとき
57 1
            if not filepath == "":
58 1
                file_name = os.path.splitext(os.path.basename(filepath))[0]
59 1
                path = "./{0}/{1}.gif".format(
60
                    self.tree_folder[4][0],
61
                    file_name
62
                )
63 1
                shutil.copy2(filepath, path)
64 1
                self.APP.cwc.frame_image()
65 1
                path = "./{0}/{1}.txt".format(
66
                    self.tree_folder[4][0],
67
                    file_name
68
                )
69 1
                tree = self.APP.tree.insert(
70
                    self.tree_folder[4][0],
71
                    'end',
72
                    text=file_name
73
                )
74 1
                self.APP.tree.see(tree)
75 1
                self.APP.tree.selection_set(tree)
76 1
                self.APP.tree.focus(tree)
77 1
                self.select_list_item = file_name
78 1
                self.APP.fmc.now_path = path
79 1
                f = open(path, 'w', encoding='utf-8')
80 1
                self.APP.sfc.zoom = 100
81 1
                f.write(str(self.APP.sfc.zoom))
82 1
                f.close()
83 1
                self.APP.cwc.frame_image()
84 1
                self.path_read_image(
85
                    self.tree_folder[4][0],
86
                    file_name,
87
                    0
88
                )
89
90
        else:
91 1
            if str(
92
                self.APP.tree.item(curItem)["text"]
93
            ) and (not str(
94
                    self.APP.tree.item(parentItem)["text"]
95
                )
96
            ):
97
                # サブダイヤログを表示する
98 1
                title = u'{0}に挿入'.format(self.APP.tree.item(curItem)["text"])
99 1
                dialog = MyDialogClass(self.APP, "挿入", True, title, False)
100 1
                self.MASTER.wait_window(dialog.sub_name_win)
101 1
                file_name = dialog.txt
102 1
                del dialog
103 1
                if not file_name == "":
104 1
                    self.APP.fmc.open_file_save(self.APP.fmc.now_path)
105 1
                    curItem = self.APP.tree.focus()
106 1
                    text = self.APP.tree.item(curItem)["text"]
107 1
                    path = ""
108 1
                    tree = ""
109
                    # 選択されているフォルダを見つける
110 1
                    for val in self.tree_folder:
111 1
                        if text == val[1]:
112 1
                            if val[0] == self.tree_folder[0][0]:
113 1
                                self.APP.cwc.frame_character()
114 1
                                self.APP.txt_yobi_name.insert(
115
                                    tk.END,
116
                                    file_name
117
                                )
118
                            else:
119 1
                                self.APP.cwc.frame()
120
121 1
                            path = "./{0}/{1}.txt".format(val[0], file_name)
122 1
                            tree = self.APP.tree.insert(
123
                                val[0],
124
                                'end',
125
                                text=file_name
126
                            )
127 1
                            self.APP.fmc.now_path = path
128 1
                            break
129
130
                    # パスが存在すれば新規作成する
131 1
                    if not path == "":
132 1
                        f = open(path, 'w', encoding='utf-8')
133 1
                        f.write("")
134 1
                        f.close()
135
                        # ツリービューを選択状態にする
136 1
                        self.APP.tree.see(tree)
137 1
                        self.APP.tree.selection_set(tree)
138 1
                        self.APP.tree.focus(tree)
139 1
                        self.select_list_item = file_name
140 1
                        self.APP.winfo_toplevel().title(
141
                            u"小説エディタ\\{0}\\{1}"
142
                            .format(text, file_name)
143
                        )
144 1
                        self.APP.text.focus()
145
                        # テキストを読み取り専用を解除する
146 1
                        self.APP.text.configure(state='normal')
147 1
                        self.APP.hpc.create_tags()
148
            # 子アイテムを右クリックしたとき
149
            else:
150 1
                if str(self.APP.tree.item(curItem)["text"]):
151
                    # 項目を削除する
152 1
                    file_name = self.APP.tree.item(curItem)["text"]
153 1
                    text = self.APP.tree.item(parentItem)["text"]
154
                    # OK、キャンセルダイアログを表示し、OKを押したとき
155 1
                    if messagebox.askokcancel(
156
                        u"項目削除",
157
                        "{0}を削除しますか?".format(file_name)
158
                    ):
159 1
                        image_path = ""
160 1
                        path = ""
161
                        # パスを取得する
162 1
                        for val in self.tree_folder:
163 1
                            if text == val[1]:
164 1
                                path = "./{0}/{1}.txt".format(
165
                                    val[0],
166
                                    file_name
167
                                )
168 1
                                image_path = "./{0}/{1}.gif".format(
169
                                    val[0],
170
                                    file_name
171
                                )
172 1
                                self.APP.tree.delete(curItem)
173 1
                                self.APP.fmc.now_path = ""
174 1
                                break
175
                        # imageパスが存在したとき
176 1
                        if os.path.isfile(image_path):
177 1
                            os.remove(image_path)
178
179
                        # パスが存在したとき
180 1
                        if not path == "":
181 1
                            os.remove(path)
182 1
                            self.APP.cwc.frame()
183 1
                            self.APP.text.focus()
184
185 1
    def on_name_click(self, event=None):
186
        """名前の変更.
187
188
        ・リストボックスの名前を変更する。
189
190
        Args:
191
            event (instance): tkinter.Event のインスタンス
192
        """
193
        # 選択アイテムの認識番号取得
194 1
        curItem = self.APP.tree.focus()
195
        # 親アイテムの認識番号取得
196 1
        parentItem = self.APP.tree.parent(curItem)
197 1
        text = self.APP.tree.item(parentItem)["text"]
198 1
        if not text == "":
199 1
            sub_text = self.APP.tree.item(curItem)["text"]
200 1
            title = u'{0}の名前を変更'.format(sub_text)
201 1
            dialog2 = MyDialogClass(self.APP, u"変更", True, title, sub_text)
202 1
            self.MASTER.wait_window(dialog2.sub_name_win)
203
            # テキストを読み取り専用を解除する
204 1
            self.APP.text.configure(state='normal')
205 1
            co_text = dialog2.txt
206 1
            del dialog2
207 1
            for val in self.tree_folder:
208 1
                if text == val[1]:
209 1
                    path1 = "./{0}/{1}.txt".format(val[0], sub_text)
210 1
                    path2 = "./{0}/{1}.txt".format(val[0], co_text)
211 1
                    self.APP.fmc.now_path = path2
212
                    # テキストの名前を変更する
213 1
                    os.rename(path1, path2)
214 1
                    self.APP.tree.delete(curItem)
215 1
                    Item = self.APP.tree.insert(
216
                        parentItem,
217
                        'end',
218
                        text=co_text
219
                    )
220 1
                    self.APP.tree.selection_set(Item)
221 1
                    self.path_read_text(val[0], co_text)
222 1
                    return
223
224 1
    def path_read_image(self, image_path, image_name, scale):
225
        """イメージを読み込んで表示.
226
227
        ・パスが存在すればイメージファイルを読み込んで表示する。
228
229
        Args:
230
            image_path (str): イメージファイルの相対パス
231
            image_name (str): イメージファイルの名前
232
            scale (int): 拡大率(%)
233
        """
234 1
        if not self.APP.fmc.now_path == "":
235 1
            title = "{0}/{1}.gif".format(
236
                image_path,
237
                image_name
238
            )
239 1
            giffile = Image.open(title)
240 1
            if scale > 0:
241 1
                giffile = giffile.resize(
242
                    (
243
                        int(giffile.width / 100*scale),
244
                        int(giffile.height / 100*scale)
245
                    ),
246
                    resample=Image.LANCZOS
247
                )
248
249 1
            self.APP.image_space.photo = ImageTk.PhotoImage(giffile)
250 1
            self.APP.image_space.itemconfig(
251
                self.APP.image_on_space,
252
                image=self.APP.image_space.photo
253
            )
254
            # イメージサイズにキャンバスサイズを合わす
255 1
            self.APP.image_space.config(
256
                scrollregion=(
257
                    0,
258
                    0,
259
                    giffile.size[0],
260
                    giffile.size[1]
261
                )
262
            )
263 1
            giffile.close()
264
265 1
        self.APP.winfo_toplevel().title(
266
                u"小説エディタ\\{0}\\{1}".format(self.tree_folder[4][1], image_name)
267
            )
268
269 1
    def path_read_text(self, text_path, text_name):
270
        """テキストを読み込んで表示.
271
272
        ・パスが存在すればテキストを読み込んで表示する。
273
274
        Args:
275
            text_path (str): テキストファイルの相対パス
276
            text_name (str): テキストファイルの名前
277
        """
278 1
        if not self.APP.fmc.now_path == "":
279 1
            if not self.APP.fmc.now_path.find(self.tree_folder[0][0]) == -1:
280
                self.APP.txt_yobi_name.delete('0', tk.END)
281
                self.APP.txt_name.delete('0', tk.END)
282
                self.APP.txt_birthday.delete('0', tk.END)
283
                self.APP.text_body.delete('1.0', tk.END)
284
                tree = ET.parse(self.APP.fmc.now_path)
285
                elem = tree.getroot()
286
                self.APP.txt_yobi_name.insert(tk.END, elem.findtext("call"))
287
                self.APP.txt_name.insert(tk.END, elem.findtext("name"))
288
                self.APP.var.set(elem.findtext("sex"))
289
                self.APP.txt_birthday.insert(tk.END, elem.findtext("birthday"))
290
                self.APP.text_body.insert(tk.END, elem.findtext("body"))
291
                title = "{0}/{1}.gif".format(
292
                    self.tree_folder[0][0],
293
                    elem.findtext("call")
294
                )
295
                if os.path.isfile(title):
296
                    self.APP.sfc.print_gif(title)
297
            else:
298 1
                self.APP.text.delete('1.0', tk.END)
299 1
                f = open(self.APP.fmc.now_path, 'r', encoding='utf-8')
300 1
                self.text_text = f.read()
301 1
                self.APP.text.insert(tk.END, self.text_text)
302 1
                f.close()
303
304 1
            self.APP.winfo_toplevel().title(
305
                u"小説エディタ\\{0}\\{1}".format(text_path, text_name)
306
            )
307
            # シンタックスハイライトをする
308 1
            self.APP.hpc.all_highlight()
309
310 1
    def on_double_click(self, event=None):
311
        """ツリービューをダブルクリック.
312
313
        ・ファイルを保存して閉じて、選択されたアイテムを表示する。
314
315
        Args:
316
            event (instance): tkinter.Event のインスタンス
317
        """
318
        # 選択アイテムの認識番号取得
319 1
        curItem = self.APP.tree.focus()
320
        # 親アイテムの認識番号取得
321 1
        parentItem = self.APP.tree.parent(curItem)
322 1
        text = self.APP.tree.item(parentItem)["text"]
323
        # 開いているファイルを保存
324 1
        self.APP.fmc.open_file_save(self.APP.fmc.now_path)
325
        # テキストを読み取り専用を解除する
326 1
        self.APP.cwc.frame()
327 1
        self.APP.text.configure(state='disabled')
328
        # 条件によって分離
329 1
        self.select_list_item = self.APP.tree.item(curItem)["text"]
330 1
        path = ""
331 1
        for val in self.tree_folder:
332 1
            if text == val[1]:
333 1
                if val[0] == self.tree_folder[4][0]:
334
                    path = "./{0}/{1}.txt".format(
335
                        val[0],
336
                        self.select_list_item
337
                    )
338
                    f = open(path, 'r', encoding='utf-8')
339
                    zoom = f.read()
340
                    self.APP.sfc.zoom = int(zoom)
341
                    self.APP.fmc.now_path = path
342
                    self.APP.cwc.frame_image()
343
                    self.path_read_image(
344
                        self.tree_folder[4][0],
345
                        self.select_list_item,
346
                        self.APP.sfc.zoom
347
                    )
348
                else:
349 1
                    path = "./{0}/{1}.txt".format(
350
                        val[0],
351
                        self.select_list_item
352
                    )
353 1
                    self.APP.fmc.now_path = path
354 1
                    if val[0] == self.tree_folder[0][0]:
355
                        self.APP.cwc.frame_character()
356
                    else:
357
                        # テキストを読み取り専用を解除する
358 1
                        self.APP.text.configure(state='normal')
359 1
                        self.APP.text.focus()
360
361 1
                    self.path_read_text(text, self.select_list_item)
362
363 1
                return
364
365 1
        self.APP.fmc.now_path = ""
366 1
        self.APP.winfo_toplevel().title(u"小説エディタ")
367
368
369 1
class MyDialogClass():
370
    """ダイアログ作成クラス.
371
372
    ・自作ダイアログを呼び出し表示する。
373
374
    Args:
375
        message (instance): 親ウインドウインスタンス
376
        caption (str): ボタンのメッセージ
377
        cancel (bool): キャンセルボタンを表示する(True)
378
        title (str): タイトル
379
        text (bool): 選択状態にする(True)
380
    """
381 1
    def __init__(self, message, caption, cancel, title, text):
382 1
        self.txt = ""
383 1
        self.sub_name_win = tk.Toplevel(message)
384 1
        self.txt_name = ttk.Entry(self.sub_name_win, width=40)
385 1
        self.txt_name.grid(
386
            row=0,
387
            column=0,
388
            columnspan=2,
389
            padx=5,
390
            pady=5,
391
            sticky=tk.W+tk.E,
392
            ipady=3
393
        )
394 1
        button = ttk.Button(
395
            self.sub_name_win,
396
            text=caption,
397
            width=str(caption),
398
            padding=(10, 5),
399
            command=self.sub_name_ok
400
        )
401 1
        button.grid(row=1, column=0)
402 1
        if cancel:
403 1
            button2 = ttk.Button(
404
                self.sub_name_win,
405
                text=u'キャンセル',
406
                width=str(u'キャンセル'),
407
                padding=(10, 5),
408
                command=self.sub_name_win.destroy
409
            )
410
411 1
            button2.grid(row=1, column=1)
412 1
            self.txt_name.focus()
413 1
            if text is not False:
414 1
                self.txt_name.insert(tk.END, text)
415 1
                self.txt_name.select_range(0, 'end')
416
417 1
        self.sub_name_win.title(title)
418 1
        self.txt_name.focus()
419
420 1
    def sub_name_ok(self, event=None):
421
        """ダイアログボタンクリック時の処理.
422
423
        ・自作ダイアログのボタンをクリックしたときにインプットボックスに
424
        入力されている値を取得する。
425
426
        Args:
427
            event (instance): tkinter.Event のインスタンス
428
429
        Returns:
430
            str: インプットボックスの値
431
        """
432 1
        self.txt = self.txt_name.get()
433 1
        self.sub_name_win.destroy()
434
        return self.txt
435