first commit
This commit is contained in:
parent
8508469625
commit
3b86483435
|
|
@ -1,179 +1,157 @@
|
|||
from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QPushButton,
|
||||
QLineEdit, QToolBar, QMenu, QTabWidget)
|
||||
from PySide6.QtCore import Qt, QUrl
|
||||
from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLineEdit, QLabel, QComboBox, QProgressBar
|
||||
from PySide6.QtCore import Qt, Signal, Slot, QUrl
|
||||
from PySide6.QtWebEngineWidgets import QWebEngineView
|
||||
from PySide6.QtGui import QIcon, QAction
|
||||
import os
|
||||
|
||||
# Fluent 위젯 추가
|
||||
from qfluentwidgets import (LineEdit, PushButton, ComboBox, ProgressBar, SearchLineEdit,
|
||||
ToolButton, FluentIcon, PrimaryToolButton, TransparentToolButton,
|
||||
InfoBar, InfoBarPosition, CardWidget, ExpandLayout, TitleLabel,
|
||||
SmoothScrollArea, IconWidget, setTheme, Theme)
|
||||
|
||||
class BrowserWidget(QWidget):
|
||||
# 시그널 정의
|
||||
status_changed = Signal(str)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.parent = parent
|
||||
self.setup_ui()
|
||||
|
||||
def setup_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
# 메인 레이아웃
|
||||
main_layout = QVBoxLayout(self)
|
||||
main_layout.setContentsMargins(0, 0, 0, 0)
|
||||
main_layout.setSpacing(0)
|
||||
|
||||
# 툴바 생성
|
||||
self.toolbar = QToolBar()
|
||||
self.toolbar.setMovable(False)
|
||||
# 브라우저 주소 및 컨트롤 카드
|
||||
control_card = CardWidget(self)
|
||||
control_layout = QVBoxLayout(control_card)
|
||||
|
||||
# 뒤로가기 버튼
|
||||
self.back_button = QPushButton()
|
||||
self.back_button.setIcon(QIcon("modules/assets/icons/back.png"))
|
||||
self.toolbar.addWidget(self.back_button)
|
||||
# 주소창 및 버튼 레이아웃
|
||||
address_layout = QHBoxLayout()
|
||||
|
||||
# 앞으로가기 버튼
|
||||
self.forward_button = QPushButton()
|
||||
self.forward_button.setIcon(QIcon("modules/assets/icons/forward.png"))
|
||||
self.toolbar.addWidget(self.forward_button)
|
||||
# 네비게이션 버튼
|
||||
self.back_button = TransparentToolButton(FluentIcon.CHEVRON_LEFT, self)
|
||||
self.forward_button = TransparentToolButton(FluentIcon.CHEVRON_RIGHT, self)
|
||||
self.refresh_button = TransparentToolButton(FluentIcon.REFRESH, self)
|
||||
self.home_button = TransparentToolButton(FluentIcon.HOME, self)
|
||||
|
||||
# 새로고침 버튼
|
||||
self.reload_button = QPushButton()
|
||||
self.reload_button.setIcon(QIcon("modules/assets/icons/reload.png"))
|
||||
self.toolbar.addWidget(self.reload_button)
|
||||
# 주소 입력창
|
||||
self.address_bar = SearchLineEdit(self)
|
||||
self.address_bar.setPlaceholderText("웹 주소 입력")
|
||||
self.address_bar.returnPressed.connect(self.navigate_to_url)
|
||||
|
||||
# 홈 버튼
|
||||
self.home_button = QPushButton()
|
||||
self.home_button.setIcon(QIcon("modules/assets/icons/home.png"))
|
||||
self.toolbar.addWidget(self.home_button)
|
||||
# 즐겨찾기 버튼 및 검색 버튼
|
||||
self.bookmark_button = TransparentToolButton(FluentIcon.BOOKMARK, self)
|
||||
self.search_button = PrimaryToolButton(FluentIcon.SEARCH, self)
|
||||
self.search_button.clicked.connect(self.navigate_to_url)
|
||||
|
||||
# 주소창
|
||||
self.url_bar = QLineEdit()
|
||||
self.url_bar.setPlaceholderText("주소를 입력하거나 검색어를 입력하세요")
|
||||
self.toolbar.addWidget(self.url_bar)
|
||||
# 주소창 레이아웃에 위젯 추가
|
||||
address_layout.addWidget(self.back_button)
|
||||
address_layout.addWidget(self.forward_button)
|
||||
address_layout.addWidget(self.refresh_button)
|
||||
address_layout.addWidget(self.home_button)
|
||||
address_layout.addWidget(self.address_bar)
|
||||
address_layout.addWidget(self.bookmark_button)
|
||||
address_layout.addWidget(self.search_button)
|
||||
|
||||
# 새 탭 버튼
|
||||
self.new_tab_button = QPushButton("+")
|
||||
self.new_tab_button.clicked.connect(self.add_new_tab)
|
||||
self.toolbar.addWidget(self.new_tab_button)
|
||||
# 컨트롤 레이아웃에 주소창 레이아웃 추가
|
||||
control_layout.addLayout(address_layout)
|
||||
|
||||
layout.addWidget(self.toolbar)
|
||||
# 상태 레이아웃
|
||||
status_layout = QHBoxLayout()
|
||||
|
||||
# 탭 위젯 생성
|
||||
self.tab_widget = QTabWidget()
|
||||
self.tab_widget.setTabsClosable(True)
|
||||
self.tab_widget.tabCloseRequested.connect(self.close_tab)
|
||||
layout.addWidget(self.tab_widget)
|
||||
# 상태 라벨
|
||||
self.status_label = QLabel("준비됨")
|
||||
|
||||
# 첫 번째 탭 추가
|
||||
self.add_new_tab()
|
||||
# 로딩 진행바
|
||||
self.progress_bar = ProgressBar(self)
|
||||
self.progress_bar.setRange(0, 100)
|
||||
self.progress_bar.setValue(100)
|
||||
self.progress_bar.setVisible(False)
|
||||
|
||||
# 북마크 툴바
|
||||
self.bookmark_toolbar = QToolBar()
|
||||
self.bookmark_toolbar.setMovable(False)
|
||||
layout.addWidget(self.bookmark_toolbar)
|
||||
# 상태 레이아웃에 위젯 추가
|
||||
status_layout.addWidget(self.status_label)
|
||||
status_layout.addWidget(self.progress_bar)
|
||||
|
||||
# 이벤트 연결
|
||||
self.url_bar.returnPressed.connect(self.navigate_to_url)
|
||||
self.back_button.clicked.connect(self.current_web_view().back)
|
||||
self.forward_button.clicked.connect(self.current_web_view().forward)
|
||||
self.reload_button.clicked.connect(self.current_web_view().reload)
|
||||
self.home_button.clicked.connect(self.navigate_home)
|
||||
# 컨트롤 레이아웃에 상태 레이아웃 추가
|
||||
control_layout.addLayout(status_layout)
|
||||
|
||||
# 탭 변경 시 주소창 업데이트
|
||||
self.tab_widget.currentChanged.connect(self.update_url_bar)
|
||||
# 웹뷰 생성
|
||||
self.web_view = QWebEngineView()
|
||||
self.web_view.loadStarted.connect(self.load_started)
|
||||
self.web_view.loadProgress.connect(self.load_progress)
|
||||
self.web_view.loadFinished.connect(self.load_finished)
|
||||
self.web_view.urlChanged.connect(self.url_changed)
|
||||
|
||||
def current_web_view(self):
|
||||
return self.tab_widget.currentWidget()
|
||||
|
||||
def add_new_tab(self, url="https://www.google.com"):
|
||||
web_view = QWebEngineView()
|
||||
web_view.setUrl(QUrl(url))
|
||||
# 기본 홈페이지 로드
|
||||
self.load_home_page()
|
||||
|
||||
# URL 변경 시 주소창 업데이트
|
||||
web_view.urlChanged.connect(self.update_url_bar)
|
||||
# 네비게이션 버튼 연결
|
||||
self.back_button.clicked.connect(self.web_view.back)
|
||||
self.forward_button.clicked.connect(self.web_view.forward)
|
||||
self.refresh_button.clicked.connect(self.web_view.reload)
|
||||
self.home_button.clicked.connect(self.load_home_page)
|
||||
|
||||
# 링크 클릭 시 새 탭에서 열기
|
||||
web_view.page().newWindowRequested.connect(self.handle_new_window_request)
|
||||
# 메인 레이아웃에 위젯 추가
|
||||
main_layout.addWidget(control_card)
|
||||
main_layout.addWidget(self.web_view)
|
||||
|
||||
# 컨텍스트 메뉴 설정
|
||||
web_view.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
web_view.customContextMenuRequested.connect(lambda pos: self.show_context_menu(pos, web_view))
|
||||
|
||||
index = self.tab_widget.addTab(web_view, "새 탭")
|
||||
self.tab_widget.setCurrentIndex(index)
|
||||
|
||||
# 탭 제목 업데이트
|
||||
web_view.titleChanged.connect(lambda title: self.tab_widget.setTabText(index, title[:20] if len(title) > 20 else title))
|
||||
|
||||
def close_tab(self, index):
|
||||
if self.tab_widget.count() > 1:
|
||||
self.tab_widget.removeTab(index)
|
||||
else:
|
||||
self.current_web_view().setUrl(QUrl("https://www.google.com"))
|
||||
|
||||
def handle_new_window_request(self, request):
|
||||
url = request.requestedUrl().toString()
|
||||
new_web_view = QWebEngineView()
|
||||
new_web_view.setUrl(QUrl(url))
|
||||
index = self.tab_widget.addTab(new_web_view, "새 탭")
|
||||
self.tab_widget.setCurrentIndex(index)
|
||||
|
||||
# URL 변경 시 주소창 업데이트
|
||||
new_web_view.urlChanged.connect(self.update_url_bar)
|
||||
|
||||
# 컨텍스트 메뉴 설정
|
||||
new_web_view.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
new_web_view.customContextMenuRequested.connect(lambda pos: self.show_context_menu(pos, new_web_view))
|
||||
|
||||
# 탭 제목 업데이트
|
||||
new_web_view.titleChanged.connect(lambda title: self.tab_widget.setTabText(index, title[:20] if len(title) > 20 else title))
|
||||
|
||||
request.accept()
|
||||
|
||||
def navigate_to_url(self):
|
||||
url = self.url_bar.text()
|
||||
if not url.startswith(('http://', 'https://')):
|
||||
url = 'https://www.google.com/search?q=' + url
|
||||
self.current_web_view().setUrl(QUrl(url))
|
||||
|
||||
def navigate_home(self):
|
||||
self.current_web_view().setUrl(QUrl("https://www.google.com"))
|
||||
|
||||
def update_url_bar(self):
|
||||
current_url = self.current_web_view().url().toString()
|
||||
self.url_bar.setText(current_url)
|
||||
|
||||
def show_context_menu(self, position, web_view):
|
||||
context_menu = QMenu(self)
|
||||
url_text = self.address_bar.text().strip()
|
||||
if not url_text:
|
||||
return
|
||||
|
||||
if not url_text.startswith(('http://', 'https://')):
|
||||
# 검색어로 간주하고 검색 페이지로 이동
|
||||
if ' ' in url_text:
|
||||
self.search_term(url_text)
|
||||
return
|
||||
# http:// 추가
|
||||
url_text = 'http://' + url_text
|
||||
|
||||
self.web_view.setUrl(QUrl(url_text))
|
||||
self.status_changed.emit(f"이동: {url_text}")
|
||||
|
||||
# 기본 메뉴 항목
|
||||
back_action = QAction("뒤로 가기", self)
|
||||
forward_action = QAction("앞으로 가기", self)
|
||||
reload_action = QAction("새로고침", self)
|
||||
def search_term(self, term):
|
||||
# 네이버 검색 사용
|
||||
search_url = f"https://search.naver.com/search.naver?query={term}"
|
||||
self.web_view.setUrl(QUrl(search_url))
|
||||
self.status_changed.emit(f"검색: {term}")
|
||||
|
||||
# 커스텀 메뉴 항목
|
||||
search_action = QAction("지재권 검색", self)
|
||||
add_forbidden_action = QAction("금지어 추가", self)
|
||||
naver_search_action = QAction("네이버 검색", self)
|
||||
def load_started(self):
|
||||
self.progress_bar.setVisible(True)
|
||||
self.progress_bar.setValue(0)
|
||||
self.status_label.setText("로딩 중...")
|
||||
self.status_changed.emit("페이지 로딩 시작")
|
||||
|
||||
context_menu.addAction(back_action)
|
||||
context_menu.addAction(forward_action)
|
||||
context_menu.addAction(reload_action)
|
||||
context_menu.addSeparator()
|
||||
context_menu.addAction(search_action)
|
||||
context_menu.addAction(add_forbidden_action)
|
||||
context_menu.addAction(naver_search_action)
|
||||
def load_progress(self, progress):
|
||||
self.progress_bar.setValue(progress)
|
||||
|
||||
# 메뉴 표시
|
||||
action = context_menu.exec_(web_view.mapToGlobal(position))
|
||||
def load_finished(self, success):
|
||||
self.progress_bar.setVisible(False)
|
||||
if success:
|
||||
self.status_label.setText("로딩 완료")
|
||||
self.status_changed.emit("페이지 로딩 완료")
|
||||
else:
|
||||
self.status_label.setText("로딩 실패")
|
||||
self.status_changed.emit("페이지 로딩 실패")
|
||||
self.show_error_message("페이지를 로드할 수 없습니다")
|
||||
|
||||
def url_changed(self, url):
|
||||
self.address_bar.setText(url.toString())
|
||||
|
||||
# 액션 처리
|
||||
if action == back_action:
|
||||
web_view.back()
|
||||
elif action == forward_action:
|
||||
web_view.forward()
|
||||
elif action == reload_action:
|
||||
web_view.reload()
|
||||
elif action == search_action:
|
||||
selected_text = web_view.selectedText()
|
||||
if selected_text:
|
||||
print(f"지재권 검색을 클릭했습니다: {selected_text}")
|
||||
# TODO: 실제 지재권 검색 기능 구현
|
||||
elif action == add_forbidden_action:
|
||||
# TODO: 금지어 추가 기능 구현
|
||||
pass
|
||||
elif action == naver_search_action:
|
||||
selected_text = web_view.selectedText()
|
||||
if selected_text:
|
||||
naver_url = f"https://search.naver.com/search.naver?query={selected_text}"
|
||||
self.add_new_tab(naver_url)
|
||||
def load_home_page(self):
|
||||
# 기본 홈페이지 설정 (여기서는 네이버)
|
||||
self.web_view.setUrl(QUrl("https://www.naver.com"))
|
||||
self.status_changed.emit("홈페이지 로드")
|
||||
|
||||
def show_error_message(self, message):
|
||||
InfoBar.error(
|
||||
title="오류",
|
||||
content=message,
|
||||
parent=self,
|
||||
position=InfoBarPosition.TOP,
|
||||
duration=3000
|
||||
)
|
||||
|
|
@ -10,14 +10,23 @@ from modules.tools.category_manager import CategoryManager
|
|||
import logging
|
||||
import os
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
# Fluent Widgets 추가
|
||||
from qfluentwidgets import (FluentWindow, NavigationItemPosition, FluentIcon,
|
||||
MessageBox, setTheme, Theme, FluentStyleSheet, InfoBar,
|
||||
InfoBarPosition, setFont)
|
||||
from qfluentwidgets import FluentTranslator
|
||||
|
||||
class MainWindow(FluentWindow):
|
||||
# 시그널 정의
|
||||
status_changed = Signal(str)
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setWindowTitle("MyCar Browser")
|
||||
self.setMinimumSize(1200, 800)
|
||||
self.resize(1200, 800)
|
||||
|
||||
# Fluent 디자인 테마 설정
|
||||
setTheme(Theme.AUTO)
|
||||
|
||||
# 로깅 설정
|
||||
self.setup_logger()
|
||||
|
|
@ -66,20 +75,10 @@ class MainWindow(QMainWindow):
|
|||
|
||||
def initUI(self):
|
||||
"""UI 관련 코드 초기화"""
|
||||
# 메인 위젯 설정
|
||||
self.central_widget = QWidget()
|
||||
self.setCentralWidget(self.central_widget)
|
||||
|
||||
# 레이아웃 설정
|
||||
self.main_layout = QVBoxLayout(self.central_widget)
|
||||
|
||||
# 메뉴바 설정
|
||||
self.menu_bar = MenuBar(self)
|
||||
self.setMenuBar(self.menu_bar)
|
||||
|
||||
# 스플리터 설정 (브라우저와 도구 영역)
|
||||
self.splitter = QSplitter(Qt.Horizontal)
|
||||
# 브라우저 위젯 생성
|
||||
self.browser_widget = BrowserWidget()
|
||||
|
||||
# 도구 위젯 생성
|
||||
self.tools_widget = ToolsWidget(
|
||||
parent=self,
|
||||
thread_pool=self.thread_pool,
|
||||
|
|
@ -88,29 +87,38 @@ class MainWindow(QMainWindow):
|
|||
category_manager=self.category_manager
|
||||
)
|
||||
|
||||
self.splitter.addWidget(self.browser_widget)
|
||||
self.splitter.addWidget(self.tools_widget)
|
||||
self.splitter.setStretchFactor(0, 7) # 브라우저 영역 70%
|
||||
self.splitter.setStretchFactor(1, 3) # 도구 영역 30%
|
||||
|
||||
self.main_layout.addWidget(self.splitter)
|
||||
|
||||
# 상태바 설정
|
||||
self.status_bar = StatusBar()
|
||||
self.setStatusBar(self.status_bar)
|
||||
|
||||
# 스타일 설정
|
||||
self.setStyleSheet("""
|
||||
QMainWindow {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
QSplitter::handle {
|
||||
background-color: #cccccc;
|
||||
}
|
||||
QSplitter::handle:horizontal {
|
||||
width: 2px;
|
||||
}
|
||||
""")
|
||||
# Fluent 스타일의 내비게이션 추가
|
||||
self.addSubInterface(self.browser_widget, FluentIcon.GLOBE, "브라우저")
|
||||
self.addSubInterface(self.tools_widget, FluentIcon.SETTING, "도구")
|
||||
|
||||
# 추가 도구 메뉴 추가
|
||||
self.navigationInterface().addSeparator()
|
||||
|
||||
# 로그 메뉴 추가
|
||||
self.navigationInterface().addItem(
|
||||
routeKey='logs',
|
||||
icon=FluentIcon.SCROLL,
|
||||
text='로그',
|
||||
position=NavigationItemPosition.BOTTOM
|
||||
)
|
||||
|
||||
# 설정 메뉴 추가
|
||||
self.navigationInterface().addItem(
|
||||
routeKey='settings',
|
||||
icon=FluentIcon.SETTING,
|
||||
text='설정',
|
||||
position=NavigationItemPosition.BOTTOM
|
||||
)
|
||||
|
||||
# 기본 페이지 설정
|
||||
self.navigationInterface().setCurrentItem("브라우저")
|
||||
|
||||
# 로고 이미지 설정
|
||||
# self.setWindowIcon(FluentIcon.CAR)
|
||||
|
||||
self.logger.info("UI 초기화 완료")
|
||||
|
||||
|
|
@ -129,4 +137,23 @@ class MainWindow(QMainWindow):
|
|||
def update_status(self, message):
|
||||
"""상태바 메시지 업데이트"""
|
||||
self.status_changed.emit(message)
|
||||
self.logger.info(f"상태 메시지: {message}")
|
||||
self.logger.info(f"상태 메시지: {message}")
|
||||
|
||||
# Fluent 스타일 알림 표시
|
||||
InfoBar.success(
|
||||
title='알림',
|
||||
content=message,
|
||||
duration=2000,
|
||||
position=InfoBarPosition.BOTTOM_RIGHT,
|
||||
parent=self
|
||||
)
|
||||
|
||||
def showMessageBox(self, title, content):
|
||||
"""Fluent 스타일 메시지 박스 표시"""
|
||||
w = MessageBox(title, content, self)
|
||||
w.show()
|
||||
|
||||
def closeEvent(self, event):
|
||||
"""앱 종료 시 이벤트 처리"""
|
||||
self.logger.info("애플리케이션 종료")
|
||||
super().closeEvent(event)
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
from PySide6.QtWidgets import QStatusBar, QLabel
|
||||
from PySide6.QtWidgets import QStatusBar, QLabel, QHBoxLayout
|
||||
from PySide6.QtCore import Qt
|
||||
from qfluentwidgets import StateToolTip, ProgressBar, PushButton, FluentIcon
|
||||
|
||||
class StatusBar(QStatusBar):
|
||||
def __init__(self, parent=None):
|
||||
|
|
@ -9,28 +10,53 @@ class StatusBar(QStatusBar):
|
|||
def setup_ui(self):
|
||||
# 상태 메시지 레이블
|
||||
self.status_label = QLabel()
|
||||
self.status_label.setStyleSheet("color: #555555; padding: 2px;")
|
||||
self.addWidget(self.status_label)
|
||||
|
||||
# 로그인 상태 레이블
|
||||
self.login_status_label = QLabel("로그인되지 않음")
|
||||
self.login_status_label.setStyleSheet("color: #777777; padding: 2px;")
|
||||
self.addPermanentWidget(self.login_status_label)
|
||||
|
||||
# 스타일 설정
|
||||
# 전체 상태바 스타일 설정
|
||||
self.setStyleSheet("""
|
||||
QStatusBar {
|
||||
background-color: #f0f0f0;
|
||||
border-top: 1px solid #cccccc;
|
||||
background-color: #f5f5f5;
|
||||
border-top: 1px solid #e0e0e0;
|
||||
min-height: 24px;
|
||||
padding: 0;
|
||||
}
|
||||
QLabel {
|
||||
padding: 2px;
|
||||
font-size: 12px;
|
||||
margin: 0 5px;
|
||||
}
|
||||
""")
|
||||
|
||||
def set_status_message(self, message):
|
||||
"""상태 메시지 설정"""
|
||||
self.status_label.setText(message)
|
||||
|
||||
def set_login_status(self, is_logged_in):
|
||||
"""로그인 상태 설정"""
|
||||
if is_logged_in:
|
||||
self.login_status_label.setText("로그인됨")
|
||||
self.login_status_label.setStyleSheet("color: #4caf50; padding: 2px; font-weight: bold;")
|
||||
else:
|
||||
self.login_status_label.setText("로그인되지 않음")
|
||||
self.login_status_label.setText("로그인되지 않음")
|
||||
self.login_status_label.setStyleSheet("color: #777777; padding: 2px;")
|
||||
|
||||
def show_progress(self, title, content):
|
||||
"""진행 상태 툴팁 표시 (오버레이 형태)"""
|
||||
state_tooltip = StateToolTip(title, content, self.parent())
|
||||
state_tooltip.show()
|
||||
return state_tooltip
|
||||
|
||||
def update_progress(self, state_tooltip, progress, content=None):
|
||||
"""진행 상태 업데이트"""
|
||||
if progress >= 100:
|
||||
state_tooltip.setContent(content or "완료되었습니다")
|
||||
state_tooltip.setState(True)
|
||||
else:
|
||||
if content:
|
||||
state_tooltip.setContent(content)
|
||||
state_tooltip.setProgress(progress)
|
||||
|
|
@ -3,7 +3,13 @@ from PySide6.QtWidgets import (QWidget, QVBoxLayout, QTabWidget, QPushButton,
|
|||
from PySide6.QtCore import Qt, Signal, Slot
|
||||
from modules.xlsFilter.xls_filter_dialog import XlsFilterDialog
|
||||
|
||||
class ToolsWidget(QWidget):
|
||||
# Fluent Widgets 추가
|
||||
from qfluentwidgets import (ScrollArea, ExpandLayout, SimpleCardWidget, SettingCardGroup,
|
||||
SwitchSettingCard, ComboBoxSettingCard, ToolButton, FluentIcon,
|
||||
PrimaryPushButton, InfoBar, InfoBarPosition, SpinBox, LineEdit,
|
||||
TextEdit, ListWidget, PushButton, TabWidget, SmoothScrollArea)
|
||||
|
||||
class ToolsWidget(ScrollArea):
|
||||
# 시그널 정의
|
||||
status_changed = Signal(str)
|
||||
|
||||
|
|
@ -24,10 +30,15 @@ class ToolsWidget(QWidget):
|
|||
self.logger.info("도구 위젯 초기화 완료")
|
||||
|
||||
def setup_ui(self):
|
||||
layout = QVBoxLayout(self)
|
||||
# 스크롤 영역 설정
|
||||
self.setWidgetResizable(True)
|
||||
|
||||
# 메인 위젯 및 레이아웃
|
||||
self.main_widget = QWidget()
|
||||
self.expand_layout = ExpandLayout(self.main_widget)
|
||||
|
||||
# 탭 위젯 생성
|
||||
self.tab_widget = QTabWidget()
|
||||
self.tab_widget = TabWidget(self.main_widget)
|
||||
|
||||
# 배송비 계산기 탭
|
||||
self.shipping_calc_tab = QWidget()
|
||||
|
|
@ -54,126 +65,236 @@ class ToolsWidget(QWidget):
|
|||
self.setup_xls_filter_tab()
|
||||
self.tab_widget.addTab(self.xls_filter_tab, "엑셀 필터링")
|
||||
|
||||
layout.addWidget(self.tab_widget)
|
||||
# 카드 그룹 추가
|
||||
card_group = SettingCardGroup("도구 모음", self.main_widget)
|
||||
card_text = "다양한 도구를 탭을 통해 사용할 수 있습니다."
|
||||
|
||||
# 도구 카드 추가
|
||||
self.tools_card = SimpleCardWidget(FluentIcon.SETTING, "도구 모음", card_text, self.main_widget)
|
||||
self.tools_card.setFixedHeight(120)
|
||||
self.tools_card.setFixedWidth(self.width())
|
||||
|
||||
# 레이아웃에 위젯 추가
|
||||
self.expand_layout.addWidget(self.tools_card)
|
||||
self.expand_layout.addWidget(card_group)
|
||||
self.expand_layout.addWidget(self.tab_widget)
|
||||
|
||||
# 위젯 설정
|
||||
self.setWidget(self.main_widget)
|
||||
|
||||
def setup_shipping_calc_tab(self):
|
||||
layout = QVBoxLayout(self.shipping_calc_tab)
|
||||
|
||||
# 설정 카드 그룹
|
||||
card_group = SettingCardGroup("배송비 계산", self.shipping_calc_tab)
|
||||
|
||||
# 무게 입력
|
||||
weight_label = QLabel("무게 (kg):")
|
||||
self.weight_input = QLineEdit()
|
||||
layout.addWidget(weight_label)
|
||||
layout.addWidget(self.weight_input)
|
||||
self.weight_input = SpinBox(self.shipping_calc_tab)
|
||||
self.weight_input.setRange(0, 100)
|
||||
self.weight_input.setSuffix(" kg")
|
||||
self.weight_input.setToolTip("배송 상품의 무게를 입력하세요")
|
||||
weight_card = ComboBoxSettingCard(
|
||||
FluentIcon.WEIGHT,
|
||||
"무게",
|
||||
"배송 상품의 무게를 입력하세요",
|
||||
customWidget=self.weight_input,
|
||||
parent=card_group
|
||||
)
|
||||
|
||||
# 지역 선택
|
||||
region_label = QLabel("지역:")
|
||||
self.region_input = QLineEdit()
|
||||
layout.addWidget(region_label)
|
||||
layout.addWidget(self.region_input)
|
||||
self.region_input = LineEdit(self.shipping_calc_tab)
|
||||
self.region_input.setPlaceholderText("배송 지역")
|
||||
region_card = ComboBoxSettingCard(
|
||||
FluentIcon.GLOBE,
|
||||
"지역",
|
||||
"배송 지역을 입력하세요",
|
||||
customWidget=self.region_input,
|
||||
parent=card_group
|
||||
)
|
||||
|
||||
# 카드 그룹에 추가
|
||||
card_group.addSettingCard(weight_card)
|
||||
card_group.addSettingCard(region_card)
|
||||
|
||||
# 계산 버튼
|
||||
calc_button = QPushButton("계산하기")
|
||||
calc_button.clicked.connect(self.calculate_shipping)
|
||||
layout.addWidget(calc_button)
|
||||
self.calc_button = PrimaryPushButton("계산하기")
|
||||
self.calc_button.clicked.connect(self.calculate_shipping)
|
||||
|
||||
# 결과 표시
|
||||
self.result_label = QLabel("배송비: ")
|
||||
layout.addWidget(self.result_label)
|
||||
|
||||
# 레이아웃에 위젯 추가
|
||||
layout.addWidget(card_group)
|
||||
layout.addWidget(self.calc_button)
|
||||
layout.addWidget(self.result_label)
|
||||
layout.addStretch()
|
||||
|
||||
def setup_forbidden_words_tab(self):
|
||||
layout = QVBoxLayout(self.forbidden_words_tab)
|
||||
|
||||
# 설정 카드 그룹
|
||||
card_group = SettingCardGroup("금지어 관리", self.forbidden_words_tab)
|
||||
|
||||
# 금지어 입력
|
||||
self.word_input = QLineEdit()
|
||||
self.word_input = LineEdit(self.forbidden_words_tab)
|
||||
self.word_input.setPlaceholderText("금지어 입력")
|
||||
layout.addWidget(self.word_input)
|
||||
word_card = ComboBoxSettingCard(
|
||||
FluentIcon.REMOVE,
|
||||
"금지어",
|
||||
"추가할 금지어를 입력하세요. 콤마 또는 공백으로 구분하여 여러 개 입력 가능합니다.",
|
||||
customWidget=self.word_input,
|
||||
parent=card_group
|
||||
)
|
||||
card_group.addSettingCard(word_card)
|
||||
|
||||
# 추가 버튼
|
||||
add_button = QPushButton("추가")
|
||||
add_button.clicked.connect(self.add_forbidden_word)
|
||||
layout.addWidget(add_button)
|
||||
self.add_button = PrimaryPushButton("추가")
|
||||
self.add_button.clicked.connect(self.add_forbidden_word)
|
||||
|
||||
# 금지어 목록
|
||||
self.word_list = QListWidget()
|
||||
layout.addWidget(self.word_list)
|
||||
self.word_list = ListWidget(self.forbidden_words_tab)
|
||||
|
||||
# 삭제 버튼
|
||||
delete_button = QPushButton("선택 삭제")
|
||||
delete_button.clicked.connect(self.delete_forbidden_word)
|
||||
layout.addWidget(delete_button)
|
||||
self.delete_button = PushButton("선택 삭제")
|
||||
self.delete_button.setIcon(FluentIcon.DELETE)
|
||||
self.delete_button.clicked.connect(self.delete_forbidden_word)
|
||||
|
||||
# 금지어 목록 로드
|
||||
if self.forbidden_words:
|
||||
self.load_forbidden_words()
|
||||
|
||||
# 레이아웃에 위젯 추가
|
||||
layout.addWidget(card_group)
|
||||
layout.addWidget(self.add_button)
|
||||
layout.addWidget(self.word_list)
|
||||
layout.addWidget(self.delete_button)
|
||||
|
||||
def setup_category_tab(self):
|
||||
layout = QVBoxLayout(self.category_tab)
|
||||
|
||||
# 설정 카드 그룹
|
||||
card_group = SettingCardGroup("카테고리 관리", self.category_tab)
|
||||
|
||||
# 카테고리 입력
|
||||
self.category_input = QLineEdit()
|
||||
self.category_input = LineEdit(self.category_tab)
|
||||
self.category_input.setPlaceholderText("카테고리 입력")
|
||||
layout.addWidget(self.category_input)
|
||||
category_card = ComboBoxSettingCard(
|
||||
FluentIcon.FOLDER,
|
||||
"카테고리",
|
||||
"추가할 카테고리를 입력하세요",
|
||||
customWidget=self.category_input,
|
||||
parent=card_group
|
||||
)
|
||||
card_group.addSettingCard(category_card)
|
||||
|
||||
# 추가 버튼
|
||||
add_button = QPushButton("추가")
|
||||
add_button.clicked.connect(self.add_category)
|
||||
layout.addWidget(add_button)
|
||||
self.add_cat_button = PrimaryPushButton("추가")
|
||||
self.add_cat_button.clicked.connect(self.add_category)
|
||||
|
||||
# 카테고리 목록
|
||||
self.category_list = QListWidget()
|
||||
layout.addWidget(self.category_list)
|
||||
self.category_list = ListWidget(self.category_tab)
|
||||
|
||||
# 삭제 버튼
|
||||
delete_button = QPushButton("선택 삭제")
|
||||
delete_button.clicked.connect(self.delete_category)
|
||||
layout.addWidget(delete_button)
|
||||
self.delete_cat_button = PushButton("선택 삭제")
|
||||
self.delete_cat_button.setIcon(FluentIcon.DELETE)
|
||||
self.delete_cat_button.clicked.connect(self.delete_category)
|
||||
|
||||
# 카테고리 목록 로드
|
||||
if self.category_manager:
|
||||
self.load_categories()
|
||||
|
||||
# 레이아웃에 위젯 추가
|
||||
layout.addWidget(card_group)
|
||||
layout.addWidget(self.add_cat_button)
|
||||
layout.addWidget(self.category_list)
|
||||
layout.addWidget(self.delete_cat_button)
|
||||
|
||||
def setup_log_tab(self):
|
||||
layout = QVBoxLayout(self.log_tab)
|
||||
|
||||
# 설정 카드 그룹
|
||||
card_group = SettingCardGroup("로그 관리", self.log_tab)
|
||||
card_group.addSettingCard(SwitchSettingCard(
|
||||
FluentIcon.HISTORY,
|
||||
"자동 저장",
|
||||
"로그를 자동으로 파일에 저장합니다",
|
||||
True,
|
||||
parent=card_group
|
||||
))
|
||||
|
||||
# 로그 표시 영역
|
||||
self.log_text = QTextEdit()
|
||||
self.log_text = TextEdit(self.log_tab)
|
||||
self.log_text.setReadOnly(True)
|
||||
layout.addWidget(self.log_text)
|
||||
|
||||
# 로그 정리 버튼
|
||||
clear_button = QPushButton("로그 정리")
|
||||
clear_button.clicked.connect(self.clear_logs)
|
||||
layout.addWidget(clear_button)
|
||||
self.clear_button = PushButton("로그 정리")
|
||||
self.clear_button.setIcon(FluentIcon.CLEAR)
|
||||
self.clear_button.clicked.connect(self.clear_logs)
|
||||
|
||||
# 레이아웃에 위젯 추가
|
||||
layout.addWidget(card_group)
|
||||
layout.addWidget(self.log_text)
|
||||
layout.addWidget(self.clear_button)
|
||||
|
||||
def setup_xls_filter_tab(self):
|
||||
layout = QVBoxLayout(self.xls_filter_tab)
|
||||
|
||||
# 엑셀 필터링 버튼
|
||||
filter_button = QPushButton("엑셀 필터링 실행")
|
||||
filter_button.clicked.connect(self.run_xls_filter)
|
||||
layout.addWidget(filter_button)
|
||||
# 설정 카드 그룹
|
||||
card_group = SettingCardGroup("엑셀 필터링", self.xls_filter_tab)
|
||||
card_text = "엑셀 파일에서 상품 정보를 추출하고 금지어/카테고리를 필터링합니다."
|
||||
|
||||
info_card = SimpleCardWidget(FluentIcon.FILTER, "엑셀 필터링", card_text, self.xls_filter_tab)
|
||||
info_card.setFixedHeight(120)
|
||||
|
||||
# 엑셀 필터링 버튼
|
||||
self.filter_button = PrimaryPushButton("엑셀 필터링 실행")
|
||||
self.filter_button.setIcon(FluentIcon.FILTER)
|
||||
self.filter_button.clicked.connect(self.run_xls_filter)
|
||||
|
||||
# 레이아웃에 위젯 추가
|
||||
layout.addWidget(card_group)
|
||||
layout.addWidget(info_card)
|
||||
layout.addWidget(self.filter_button)
|
||||
layout.addStretch()
|
||||
|
||||
def calculate_shipping(self):
|
||||
weight = self.weight_input.text()
|
||||
weight = self.weight_input.value()
|
||||
region = self.region_input.text()
|
||||
|
||||
if not weight or not region:
|
||||
if not region:
|
||||
self.show_info_bar("경고", "지역을 입력해주세요", InfoBarPosition.TOP, True)
|
||||
self.status_changed.emit("무게와 지역을 입력해주세요.")
|
||||
return
|
||||
|
||||
try:
|
||||
weight = float(weight)
|
||||
# 여기에서 실제 배송비 계산 로직을 구현
|
||||
shipping_cost = weight * 2500 # 예시 계산 로직
|
||||
self.result_label.setText(f"배송비: {shipping_cost:,} 원")
|
||||
self.status_changed.emit(f"배송비 계산 완료: {shipping_cost:,} 원")
|
||||
self.show_info_bar("완료", f"배송비 계산 완료: {shipping_cost:,} 원", InfoBarPosition.BOTTOM_RIGHT)
|
||||
except ValueError:
|
||||
self.show_info_bar("오류", "무게는 숫자로 입력해주세요.", InfoBarPosition.TOP, True)
|
||||
self.status_changed.emit("무게는 숫자로 입력해주세요.")
|
||||
|
||||
|
||||
def show_info_bar(self, title, content, position=InfoBarPosition.TOP, is_error=False):
|
||||
"""정보 바 표시"""
|
||||
if is_error:
|
||||
InfoBar.error(
|
||||
title=title,
|
||||
content=content,
|
||||
parent=self,
|
||||
position=position,
|
||||
duration=3000
|
||||
)
|
||||
else:
|
||||
InfoBar.success(
|
||||
title=title,
|
||||
content=content,
|
||||
parent=self,
|
||||
position=position,
|
||||
duration=3000
|
||||
)
|
||||
|
||||
def load_forbidden_words(self):
|
||||
"""금지어 목록 로드"""
|
||||
if self.logger:
|
||||
|
|
@ -193,6 +314,7 @@ class ToolsWidget(QWidget):
|
|||
if self.forbidden_words:
|
||||
self.forbidden_words.add_word(word)
|
||||
self.status_changed.emit(f"금지어 '{word}' 추가됨")
|
||||
self.show_info_bar("추가 완료", f"금지어 '{word}' 추가됨", InfoBarPosition.BOTTOM_RIGHT)
|
||||
self.word_list.addItem(word)
|
||||
self.word_input.clear()
|
||||
|
||||
|
|
@ -203,6 +325,7 @@ class ToolsWidget(QWidget):
|
|||
if self.forbidden_words:
|
||||
self.forbidden_words.remove_word(word)
|
||||
self.status_changed.emit(f"금지어 '{word}' 삭제됨")
|
||||
self.show_info_bar("삭제 완료", f"금지어 '{word}' 삭제됨", InfoBarPosition.BOTTOM_RIGHT)
|
||||
self.word_list.takeItem(self.word_list.row(current_item))
|
||||
|
||||
def load_categories(self):
|
||||
|
|
@ -224,6 +347,7 @@ class ToolsWidget(QWidget):
|
|||
if self.category_manager:
|
||||
self.category_manager.add_category(category)
|
||||
self.status_changed.emit(f"카테고리 '{category}' 추가됨")
|
||||
self.show_info_bar("추가 완료", f"카테고리 '{category}' 추가됨", InfoBarPosition.BOTTOM_RIGHT)
|
||||
self.category_list.addItem(category)
|
||||
self.category_input.clear()
|
||||
|
||||
|
|
@ -234,11 +358,13 @@ class ToolsWidget(QWidget):
|
|||
if self.category_manager:
|
||||
self.category_manager.remove_category(category)
|
||||
self.status_changed.emit(f"카테고리 '{category}' 삭제됨")
|
||||
self.show_info_bar("삭제 완료", f"카테고리 '{category}' 삭제됨", InfoBarPosition.BOTTOM_RIGHT)
|
||||
self.category_list.takeItem(self.category_list.row(current_item))
|
||||
|
||||
def clear_logs(self):
|
||||
self.log_text.clear()
|
||||
self.status_changed.emit("로그가 정리되었습니다.")
|
||||
self.show_info_bar("완료", "로그가 정리되었습니다", InfoBarPosition.BOTTOM_RIGHT)
|
||||
|
||||
def run_xls_filter(self):
|
||||
if self.logger:
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ selenium = "^4.31.0"
|
|||
webdriver-manager = "^4.0.2"
|
||||
pandas = "^2.2.2"
|
||||
openpyxl = "^3.1.2"
|
||||
PySide6-Fluent-Widgets = "^1.5.0"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
|
|
|
|||
Loading…
Reference in New Issue