first commit

This commit is contained in:
9700X_PC 2025-04-25 16:52:49 +09:00
parent 8508469625
commit 3b86483435
5 changed files with 396 additions and 238 deletions

View File

@ -1,179 +1,157 @@
from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QPushButton, from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLineEdit, QLabel, QComboBox, QProgressBar
QLineEdit, QToolBar, QMenu, QTabWidget) from PySide6.QtCore import Qt, Signal, Slot, QUrl
from PySide6.QtCore import Qt, QUrl
from PySide6.QtWebEngineWidgets import QWebEngineView 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): class BrowserWidget(QWidget):
# 시그널 정의
status_changed = Signal(str)
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self.parent = parent
self.setup_ui() self.setup_ui()
def setup_ui(self): 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() control_card = CardWidget(self)
self.toolbar.setMovable(False) control_layout = QVBoxLayout(control_card)
# 뒤로가기 버튼 # 주소창 및 버튼 레이아웃
self.back_button = QPushButton() address_layout = QHBoxLayout()
self.back_button.setIcon(QIcon("modules/assets/icons/back.png"))
self.toolbar.addWidget(self.back_button)
# 앞으로가기 버튼 # 네비게이션 버튼
self.forward_button = QPushButton() self.back_button = TransparentToolButton(FluentIcon.CHEVRON_LEFT, self)
self.forward_button.setIcon(QIcon("modules/assets/icons/forward.png")) self.forward_button = TransparentToolButton(FluentIcon.CHEVRON_RIGHT, self)
self.toolbar.addWidget(self.forward_button) self.refresh_button = TransparentToolButton(FluentIcon.REFRESH, self)
self.home_button = TransparentToolButton(FluentIcon.HOME, self)
# 새로고침 버튼 # 주소 입력창
self.reload_button = QPushButton() self.address_bar = SearchLineEdit(self)
self.reload_button.setIcon(QIcon("modules/assets/icons/reload.png")) self.address_bar.setPlaceholderText("웹 주소 입력")
self.toolbar.addWidget(self.reload_button) self.address_bar.returnPressed.connect(self.navigate_to_url)
# 버튼 # 즐겨찾기 버튼 및 검색 버튼
self.home_button = QPushButton() self.bookmark_button = TransparentToolButton(FluentIcon.BOOKMARK, self)
self.home_button.setIcon(QIcon("modules/assets/icons/home.png")) self.search_button = PrimaryToolButton(FluentIcon.SEARCH, self)
self.toolbar.addWidget(self.home_button) self.search_button.clicked.connect(self.navigate_to_url)
# 주소창 # 주소창 레이아웃에 위젯 추가
self.url_bar = QLineEdit() address_layout.addWidget(self.back_button)
self.url_bar.setPlaceholderText("주소를 입력하거나 검색어를 입력하세요") address_layout.addWidget(self.forward_button)
self.toolbar.addWidget(self.url_bar) 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("+") control_layout.addLayout(address_layout)
self.new_tab_button.clicked.connect(self.add_new_tab)
self.toolbar.addWidget(self.new_tab_button)
layout.addWidget(self.toolbar) # 상태 레이아웃
status_layout = QHBoxLayout()
# 탭 위젯 생성 # 상태 라벨
self.tab_widget = QTabWidget() self.status_label = QLabel("준비됨")
self.tab_widget.setTabsClosable(True)
self.tab_widget.tabCloseRequested.connect(self.close_tab)
layout.addWidget(self.tab_widget)
# 첫 번째 탭 추가 # 로딩 진행바
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() status_layout.addWidget(self.status_label)
self.bookmark_toolbar.setMovable(False) status_layout.addWidget(self.progress_bar)
layout.addWidget(self.bookmark_toolbar)
# 이벤트 연결 # 컨트롤 레이아웃에 상태 레이아웃 추가
self.url_bar.returnPressed.connect(self.navigate_to_url) control_layout.addLayout(status_layout)
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)
# 탭 변경 시 주소창 업데이트 # 웹뷰 생성
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() self.load_home_page()
def add_new_tab(self, url="https://www.google.com"):
web_view = QWebEngineView()
web_view.setUrl(QUrl(url))
# 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): def navigate_to_url(self):
url = self.url_bar.text() url_text = self.address_bar.text().strip()
if not url.startswith(('http://', 'https://')): if not url_text:
url = 'https://www.google.com/search?q=' + url return
self.current_web_view().setUrl(QUrl(url))
if not url_text.startswith(('http://', 'https://')):
def navigate_home(self): # 검색어로 간주하고 검색 페이지로 이동
self.current_web_view().setUrl(QUrl("https://www.google.com")) if ' ' in url_text:
self.search_term(url_text)
def update_url_bar(self): return
current_url = self.current_web_view().url().toString() # http:// 추가
self.url_bar.setText(current_url) url_text = 'http://' + url_text
def show_context_menu(self, position, web_view): self.web_view.setUrl(QUrl(url_text))
context_menu = QMenu(self) self.status_changed.emit(f"이동: {url_text}")
# 기본 메뉴 항목 def search_term(self, term):
back_action = QAction("뒤로 가기", self) # 네이버 검색 사용
forward_action = QAction("앞으로 가기", self) search_url = f"https://search.naver.com/search.naver?query={term}"
reload_action = QAction("새로고침", self) self.web_view.setUrl(QUrl(search_url))
self.status_changed.emit(f"검색: {term}")
# 커스텀 메뉴 항목 def load_started(self):
search_action = QAction("지재권 검색", self) self.progress_bar.setVisible(True)
add_forbidden_action = QAction("금지어 추가", self) self.progress_bar.setValue(0)
naver_search_action = QAction("네이버 검색", self) self.status_label.setText("로딩 중...")
self.status_changed.emit("페이지 로딩 시작")
context_menu.addAction(back_action) def load_progress(self, progress):
context_menu.addAction(forward_action) self.progress_bar.setValue(progress)
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_finished(self, success):
action = context_menu.exec_(web_view.mapToGlobal(position)) 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())
# 액션 처리 def load_home_page(self):
if action == back_action: # 기본 홈페이지 설정 (여기서는 네이버)
web_view.back() self.web_view.setUrl(QUrl("https://www.naver.com"))
elif action == forward_action: self.status_changed.emit("홈페이지 로드")
web_view.forward()
elif action == reload_action: def show_error_message(self, message):
web_view.reload() InfoBar.error(
elif action == search_action: title="오류",
selected_text = web_view.selectedText() content=message,
if selected_text: parent=self,
print(f"지재권 검색을 클릭했습니다: {selected_text}") position=InfoBarPosition.TOP,
# TODO: 실제 지재권 검색 기능 구현 duration=3000
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)

