...
 
Commits (7)
    https://gitcode.net/horse_sword/tagdox/-/commit/9fe67770d4bf21cc7c588eadac680a2baf05d2be 增加.git文件夹的忽略; 2022-01-29T11:18:25+08:00 horsesword horsesword@qq.com 将默认配置文件配置设定在上级目录。 https://gitcode.net/horse_sword/tagdox/-/commit/b409358d3e672f68ed2c7223d70dbfc3c2c90066 实现了按照子文件夹分组显示的功能, 2022-03-05T19:40:15+08:00 horsesword horsesword@qq.com 修复了文件夹分组的背景色问题; 已知bug:tree定位到高亮内容存在错误。 https://gitcode.net/horse_sword/tagdox/-/commit/6cf720c9742850b05430be56c3bef6598a4078d2 尝试修复了tree定位高亮项目的错误。 2022-03-07T20:45:24+08:00 horsesword horsesword@qq.com https://gitcode.net/horse_sword/tagdox/-/commit/ad5a946a629b825c66d064bf5421e016dc67b0c7 修复了点击列表空白处的bug。 2022-03-09T11:04:22+08:00 horsesword horsesword@qq.com https://gitcode.net/horse_sword/tagdox/-/commit/bb152d81ce039b04bc9c4883801b0a1036154b0b 修复了文件夹名称存在包含关系时,较长文件夹的内部文件会出现在较短文件夹内部的bug。 2022-04-30T15:25:58+08:00 horsesword horsesword@qq.com https://gitcode.net/horse_sword/tagdox/-/commit/cf831e1e70fe41aad52887a0e508bd8b56fae42b 补充了更新记录 2022-04-30T15:28:08+08:00 horsesword horsesword@qq.com https://gitcode.net/horse_sword/tagdox/-/commit/8a8c050a216d3ef29c5bee1ed7f4ec72f40c6cf0 修复目录比对的bug 2022-04-30T17:12:57+08:00 horsesword horsesword@qq.com
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7 (MyPython)" project-jdk-type="Python SDK" /> <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7 (math)" project-jdk-type="Python SDK" />
<component name="PyCharmProfessionalAdvertiser"> <component name="PyCharmProfessionalAdvertiser">
<option name="shown" value="true" /> <option name="shown" value="true" />
</component> </component>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<module type="PYTHON_MODULE" version="4"> <module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager"> <component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" /> <content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Python 3.7 (MyPython)" jdkType="Python SDK" /> <orderEntry type="jdk" jdkName="Python 3.7 (math)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
<component name="PyDocumentationSettings"> <component name="PyDocumentationSettings">
......
...@@ -57,6 +57,45 @@ Tagdox / 标签文库,是用于对文档进行「标签化管理」的免费 ...@@ -57,6 +57,45 @@ Tagdox / 标签文库,是用于对文档进行「标签化管理」的免费
## 近期更新 ## 近期更新
#### v0.23.1.2 2022年4月30日
修复了文件夹名称存在包含关系时,较长文件夹的内部文件会出现在较短文件夹内部的bug。
#### v0.23.1.1 2022年3月9日
修复了点击列表空白处的bug。
#### v0.23.1.0 2022年3月8日
实现了隐藏空分组的功能。
已知bug:按住Ctrl的时候,点击分组内的项目,不能选中。
#### v0.23.0.3 2022年3月7日
尝试修复了tree定位高亮项目的错误。
#### v0.23.0.2 2022年3月5日
尝试修复输入框与中文输入法之间的兼容性问题。
#### v0.23.0.1 2022年3月5日
实现了按照子文件夹分组显示的功能,
修复了文件夹分组的背景色问题;
已知bug:tree定位到高亮内容存在错误。
#### v0.23.0.0 2022年3月3日
增加tree分组显示,可以将子文件夹的内容在第二组显示出来,
相关的功能还没有全部测试。
已知bug:tree定位到高亮内容存在错误。
tree列表的背景色有错误;
如果能显示文件夹名称就更好了。
#### v0.22.1.0 2022年1月12日
增加.git文件夹的忽略;
将默认配置文件配置设定在上级目录。
#### v0.22.0.4 2022年1月12日
优化了新建笔记时候的扩展名提示。
#### v0.22.0.3 2022年1月3日
对部分函数进行了重命名,逻辑没有改。
#### v0.22.0.2 2021年12月25日 #### v0.22.0.2 2021年12月25日
文件重命名默认不再修改扩展名,避免重命名导致的其他问题。 文件重命名默认不再修改扩展名,避免重命名导致的其他问题。
圣诞快乐! 圣诞快乐!
......
_img
\ No newline at end of file
.md
\ No newline at end of file
...@@ -135,6 +135,13 @@ def copy_md(file_path_old: str, file_path_new: str, mode='copy'): ...@@ -135,6 +135,13 @@ def copy_md(file_path_old: str, file_path_new: str, mode='copy'):
print(e) print(e)
def mv_md(file_path_old: str, file_path_new: str):
"""
移动文件
"""
copy_md(file_path_old, file_path_new, mode='move')
if __name__ == '__main__': if __name__ == '__main__':
file_old = r"D:\MaJian\Desktop\@短文剪辑\Python 图像库 PIL 的类 Image 及其方法介绍_leemboy 的博客 - CSDN 博客_pil.md" file_old = r"D:\MaJian\Desktop\@短文剪辑\Python 图像库 PIL 的类 Image 及其方法介绍_leemboy 的博客 - CSDN 博客_pil.md"
file_new = r'd:/to_delete/a/b/c/d\\e/PIL.md' file_new = r'd:/to_delete/a/b/c/d\\e/PIL.md'
......
from tkinter import ttk
import tkinter as tk
class TdTreeview:
def __init__(self, base, vbar=False, hbar=False, **kwargs):
self.bar_width = 16
self.columns = ['tags', 'values']
#
self.frame = ttk.Frame(base, **kwargs)
#
self.bar_v = tk.Scrollbar(self.frame, width=self.bar_width)
self.bar_h = tk.Scrollbar(self.frame, orient=tk.HORIZONTAL, width=self.bar_width)
self.tree = ttk.Treeview(self.frame,
columns=self.columns,
yscrollcommand=self.bar_v.set,
xscrollcommand=self.bar_h.set,
)
#
self.bar_v.config(command=self.tree.yview)
self.bar_h.config(command=self.tree.xview)
#
if vbar:
self.bar_v.pack(side=tk.RIGHT, expand=0, fill=tk.Y)
if hbar:
self.bar_h.pack(side=tk.BOTTOM, expand=0, fill=tk.X)
#
self.tree.pack(expand=1, fill=tk.BOTH)
def insert(self, *args, **kwargs):
self.tree.insert(*args, **kwargs)
def pack(self):
self.frame.pack(expand=1, fill=tk.BOTH)
def clear_items(self) -> None: #
"""
treeview 清除函数
"""
x = self.tree.get_children()
for item in x:
self.tree.delete(item)
def tree_find(self, full_path='', need_update=True, the_col=None): #
"""
用于在 任意 treeview(默认是tree) 里面找到项目,并加高亮。
输入参数是查找值(完整路径)。
need_update 代表是否要刷新列表。一般否是要刷新才能保证正确,
如果是批量查询,可以自己提前刷新,然后取消函数刷新,可以增加速度。
只支持单项目查找,多个查询需要重复运算。
如果返回-1,代表没有找到。
"""
if full_path == '' or full_path is None:
return -1
#
# 默认值
the_tree = self.tree
the_bar = self.bar_v
if the_col is None:
the_col = -1
#
# 根据完整路径,找到对应的文件并高亮
if need_update:
the_tree.update() # 必须在定位之前刷新列表,否则定位会错误
tc = the_tree.get_children()
tc_cnt = len(tc)
print('条目数量为:%s' % tc_cnt)
n = 0
print('开始查找高亮的位置')
try:
(b1, b2) = the_bar.get()
except:
print(f'查询滚动条位置出现错误')
print(the_bar.get())
return (-1)
b0 = b2 - b1
# b0=0
print('b0=')
print(b0)
for i in tc:
tmp = the_tree.item(i, "values")
# print(tmp[the_col])
if tmp[the_col] == full_path:
# the_tree.focus(i) #这个并不能高亮
the_tree.selection_add(i)
# the_tree.selection_add(tc[0])
print('在第%d处检查到了相应结果' % n)
b1 = n / tc_cnt - 0.5 * b0
b2 = n / tc_cnt + 0.5 * b0
print((b0, b1, b2))
if b1 < 0:
b1 = 0
b2 = b0
elif b2 > 1:
b2 = 1
b1 = 1 - b0
print((b1, b2))
# the_bar.set(b1,b2)
the_tree.yview_moveto(b1)
return n
break
else:
n += 1
print('居然没找到:')
print(full_path)
return -1
# for i in range()
def tree_find_by_lst(self, inp_lst):
"""
传入一个列表。tree高亮。
输入参数是要查询的内容,必须是列表。
"""
self.tree.update()
if type(inp_lst) is not list:
print('输入参数不是列表!')
return
for tmp_final_name in inp_lst:
tmp_final_name = tmp_final_name.replace('\\', '/')
print(f'正在定位 {tmp_final_name}')
self.tree_find(tmp_final_name, need_update=False) # 为加标签之后的项目高亮
def test_insert(self):
for i in range(100):
self.insert('', i, text=' hello '+str(i),
values=(str(i), ' hello '+str(i)))
def test_init(self):
# self.name = 'test'
self.tree.heading("tags", text="全部标签", anchor='w', command=self.tree_test)
self.tree.heading("values", text="值", anchor='w', command=self.tree_test)
# self.insert()
def tree_test(self):
self.tree_find(' hello 30')
if __name__ == '__main__':
root = tk.Tk()
a = TdTreeview(root, True, False)
a.test_init()
a.test_insert()
a.pack()
root.mainloop()
import tkinter as tk
from tkinter import ttk
LOGO_PATH = './src/LOGO.ico'
LARGE_FONT = 10 # 表头字号
MON_FONTSIZE = 9 # 正文字号
class TdProgressWindow:
"""
一个出现在主窗口中间的进度条
"""
# input_window = '' # =tk.Toplevel(self.form0)
def __init__(self, parent, prog_value=0, prog_text='') -> None:
"""
进度条,输入进度数值
"""
# 变量设置
self.form0 = parent
self.input_value = ''
self.input_window = tk.Toplevel(self.form0)
print('———————————— 进度条激活 ——————————')
self.input_window.title('进度')
self.my_prog = tk.DoubleVar() # 进度
self.my_text = prog_text
self.my_prog.set(prog_value)
#
# 窗口设置
self.input_window.overrideredirect(True) # 这句话可以去掉标题栏,同时也会没有阴影
self.w_width = 800
self.w_height = 100
#
# 屏幕中央:
# self.screenwidth = SCREEN_WIDTH
# self.screenheight = SCREEN_HEIGHT
# self.x_pos = (self.screenwidth - self.w_width) / 2
# self.y_pos = (self.screenheight - self.w_height) / 2
#
# 主窗口中央:
self.x_pos = self.form0.winfo_x() + (self.form0.winfo_width() - self.w_width) / 2
self.y_pos = self.form0.winfo_y() + (self.form0.winfo_height() - self.w_height) / 2
self.input_window.geometry('%dx%d+%d+%d' % (self.w_width, self.w_height, self.x_pos, self.y_pos))
# self.input_window.title(self.title)
self.input_window.transient(self.form0) # 避免在任务栏出现第二个窗口,而且可以实现置顶
self.input_window.withdraw()
try:
self.input_window.iconbitmap(LOGO_PATH) # 左上角图标
except:
pass
self.iframe = tk.Frame(self.input_window, padx=20, pady=20)
self.iframe.pack(expand=0, fill=tk.BOTH)
# 标签
self.pct = tk.Label(self.iframe)
self.pct.pack()
# 进度条
self.prog_bar = ttk.Progressbar(self.iframe, variable=self.my_prog)
self.prog_bar.pack(expand=0, fill=tk.BOTH)
#
self.prog_bar.bind("<FocusOut>", self.on_focus_out)
self.prog_bar.bind('<1>', self.force_close)
def force_close(self, event=None):
self.input_window.destroy()
def on_focus_out(self, event=None):
"""
失去焦点的事件,自动关闭窗口,避免最小化等操作时程序锁死
"""
# print(event.widget)
if event.widget == self.prog_bar:
print("失去焦点")
self.force_close(self)
def set(self, value):
self.progress = value
self.my_prog.set(self.progress)
self.pct.configure(text=self.my_text + str(int(value)) + '%')
self.input_window.update()
# self.pct.update()
# self.prog_bar.update()
if value == 0:
self.input_window.withdraw()
elif value > 0:
self.input_window.deiconify() # 置顶
# self.input_window.lift() # 置顶,但是会导致后面失去输入能力
# self.input_window.focus_force()
self.input_window.grab_set() # 模态
if value >= 100:
self.input_window.withdraw()
# self.input_window.overrideredirect(False)
self.input_window.destroy()
self.__destroy__()
# 自制输入窗体
class TdInputWindow:
"""
输入窗体类。
实现了一个居中的模态窗体。
"""
input_value = ''
def __init__(self, parent, title='未命名', msg='未定义', default_value='', selection_range=None) -> None:
"""
自制输入窗体的初始化;
参数:
selection_range 是默认选中的范围。
"""
# 变量设置
self.form0 = parent # 父窗格
#
self.input_value = ''
self.title = title
self.msg = msg
self.default_value = default_value
self.input_window = tk.Toplevel(self.form0)
#
self.input_window.transient(self.form0) # 避免在任务栏出现第二个窗口,而且可以实现置顶
self.input_window.grab_set() # 模态
#
# 窗口设置
# self.input_window.overrideredirect(True) # 这句话可以去掉标题栏,同时也会没有阴影
# 上面功能启用之后,好像快捷键会出现问题。
self.w_width = 800
self.w_height = 160
#
# 屏幕中央:
# self.screenwidth = SCREEN_WIDTH
# self.screenheight = SCREEN_HEIGHT
# self.x_pos = (self.screenwidth - self.w_width) / 2
# self.y_pos = (self.screenheight - self.w_height) / 2
#
# 主窗口中央:
self.x_pos = self.form0.winfo_x() + (self.form0.winfo_width() - self.w_width) / 2
self.y_pos = self.form0.winfo_y() + (self.form0.winfo_height() - self.w_height) / 2
self.input_window.geometry('%dx%d+%d+%d' % (self.w_width, self.w_height, self.x_pos, self.y_pos))
self.input_window.title(self.title)
#
try:
self.input_window.iconbitmap(LOGO_PATH) # 左上角图标
except:
pass
self.iframe = tk.Frame(self.input_window, padx=20, pady=10)
self.iframe.pack(expand=0, fill=tk.BOTH)
# 文本框
self.lb = tk.Label(self.iframe, text=self.msg, font="微软雅黑 " + str(MON_FONTSIZE))
self.lb.pack(anchor='sw', pady=5)
self.input_window.update()
# 输入框
self.et = ttk.Entry(self.iframe, font="微软雅黑 " + str(MON_FONTSIZE))
self.et.insert(0, self.default_value)
self.et.pack(expand=0, fill=tk.X, pady=5)
# self.et.selection_range(0, len(self.et.get()))
if selection_range is None:
self.et.selection_range(0, len(self.et.get()))
else:
self.et.selection_range(0, selection_range)
self.et.focus() # 获得焦点
# self.et.focus()
# 键盘快捷键
self.input_window.bind_all('<Return>', self.bt_yes_click)
self.input_window.bind_all('<Escape>', self.bt_cancel_click)
self.iframe_bt = tk.Frame(self.input_window, padx=10, pady=10)
self.iframe_bt.pack()
# self.iframe_bt.pack(expand=0,fill=tk.BOTH)
# 按钮
self.bty = ttk.Button(self.iframe_bt, text='确定', command=self.bt_yes_click)
self.bty.pack(side=tk.LEFT, padx=20)
self.btc = ttk.Button(self.iframe_bt, text='取消', command=self.bt_cancel_click)
self.btc.pack(side=tk.LEFT, padx=20)
self.input_window.deiconify()
self.input_window.lift()
self.input_window.focus_force()
self.input_window.bind("<FocusOut>", self.on_focus_out)
self.form0.wait_window(self.input_window) # 要用这句话拦截主窗体的代码运行
def on_focus_out(self, event=None):
"""
失去焦点的事件,自动关闭窗口,避免最小化等操作时程序锁死
"""
# print(event.widget)
if event.widget == self.input_window:
print("输入框失去焦点")
self.bt_cancel_click(self)
def bt_cancel_click(self, event=None):
self.input_window.unbind_all('<Return>')
self.input_window.unbind_all('<Escape>')
self.input_window.destroy()
def bt_yes_click(self, event=None) -> str:
self.input_window.unbind_all('<Return>')
self.input_window.unbind_all('<Escape>')
try:
self.input_value = self.et.get() #
except Exception as e:
print(e)
# print(self.input_value)
self.input_window.destroy()
return self.input_value
def __str__(self) -> str:
return self.input_value
def __del__(self) -> str:
self.input_value = ''
# self.input_window.destroy()
return ''
class TdSpaceWindow:
"""
空格窗体类。
实现了一个居中的模态窗体。
"""
input_value = ''
def __init__(self, parent,
title='未命名',
msg='未定义',
default_value='',
selection_range=None,
width=960,
height=560,
) -> None:
"""
自制输入窗体的初始化;
参数:
selection_range 是默认选中的范围。
"""
# 变量设置
self.form0 = parent # 父窗格
#
self.input_value = ''
self.title = title
self.msg = msg
self.default_value = default_value
self.sub_window = tk.Toplevel(self.form0)
#
self.sub_window.transient(self.form0) # 避免在任务栏出现第二个窗口,而且可以实现置顶
# self.sub_window.grab_set() # 模态,此功能生效后,窗口外不可以点击。注释掉就可以操作了。
#
# 窗口设置
# self.sub_window.overrideredirect(True) # 这句话可以去掉标题栏,同时也会没有阴影
self.w_width = width
self.w_height = height
#
# 屏幕中央:
# self.screenwidth = SCREEN_WIDTH
# self.screenheight = SCREEN_HEIGHT
# self.x_pos = (self.screenwidth - self.w_width) / 2
# self.y_pos = (self.screenheight - self.w_height) / 2
#
# 主窗口中央:
self.x_pos = self.form0.winfo_x() + (self.form0.winfo_width() - self.w_width) / 2
self.y_pos = self.form0.winfo_y() + (self.form0.winfo_height() - self.w_height) / 2
self.sub_window.geometry('%dx%d+%d+%d' % (self.w_width, self.w_height, self.x_pos, self.y_pos))
self.sub_window.title(self.title)
#
try:
self.sub_window.iconbitmap(LOGO_PATH) # 左上角图标
except:
pass
self.iframe = tk.Frame(self.sub_window, padx=20, pady=10)
self.iframe.pack(expand=1, fill=tk.BOTH)
# 文本框
self.lb = tk.Label(self.iframe, text=self.msg,
wraplength=900,
justify="left",
font="微软雅黑 10")
self.lb.pack(anchor='sw', pady=5)
self.lb.focus() # 获得焦点
self.sub_window.update()
self.sub_window.bind_all('<space>', self.on_exit)
#
# 失去焦点自动退出
self.sub_window.bind('<FocusOut>', self.on_focus_out)
def on_focus_out(self, event=None):
"""
失去焦点的事件,自动关闭窗口,避免最小化等操作时程序锁死
"""
# print(event.widget)
if event.widget == self.sub_window:
print("失去焦点")
self.on_exit(self)
def on_exit(self, event=None):
self.sub_window.destroy()
此差异已折叠。
# 后端代码
# 后端的主要作用是文件的检索、返回等。
# 从设计原则上讲,尽量不涉及全局变量比较合适,都用传参的方式处理。
import os
import json
from os.path import isdir
from os.path import isfile
import time
import threading # 多线程
from multiprocessing import Pool # 进程
from multiprocessing import Process
import shutil
import queue
#
import subprocess # 用于打开文件所在位置并选中文件
from libs.common_funcs import get_split_path
def show_msg_success(msg):
print(msg)
def show_msg_error(msg):
print(msg)
# if False:
# tk.messagebox.showerror(title='错误',
# message='文件移动失败。')
def exec_safe_rename_v2(old_name: str, new_name: str):
"""
在基础的重命名之外,增加了对文件是否重名的判断;
返回值str, 如果重命名成功,返回(1,添加数字之后的最终文件名);
如果重命名失败,返回(0,原始文件名)。
"""
old_name = old_name.replace('\\', '/')
new_name = new_name.replace('\\', '/')
'''
n=1
[tmp_path,tmp_new_name]=os.path.split(new_name)
# tmp_path=''
# tmp_new_name=new_name
p=tmp_new_name.find(V_SEP)
if p>=0:
name_1=tmp_new_name[:p]
name_2=tmp_new_name[p:]
else:
p=tmp_new_name.rfind('.')
if p>=0:
name_1=tmp_new_name[:p]
name_2=tmp_new_name[p:]
else: # 连'.'都没有的话
name_1=tmp_new_name
name_2=''
tmp_new_full_name=new_name
while isfile(tmp_new_full_name):
tmp_new_name=name_1+'('+ str(n)+')'+name_2
tmp_new_full_name=tmp_path+'/'+tmp_new_name
n+=1
print(tmp_new_full_name)
'''
tmp_new_full_name = safe_get_name(new_name)
try:
os.rename(old_name, tmp_new_full_name)
return 1, tmp_new_full_name
except:
print('安全重命名失败!')
return 0, old_name,
pass
def safe_get_name(new_name: str, v_sep='^') -> str:
"""
输入: 目标全路径;
返回: 安全的新路径(可用于重命名、新建等)
输入和输出都是字符串。
"""
n = 1
[tmp_path, tmp_new_name] = os.path.split(new_name)
p = tmp_new_name.find(v_sep)
if p >= 0:
name_1 = tmp_new_name[:p]
name_2 = tmp_new_name[p:]
else:
p = tmp_new_name.rfind('.')
if p >= 0:
name_1 = tmp_new_name[:p]
name_2 = tmp_new_name[p:]
else: # 连'.'都没有的话
name_1 = tmp_new_name
name_2 = ''
tmp_new_full_name = new_name
while isfile(tmp_new_full_name):
tmp_new_name = name_1 + '(' + str(n) + ')' + name_2
tmp_new_full_name = tmp_path + '/' + tmp_new_name
n += 1
# print(tmp_new_full_name)
return tmp_new_full_name
def exec_safe_copy(old_name: str, new_name: str, opt_type: str = 'copy'):
"""
安全复制或移动文件。
:param opt_type: 'copy' 或 'move'。
:param old_name: 旧的文件完整路径
:param new_name: 新的文件完整路径(含文件名)
:return: 操作之后的文件路径,移动失败返回原始路径,移动成功返回新路径。
"""
old_name = old_name.replace('\\', '/')
new_name = new_name.replace('\\', '/')
#
# 完全相同的路径不需要执行移动操作
if old_name == new_name and opt_type == 'move':
show_msg_error('原始路径和新路径一致,跳过')
return 7, old_name
#
tmp_new_full_name = safe_get_name(new_name)
print('开始安全复制')
print(old_name)
print(tmp_new_full_name)
if opt_type == 'copy':
try:
shutil.copy(old_name, tmp_new_full_name)
# os.popen('copy '+ old_name +' '+ tmp_new_full_name)
show_msg_success('安全复制成功')
# os.rename(old_name,tmp_new_full_name)
return 1, tmp_new_full_name
except:
res_message = '对以下文件复制失败!' + 'old_name'
show_msg_error(res_message)
return 0, old_name,
pass
elif opt_type == 'move':
try:
shutil.move(old_name, tmp_new_full_name)
# os.popen('copy '+ old_name +' '+ tmp_new_full_name)
show_msg_success('安全移动成功')
# os.rename(old_name,tmp_new_full_name)
return 1, tmp_new_full_name
except:
res_message = '对以下文件移动失败!' + 'old_name'
show_msg_error(res_message)
return 0, old_name
pass
class TagdoxOptions:
"""
配置文件类。
"""
def __init__(self):
self.lst_my_path_short = []
self.lst_my_path_long = []
self.lst_my_path_long_selected = []
self.dict_path = {}
self.dict_folder_groups = {}
self.folder_path = '' # 目标文件所在文件夹路径
# self.DEFAULT_FILEPATH = 'D:/MyPython/开发数据/options_for_tagdox.json'
self.DEFAULT = {
'FILEPATH': 'D:/MyPython/开发数据/options_for_tagdox.json',
'DEFAULT_GROUP_NAME': "默认文件夹分组",
}
# global json_data
# global dict_folder_groups # 文件夹对应分组
try:
if isfile(self.DEFAULT['FILEPATH']):
print('读取开发模式的配置文件')
self.file_path = self.DEFAULT['FILEPATH']
else:
print('读取标准模式的配置文件(相同路径下)')
self.file_path = 'options_for_tagdox.json' # 配置文件的名称
except Exception as e:
print('读取标准模式的配置文件(相同路径下)')
self.file_path = 'options_for_tagdox.json' # 配置文件的名称
self.DEFAULT_DATA = {
"options": {
"sep": "^",
"vfolders": "2",
"note_ext": ".docx",
"file_drag_enter": "copy",
"TREE_SUB_SHOW": 'sub_folder',
#
'FOLDER_AS_TAG': '',
'TAG_EASY': "",
},
"folders": [
]
} # 目标文件内容
self.options = self.DEFAULT_DATA['options'].copy()
self.folders = self.DEFAULT_DATA['folders'].copy()
#
self.data = {'options': self.options,
'folders': self.folders,
}
def set_option_by_key(self, key1, value1, need_write=True) -> int:
"""
修改设置项,以键值对的方式修改。
会自动触发 exec_update_json(写入json文件).
参数 need_write 代表了是否需要写入文件。默认是修改后立刻写入。
"""
try:
self.options.update({key1: value1})
#
if need_write:
self.exec_options_file_write()
# exec_json_file_write(data=json_data)
# exec_json_file_load()
pass
return 1
except:
print('修改设置发生错误')
return 0
def exec_options_file_write(self, tar=None, data=None) -> None:
"""
将 json_data 变量的值,写入 json 文件。
可以不带参数,随时调用就是写入 json。
"""
tar = self.file_path if tar is None else tar
data = self.data if data is None else data
try:
with open(tar, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False)
except Exception as e:
print('json文件写入异常: ', e)
def exec_options_file_load(self, load_settings=True, load_folders=True) -> None:
"""
读取json文件,获取其中的参数,并存储到相应的变量中。
如果json文件读取失败,则按照初始化标准重建这个文件。
依赖函数:update_json。
"""
dict_folder_groups = dict()
need_init_json = 0
try:
with open(self.file_path, 'r', encoding='utf8') as fp:
json_data = json.load(fp) # 读取到的内容
if load_settings: # 加载设置部分
try:
opt_data = json_data['options'] # 设置
self.set_option_by_key('sep', opt_data['sep'], False) # 分隔符,默认是 # 号,也可以设置为 ^ 等符号。
self.set_option_by_key('vfolders', int(opt_data['vfolders']), False) # 目录最末层数名称检查,作为标签的检查层数
self.set_option_by_key('note_ext', opt_data['note_ext'], False) # 默认笔记类型。
self.set_option_by_key('file_drag_enter', opt_data['file_drag_enter'], False) # 默认拖动操作
self.set_option_by_key('sub_folder', 'sub_folder', False) # 这个项目不再允许调整,而且不再起作用。
self.set_option_by_key('FOLDER_AS_TAG', opt_data['FOLDER_AS_TAG'], False) # 最后文件夹识别。
self.set_option_by_key('TAG_EASY', opt_data['TAG_EASY'], False) # 标签搜索方式
#
print('加载基本参数成功')
except Exception as e:
print(e)
print('加载基本参数失败')
pass
if load_folders:
# lst_my_path_long_selected=lst_my_path_long.copy() #按文件夹筛选用
self.lst_my_path_long = []
self.lst_my_path_short = []
json_folders_lst = json_data['folders'] # 读取到的文件夹数据部分
for i in json_folders_lst:
# lst_my_path_long.append(i)
tmp = {'pth': i['pth'].strip()}
#
try:
tmp['short'] = i['short'] # 如果有自定义名称,优先加载
except:
tmp['short'] = get_split_path(i['pth'])[-1]
#
try:
tmp['group'] = i['group'] # 分组名称
except:
tmp['group'] = self.DEFAULT['DEFAULT_GROUP_NAME']
#
# 其他处理
tmp['short'] = tmp['short'].replace(' ', '_') # 修复路径空格bug的权宜之计,以后应该可以优化
# 增加逻辑:避免短路径重名:
j = 1
tmp_2 = tmp['short']
while tmp_2 in self.lst_my_path_short:
j += 1
tmp_2 = tmp['short'] + "(" + str(j) + ")"
print('tmp2=', tmp_2)
tmp['short'] = tmp_2.strip()
if tmp['short'] == '' or tmp['pth'] == '': # 出现空白文件夹
for j in range(len(json_folders_lst) - 1, -1, -1):
if json_folders_lst[j]['pth'].strip() == '':
json_folders_lst.pop(j)
else:
self.lst_my_path_long.append(tmp['pth'])
self.lst_my_path_short.append(tmp['short'])
#
self.dict_path.update({tmp['short']: tmp['pth']})
self.dict_folder_groups.update({tmp['short']: tmp['group']})
self.lst_my_path_long_selected = self.lst_my_path_long.copy() #
# 此处有大量的可优化空间。
print('加载关注文件夹列表成功')
# 加载成功后,保存
self.folders += json_folders_lst
except Exception as e:
print('加载json异常,错误为:', e, ';即将重置json文件')
# need_init_json=1
# 备份之前的文件;
# self.file_path
try:
exec_safe_copy(self.file_path, self.file_path, 'copy')
# 写新文件
self.data = self.DEFAULT_DATA
self.exec_options_file_write()
except Exception as e:
print('发生错误:', e)
if __name__ == '__main__':
d = TagdoxOptions()
d.exec_options_file_load()
pass