|
@@ -1,13 +1,15 @@
|
|
|
import tkinter as tk
|
|
import tkinter as tk
|
|
|
|
|
|
|
|
class SquareWindow:
|
|
class SquareWindow:
|
|
|
- def __init__(self, config, path_info=None):
|
|
|
|
|
|
|
+ def __init__(self, config, path_info=None, path_mapping=None):
|
|
|
# Configuration: [(parent_number, count), ...]
|
|
# Configuration: [(parent_number, count), ...]
|
|
|
# (None, 11) means draw 11 squares inside square #0 (the main square)
|
|
# (None, 11) means draw 11 squares inside square #0 (the main square)
|
|
|
# (2, 7) means draw 7 squares inside square #2
|
|
# (2, 7) means draw 7 squares inside square #2
|
|
|
# path_info: Optional dict mapping square numbers to file/folder names
|
|
# path_info: Optional dict mapping square numbers to file/folder names
|
|
|
|
|
+ # path_mapping: Optional dict mapping square numbers to file paths
|
|
|
self.config = config
|
|
self.config = config
|
|
|
self.path_info = path_info if path_info is not None else {}
|
|
self.path_info = path_info if path_info is not None else {}
|
|
|
|
|
+ self.number_to_path = path_mapping if path_mapping is not None else {}
|
|
|
|
|
|
|
|
# Set window size to 1000x1000 pixels (needed for calculate_squares)
|
|
# Set window size to 1000x1000 pixels (needed for calculate_squares)
|
|
|
self.window_size = 1000
|
|
self.window_size = 1000
|
|
@@ -28,6 +30,9 @@ class SquareWindow:
|
|
|
# Property to store square information: {number: (x, y, size, parent_number)}
|
|
# Property to store square information: {number: (x, y, size, parent_number)}
|
|
|
self.square_positions = {}
|
|
self.square_positions = {}
|
|
|
|
|
|
|
|
|
|
+ # Store original colors for flashing effect
|
|
|
|
|
+ self.original_colors = {}
|
|
|
|
|
+
|
|
|
# Draw all squares based on the calculated squares dictionary
|
|
# Draw all squares based on the calculated squares dictionary
|
|
|
for number, (x, y, size, parent_number) in self.squares.items():
|
|
for number, (x, y, size, parent_number) in self.squares.items():
|
|
|
self.draw_square_at_location(x, y, size, number, parent_number)
|
|
self.draw_square_at_location(x, y, size, number, parent_number)
|
|
@@ -39,6 +44,11 @@ class SquareWindow:
|
|
|
# Save the output to print.log file
|
|
# Save the output to print.log file
|
|
|
with open("print.log", "w", encoding="utf-8") as f:
|
|
with open("print.log", "w", encoding="utf-8") as f:
|
|
|
f.write(output_content)
|
|
f.write(output_content)
|
|
|
|
|
+
|
|
|
|
|
+ # Initialize clipboard monitoring for file content search
|
|
|
|
|
+ self.highlighted_squares = set()
|
|
|
|
|
+ self.all_highlighted_squares = set() # Track all previously highlighted squares
|
|
|
|
|
+ self.check_clipboard_content()
|
|
|
|
|
|
|
|
def calculate_squares(self):
|
|
def calculate_squares(self):
|
|
|
"""
|
|
"""
|
|
@@ -152,10 +162,16 @@ class SquareWindow:
|
|
|
dark_outline = f"#{r:02x}{g:02x}{b:02x}"
|
|
dark_outline = f"#{r:02x}{g:02x}{b:02x}"
|
|
|
else:
|
|
else:
|
|
|
dark_outline = "black" # fallback
|
|
dark_outline = "black" # fallback
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ # Store the original color for flashing
|
|
|
|
|
+ self.original_colors[number] = color
|
|
|
|
|
+
|
|
|
# Create a semi-transparent effect using stipple pattern
|
|
# Create a semi-transparent effect using stipple pattern
|
|
|
# This creates a checkerboard-like pattern that simulates transparency
|
|
# This creates a checkerboard-like pattern that simulates transparency
|
|
|
- self.canvas.create_rectangle(x, y, x + size, y + size, outline=dark_outline, fill=color, width=1, stipple='gray50')
|
|
|
|
|
|
|
+ rect_id = self.canvas.create_rectangle(x, y, x + size, y + size, outline=dark_outline, fill=color, width=1, stipple='gray50')
|
|
|
|
|
+
|
|
|
|
|
+ # Tag the rectangle with the number for easy identification
|
|
|
|
|
+ self.canvas.addtag_withtag(f"square_{number}", rect_id)
|
|
|
|
|
|
|
|
# Draw a line segment at the bottom edge of the square (inside the square) only if size >= 50
|
|
# Draw a line segment at the bottom edge of the square (inside the square) only if size >= 50
|
|
|
if size >= 50:
|
|
if size >= 50:
|
|
@@ -191,6 +207,131 @@ class SquareWindow:
|
|
|
|
|
|
|
|
return level
|
|
return level
|
|
|
|
|
|
|
|
|
|
+ def check_clipboard_content(self):
|
|
|
|
|
+ """Check clipboard content and highlight matching files"""
|
|
|
|
|
+ try:
|
|
|
|
|
+ # Get clipboard content
|
|
|
|
|
+ clipboard_content = self.root.clipboard_get()
|
|
|
|
|
+
|
|
|
|
|
+ # Find all files that contain the clipboard content
|
|
|
|
|
+ matching_squares = set()
|
|
|
|
|
+ if clipboard_content and len(clipboard_content.strip()) > 0:
|
|
|
|
|
+ matching_squares = self.search_files_for_content(clipboard_content)
|
|
|
|
|
+
|
|
|
|
|
+ # Update highlighted squares
|
|
|
|
|
+ old_highlighted = self.highlighted_squares.copy()
|
|
|
|
|
+ self.highlighted_squares = matching_squares
|
|
|
|
|
+
|
|
|
|
|
+ # If there are changes, update the highlighted squares
|
|
|
|
|
+ if old_highlighted != self.highlighted_squares:
|
|
|
|
|
+ # Update the colors of highlighted squares
|
|
|
|
|
+ self.update_highlighted_squares()
|
|
|
|
|
+
|
|
|
|
|
+ except tk.TclError:
|
|
|
|
|
+ # Clipboard is empty or contains non-text data
|
|
|
|
|
+ old_highlighted = self.highlighted_squares.copy()
|
|
|
|
|
+ self.highlighted_squares = set()
|
|
|
|
|
+
|
|
|
|
|
+ # Restore colors of previously highlighted squares
|
|
|
|
|
+ for square_num in old_highlighted:
|
|
|
|
|
+ self.restore_square_color(square_num)
|
|
|
|
|
+
|
|
|
|
|
+ # Schedule next check
|
|
|
|
|
+ self.root.after(1000, self.check_clipboard_content) # Check every second
|
|
|
|
|
+
|
|
|
|
|
+ def restore_square_color(self, square_num):
|
|
|
|
|
+ """Restore the original color of a square"""
|
|
|
|
|
+ if square_num in self.squares:
|
|
|
|
|
+ x, y, size, parent_number = self.squares[square_num]
|
|
|
|
|
+
|
|
|
|
|
+ # Find the rectangle item for this square
|
|
|
|
|
+ tags = f"square_{square_num}"
|
|
|
|
|
+ items = self.canvas.find_withtag(tags)
|
|
|
|
|
+
|
|
|
|
|
+ # Restore original color
|
|
|
|
|
+ original_color = self.original_colors.get(square_num, "#FFFFFF")
|
|
|
|
|
+ for item in items:
|
|
|
|
|
+ if "rectangle" in str(self.canvas.type(item)):
|
|
|
|
|
+ self.canvas.itemconfig(item, fill=original_color)
|
|
|
|
|
+
|
|
|
|
|
+ def stop_flashing(self):
|
|
|
|
|
+ """Stop the highlighting (placeholder function)"""
|
|
|
|
|
+ pass
|
|
|
|
|
+
|
|
|
|
|
+ def search_files_for_content(self, search_content):
|
|
|
|
|
+ """Search all text files for the given content and return matching square numbers"""
|
|
|
|
|
+ import os
|
|
|
|
|
+
|
|
|
|
|
+ matching_squares = set()
|
|
|
|
|
+
|
|
|
|
|
+ # Only search files (not directories) that contain the search content
|
|
|
|
|
+ if hasattr(self, 'number_to_path'):
|
|
|
|
|
+ for number, path in self.number_to_path.items():
|
|
|
|
|
+ # Double-check that this is a file, not a directory
|
|
|
|
|
+ # Using both isfile() and not isdir() for extra safety
|
|
|
|
|
+ # Double-check that this is a file, not a directory
|
|
|
|
|
+ # Using both isfile() and not isdir() for extra safety
|
|
|
|
|
+ if os.path.isfile(path) and not os.path.isdir(path):
|
|
|
|
|
+ try:
|
|
|
|
|
+ # Try to read the file as text
|
|
|
|
|
+ with open(path, 'r', encoding='utf-8', errors='ignore') as f:
|
|
|
|
|
+ content = f.read()
|
|
|
|
|
+ if search_content.lower() in content.lower():
|
|
|
|
|
+ matching_squares.add(number)
|
|
|
|
|
+ except Exception:
|
|
|
|
|
+ # If we can't read the file, skip it
|
|
|
|
|
+ continue
|
|
|
|
|
+
|
|
|
|
|
+ return matching_squares
|
|
|
|
|
+
|
|
|
|
|
+ def update_highlighted_squares(self):
|
|
|
|
|
+ """Update the color of highlighted squares to red"""
|
|
|
|
|
+ # First, restore all previously highlighted squares to their original color
|
|
|
|
|
+ for square_num in self.all_highlighted_squares:
|
|
|
|
|
+ if square_num in self.squares:
|
|
|
|
|
+ x, y, size, parent_number = self.squares[square_num]
|
|
|
|
|
+
|
|
|
|
|
+ # Find the rectangle item for this square
|
|
|
|
|
+ tags = f"square_{square_num}"
|
|
|
|
|
+ items = self.canvas.find_withtag(tags)
|
|
|
|
|
+
|
|
|
|
|
+ # Restore original color
|
|
|
|
|
+ original_color = self.original_colors.get(square_num, "#FFFFFF")
|
|
|
|
|
+ for item in items:
|
|
|
|
|
+ if "rectangle" in str(self.canvas.type(item)):
|
|
|
|
|
+ self.canvas.itemconfig(item, fill=original_color)
|
|
|
|
|
+
|
|
|
|
|
+ # Now highlight the new matching squares in red
|
|
|
|
|
+ for square_num in self.highlighted_squares:
|
|
|
|
|
+ if square_num in self.squares:
|
|
|
|
|
+ x, y, size, parent_number = self.squares[square_num]
|
|
|
|
|
+
|
|
|
|
|
+ # Find the rectangle item for this square
|
|
|
|
|
+ tags = f"square_{square_num}"
|
|
|
|
|
+ items = self.canvas.find_withtag(tags)
|
|
|
|
|
+
|
|
|
|
|
+ # Change color to red
|
|
|
|
|
+ for item in items:
|
|
|
|
|
+ if "rectangle" in str(self.canvas.type(item)):
|
|
|
|
|
+ self.canvas.itemconfig(item, fill="red")
|
|
|
|
|
+
|
|
|
|
|
+ # Update the set of all highlighted squares
|
|
|
|
|
+ self.all_highlighted_squares = self.highlighted_squares.copy()
|
|
|
|
|
+
|
|
|
|
|
+ def find_square_items_by_position(self, x, y, size):
|
|
|
|
|
+ """Find canvas item IDs that correspond to a square at the given position"""
|
|
|
|
|
+ # Find items by coordinates
|
|
|
|
|
+ items = []
|
|
|
|
|
+ overlapping = self.canvas.find_overlapping(x, y, x + size, y + size)
|
|
|
|
|
+
|
|
|
|
|
+ for item in overlapping:
|
|
|
|
|
+ # Check if this item is part of a square we drew
|
|
|
|
|
+ tags = self.canvas.gettags(item)
|
|
|
|
|
+ if any('square' in tag.lower() for tag in tags) or len(tags) == 0: # Assume squares have no special tags or 'square' in tag
|
|
|
|
|
+ items.append(item)
|
|
|
|
|
+
|
|
|
|
|
+ return items
|
|
|
|
|
+
|
|
|
def run(self):
|
|
def run(self):
|
|
|
self.root.mainloop()
|
|
self.root.mainloop()
|
|
|
|
|
|
|
@@ -204,20 +345,23 @@ def folder_to_config(folder_path, skip_folder=[]):
|
|
|
skip_folder: 不需要遍历的文件夹名称列表
|
|
skip_folder: 不需要遍历的文件夹名称列表
|
|
|
|
|
|
|
|
Returns:
|
|
Returns:
|
|
|
- tuple: (config_list, path_info_dict)
|
|
|
|
|
|
|
+ tuple: (config_list, path_info_dict, path_mapping_dict)
|
|
|
config_list: 包含(父级编号, 子项数量)元组的列表
|
|
config_list: 包含(父级编号, 子项数量)元组的列表
|
|
|
(None, n) 表示根目录下有n个子项
|
|
(None, n) 表示根目录下有n个子项
|
|
|
path_info_dict: 映射编号到文件/文件夹名称的字典
|
|
path_info_dict: 映射编号到文件/文件夹名称的字典
|
|
|
|
|
+ path_mapping_dict: 映射编号到完整文件路径的字典
|
|
|
"""
|
|
"""
|
|
|
import os
|
|
import os
|
|
|
|
|
|
|
|
# 存储路径到编号的映射
|
|
# 存储路径到编号的映射
|
|
|
path_to_number = {}
|
|
path_to_number = {}
|
|
|
number_to_name = {}
|
|
number_to_name = {}
|
|
|
|
|
+ number_to_path = {} # 新增:编号到路径的映射
|
|
|
|
|
|
|
|
# 首先为根目录分配编号
|
|
# 首先为根目录分配编号
|
|
|
path_to_number[folder_path] = 0
|
|
path_to_number[folder_path] = 0
|
|
|
number_to_name[0] = os.path.basename(folder_path)
|
|
number_to_name[0] = os.path.basename(folder_path)
|
|
|
|
|
+ number_to_path[0] = folder_path # 添加路径映射
|
|
|
|
|
|
|
|
# 使用栈进行迭代式深度优先遍历,确保正确处理父子关系
|
|
# 使用栈进行迭代式深度优先遍历,确保正确处理父子关系
|
|
|
stack = [folder_path]
|
|
stack = [folder_path]
|
|
@@ -245,6 +389,7 @@ def folder_to_config(folder_path, skip_folder=[]):
|
|
|
number = len(path_to_number)
|
|
number = len(path_to_number)
|
|
|
path_to_number[item_path] = number
|
|
path_to_number[item_path] = number
|
|
|
number_to_name[number] = os.path.basename(item_path)
|
|
number_to_name[number] = os.path.basename(item_path)
|
|
|
|
|
+ number_to_path[number] = item_path # 添加路径映射
|
|
|
|
|
|
|
|
# 如果是目录且不在跳过列表中,加入栈中待处理
|
|
# 如果是目录且不在跳过列表中,加入栈中待处理
|
|
|
if os.path.isdir(item_path):
|
|
if os.path.isdir(item_path):
|
|
@@ -289,11 +434,11 @@ def folder_to_config(folder_path, skip_folder=[]):
|
|
|
parent_number = path_to_number[path]
|
|
parent_number = path_to_number[path]
|
|
|
result.append((parent_number, 0))
|
|
result.append((parent_number, 0))
|
|
|
|
|
|
|
|
- return result, number_to_name
|
|
|
|
|
|
|
+ return result, number_to_name, number_to_path
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if __name__ == "__main__":
|
|
|
- config, path_info = folder_to_config(r"E:\agricultural_research_platform", skip_folder=["automatedDeployment", "node_modules", ".vscode", ".git", "images"])
|
|
|
|
|
|
|
+ config, path_info, path_mapping = folder_to_config(r"E:\agricultural_research_platform", skip_folder=["automatedDeployment", "node_modules", ".vscode", ".git", "images"])
|
|
|
print(config)
|
|
print(config)
|
|
|
- app = SquareWindow(config, path_info)
|
|
|
|
|
|
|
+ app = SquareWindow(config, path_info, path_mapping)
|
|
|
app.run()
|
|
app.run()
|