View File

@ -10,14 +10,23 @@ from modules.tools.category_manager import CategoryManager
import logging import logging
import os 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) status_changed = Signal(str)
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.setWindowTitle("MyCar Browser") self.setWindowTitle("MyCar Browser")
self.setMinimumSize(1200, 800) self.resize(1200, 800)
# Fluent 디자인 테마 설정
setTheme(Theme.AUTO)
# 로깅 설정 # 로깅 설정
self.setup_logger() self.setup_logger()
@ -66,20 +75,10 @@ class MainWindow(QMainWindow):
def initUI(self): def initUI(self):
"""UI 관련 코드 초기화""" """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.browser_widget = BrowserWidget()
# 도구 위젯 생성
self.tools_widget = ToolsWidget( self.tools_widget = ToolsWidget(
parent=self, parent=self,
thread_pool=self.thread_pool, thread_pool=self.thread_pool,
@ -88,29 +87,38 @@ class MainWindow(QMainWindow):
category_manager=self.category_manager 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.status_bar = StatusBar()
self.setStatusBar(self.status_bar) self.setStatusBar(self.status_bar)
# 스타일 설정 # Fluent 스타일의 내비게이션 추가
self.setStyleSheet(""" self.addSubInterface(self.browser_widget, FluentIcon.GLOBE, "브라우저")
QMainWindow { self.addSubInterface(self.tools_widget, FluentIcon.SETTING, "도구")
background-color: #f0f0f0;
} # 추가 도구 메뉴 추가
QSplitter::handle { self.navigationInterface().addSeparator()
background-color: #cccccc;
} # 로그 메뉴 추가
QSplitter::handle:horizontal { self.navigationInterface().addItem(
width: 2px; 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 초기화 완료") self.logger.info("UI 초기화 완료")
@ -129,4 +137,23 @@ class MainWindow(QMainWindow):
def update_status(self, message): def update_status(self, message):
"""상태바 메시지 업데이트""" """상태바 메시지 업데이트"""
self.status_changed.emit(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)

View File

@ -1,5 +1,6 @@
from PySide6.QtWidgets import QStatusBar, QLabel from PySide6.QtWidgets import QStatusBar, QLabel, QHBoxLayout
from PySide6.QtCore import Qt from PySide6.QtCore import Qt
from qfluentwidgets import StateToolTip, ProgressBar, PushButton, FluentIcon
class StatusBar(QStatusBar): class StatusBar(QStatusBar):
def __init__(self, parent=None): def __init__(self, parent=None):
@ -9,28 +10,53 @@ class StatusBar(QStatusBar):
def setup_ui(self): def setup_ui(self):
# 상태 메시지 레이블 # 상태 메시지 레이블
self.status_label = QLabel() self.status_label = QLabel()
self.status_label.setStyleSheet("color: #555555; padding: 2px;")
self.addWidget(self.status_label) self.addWidget(self.status_label)
# 로그인 상태 레이블 # 로그인 상태 레이블
self.login_status_label = QLabel("로그인되지 않음") self.login_status_label = QLabel("로그인되지 않음")
self.login_status_label.setStyleSheet("color: #777777; padding: 2px;")
self.addPermanentWidget(self.login_status_label) self.addPermanentWidget(self.login_status_label)
# 스타일 설정 # 전체 상태바 스타일 설정
self.setStyleSheet(""" self.setStyleSheet("""
QStatusBar { QStatusBar {
background-color: #f0f0f0; background-color: #f5f5f5;
border-top: 1px solid #cccccc; border-top: 1px solid #e0e0e0;
min-height: 24px;
padding: 0;
} }
QLabel { QLabel {
padding: 2px; font-size: 12px;
margin: 0 5px;
} }
""") """)
def set_status_message(self, message): def set_status_message(self, message):
"""상태 메시지 설정"""
self.status_label.setText(message) self.status_label.setText(message)
def set_login_status(self, is_logged_in): def set_login_status(self, is_logged_in):
"""로그인 상태 설정"""
if is_logged_in: if is_logged_in:
self.login_status_label.setText("로그인됨") self.login_status_label.setText("로그인됨")
self.login_status_label.setStyleSheet("color: #4caf50; padding: 2px; font-weight: bold;")
else: 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)

View File

@ -3,7 +3,13 @@ from PySide6.QtWidgets import (QWidget, QVBoxLayout, QTabWidget, QPushButton,
from PySide6.QtCore import Qt, Signal, Slot from PySide6.QtCore import Qt, Signal, Slot
from modules.xlsFilter.xls_filter_dialog import XlsFilterDialog 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) status_changed = Signal(str)
@ -24,10 +30,15 @@ class ToolsWidget(QWidget):
self.logger.info("도구 위젯 초기화 완료") self.logger.info("도구 위젯 초기화 완료")
def setup_ui(self): 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() self.shipping_calc_tab = QWidget()
@ -54,126 +65,236 @@ class ToolsWidget(QWidget):
self.setup_xls_filter_tab() self.setup_xls_filter_tab()
self.tab_widget.addTab(self.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): def setup_shipping_calc_tab(self):
layout = QVBoxLayout(self.shipping_calc_tab) layout = QVBoxLayout(self.shipping_calc_tab)
# 설정 카드 그룹
card_group = SettingCardGroup("배송비 계산", self.shipping_calc_tab)
# 무게 입력 # 무게 입력
weight_label = QLabel("무게 (kg):") self.weight_input = SpinBox(self.shipping_calc_tab)
self.weight_input = QLineEdit() self.weight_input.setRange(0, 100)
layout.addWidget(weight_label) self.weight_input.setSuffix(" kg")
layout.addWidget(self.weight_input) self.weight_input.setToolTip("배송 상품의 무게를 입력하세요")
weight_card = ComboBoxSettingCard(
FluentIcon.WEIGHT,
"무게",
"배송 상품의 무게를 입력하세요",
customWidget=self.weight_input,
parent=card_group
)
# 지역 선택 # 지역 선택
region_label = QLabel("지역:") self.region_input = LineEdit(self.shipping_calc_tab)
self.region_input = QLineEdit() self.region_input.setPlaceholderText("배송 지역")
layout.addWidget(region_label) region_card = ComboBoxSettingCard(
layout.addWidget(self.region_input) FluentIcon.GLOBE,
"지역",
"배송 지역을 입력하세요",
customWidget=self.region_input,
parent=card_group
)
# 카드 그룹에 추가
card_group.addSettingCard(weight_card)
card_group.addSettingCard(region_card)
# 계산 버튼 # 계산 버튼
calc_button = QPushButton("계산하기") self.calc_button = PrimaryPushButton("계산하기")
calc_button.clicked.connect(self.calculate_shipping) self.calc_button.clicked.connect(self.calculate_shipping)
layout.addWidget(calc_button)
# 결과 표시 # 결과 표시
self.result_label = QLabel("배송비: ") 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() layout.addStretch()
def setup_forbidden_words_tab(self): def setup_forbidden_words_tab(self):
layout = QVBoxLayout(self.forbidden_words_tab) 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("금지어 입력") 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("추가") self.add_button = PrimaryPushButton("추가")
add_button.clicked.connect(self.add_forbidden_word) self.add_button.clicked.connect(self.add_forbidden_word)
layout.addWidget(add_button)
# 금지어 목록 # 금지어 목록
self.word_list = QListWidget() self.word_list = ListWidget(self.forbidden_words_tab)
layout.addWidget(self.word_list)
# 삭제 버튼 # 삭제 버튼
delete_button = QPushButton("선택 삭제") self.delete_button = PushButton("선택 삭제")
delete_button.clicked.connect(self.delete_forbidden_word) self.delete_button.setIcon(FluentIcon.DELETE)
layout.addWidget(delete_button) self.delete_button.clicked.connect(self.delete_forbidden_word)
# 금지어 목록 로드 # 금지어 목록 로드
if self.forbidden_words: if self.forbidden_words:
self.load_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): def setup_category_tab(self):
layout = QVBoxLayout(self.category_tab) 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("카테고리 입력") 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("추가") self.add_cat_button = PrimaryPushButton("추가")
add_button.clicked.connect(self.add_category) self.add_cat_button.clicked.connect(self.add_category)
layout.addWidget(add_button)
# 카테고리 목록 # 카테고리 목록
self.category_list = QListWidget() self.category_list = ListWidget(self.category_tab)
layout.addWidget(self.category_list)
# 삭제 버튼 # 삭제 버튼
delete_button = QPushButton("선택 삭제") self.delete_cat_button = PushButton("선택 삭제")
delete_button.clicked.connect(self.delete_category) self.delete_cat_button.setIcon(FluentIcon.DELETE)
layout.addWidget(delete_button) self.delete_cat_button.clicked.connect(self.delete_category)
# 카테고리 목록 로드 # 카테고리 목록 로드
if self.category_manager: if self.category_manager:
self.load_categories() 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): def setup_log_tab(self):
layout = QVBoxLayout(self.log_tab) 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) self.log_text.setReadOnly(True)
layout.addWidget(self.log_text)
# 로그 정리 버튼 # 로그 정리 버튼
clear_button = QPushButton("로그 정리") self.clear_button = PushButton("로그 정리")
clear_button.clicked.connect(self.clear_logs) self.clear_button.setIcon(FluentIcon.CLEAR)
layout.addWidget(clear_button) 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): def setup_xls_filter_tab(self):
layout = QVBoxLayout(self.xls_filter_tab) layout = QVBoxLayout(self.xls_filter_tab)
# 엑셀 필터링 버튼 # 설정 카드 그룹
filter_button = QPushButton("엑셀 필터링 실행") card_group = SettingCardGroup("엑셀 필터링", self.xls_filter_tab)
filter_button.clicked.connect(self.run_xls_filter) card_text = "엑셀 파일에서 상품 정보를 추출하고 금지어/카테고리를 필터링합니다."
layout.addWidget(filter_button)
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() layout.addStretch()
def calculate_shipping(self): def calculate_shipping(self):
weight = self.weight_input.text() weight = self.weight_input.value()
region = self.region_input.text() 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("무게와 지역을 입력해주세요.") self.status_changed.emit("무게와 지역을 입력해주세요.")
return return
try: try:
weight = float(weight)
# 여기에서 실제 배송비 계산 로직을 구현 # 여기에서 실제 배송비 계산 로직을 구현
shipping_cost = weight * 2500 # 예시 계산 로직 shipping_cost = weight * 2500 # 예시 계산 로직
self.result_label.setText(f"배송비: {shipping_cost:,}") self.result_label.setText(f"배송비: {shipping_cost:,}")
self.status_changed.emit(f"배송비 계산 완료: {shipping_cost:,}") self.status_changed.emit(f"배송비 계산 완료: {shipping_cost:,}")
self.show_info_bar("완료", f"배송비 계산 완료: {shipping_cost:,}", InfoBarPosition.BOTTOM_RIGHT)
except ValueError: except ValueError:
self.show_info_bar("오류", "무게는 숫자로 입력해주세요.", InfoBarPosition.TOP, True)
self.status_changed.emit("무게는 숫자로 입력해주세요.") 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): def load_forbidden_words(self):
"""금지어 목록 로드""" """금지어 목록 로드"""
if self.logger: if self.logger:
@ -193,6 +314,7 @@ class ToolsWidget(QWidget):
if self.forbidden_words: if self.forbidden_words:
self.forbidden_words.add_word(word) self.forbidden_words.add_word(word)
self.status_changed.emit(f"금지어 '{word}' 추가됨") self.status_changed.emit(f"금지어 '{word}' 추가됨")
self.show_info_bar("추가 완료", f"금지어 '{word}' 추가됨", InfoBarPosition.BOTTOM_RIGHT)
self.word_list.addItem(word) self.word_list.addItem(word)
self.word_input.clear() self.word_input.clear()
@ -203,6 +325,7 @@ class ToolsWidget(QWidget):
if self.forbidden_words: if self.forbidden_words:
self.forbidden_words.remove_word(word) self.forbidden_words.remove_word(word)
self.status_changed.emit(f"금지어 '{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)) self.word_list.takeItem(self.word_list.row(current_item))
def load_categories(self): def load_categories(self):
@ -224,6 +347,7 @@ class ToolsWidget(QWidget):
if self.category_manager: if self.category_manager:
self.category_manager.add_category(category) self.category_manager.add_category(category)
self.status_changed.emit(f"카테고리 '{category}' 추가됨") self.status_changed.emit(f"카테고리 '{category}' 추가됨")
self.show_info_bar("추가 완료", f"카테고리 '{category}' 추가됨", InfoBarPosition.BOTTOM_RIGHT)
self.category_list.addItem(category) self.category_list.addItem(category)
self.category_input.clear() self.category_input.clear()
@ -234,11 +358,13 @@ class ToolsWidget(QWidget):
if self.category_manager: if self.category_manager:
self.category_manager.remove_category(category) self.category_manager.remove_category(category)
self.status_changed.emit(f"카테고리 '{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)) self.category_list.takeItem(self.category_list.row(current_item))
def clear_logs(self): def clear_logs(self):
self.log_text.clear() self.log_text.clear()
self.status_changed.emit("로그가 정리되었습니다.") self.status_changed.emit("로그가 정리되었습니다.")
self.show_info_bar("완료", "로그가 정리되었습니다", InfoBarPosition.BOTTOM_RIGHT)
def run_xls_filter(self): def run_xls_filter(self):
if self.logger: if self.logger:

View File

@ -15,6 +15,7 @@ selenium = "^4.31.0"
webdriver-manager = "^4.0.2" webdriver-manager = "^4.0.2"
pandas = "^2.2.2" pandas = "^2.2.2"
openpyxl = "^3.1.2" openpyxl = "^3.1.2"
PySide6-Fluent-Widgets = "^1.5.0"
[build-system] [build-system]
requires = ["poetry-core"] requires = ["poetry-core"]