Compare commits
2 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
233ab94cad | |
|
|
6cc149de71 |
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,31 @@
|
|||
import sys
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from PySide6 import QtWidgets, QtCore
|
||||
from qasync import QEventLoop
|
||||
from src.logger_module import Logger
|
||||
from delivery_fee_calculator import DeliveryFeeCalculator
|
||||
|
||||
if __name__ == '__main__':
|
||||
# High DPI 관련 설정 (Qt6에서는 QDesktopWidget 대신 primaryScreen()를 사용합니다)
|
||||
QtWidgets.QApplication.setHighDpiScaleFactorRoundingPolicy(
|
||||
QtCore.Qt.HighDpiScaleFactorRoundingPolicy.PassThrough)
|
||||
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
|
||||
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps)
|
||||
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
# qasync 이벤트 루프 생성 – PySide6의 이벤트 루프와 연동
|
||||
loop = QEventLoop(app)
|
||||
asyncio.set_event_loop(loop)
|
||||
|
||||
app.setStyle('Fusion')
|
||||
logger = Logger(log_file="Scrapper2.log", logger_name="Scrapper_Logger", level=logging.INFO)
|
||||
|
||||
ex = DeliveryFeeCalculator(logger)
|
||||
ex.show()
|
||||
|
||||
with loop:
|
||||
loop.run_forever()
|
||||
|
||||
sys.exit(app.exec())
|
||||
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
|
|
@ -1,19 +1,23 @@
|
|||
import sys
|
||||
from PyQt5.QtWidgets import QApplication, QMessageBox, QSizePolicy, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QTextEdit, QGridLayout
|
||||
from PyQt5.QtGui import QPixmap
|
||||
from PyQt5.QtCore import Qt, QByteArray, QBuffer, QIODevice
|
||||
from PySide6.QtWidgets import (QApplication, QMessageBox, QSizePolicy, QWidget,
|
||||
QVBoxLayout, QHBoxLayout, QLabel, QLineEdit,
|
||||
QPushButton, QTextEdit, QGridLayout)
|
||||
from PySide6.QtGui import QPixmap
|
||||
from PySide6.QtCore import Qt, QByteArray, QBuffer, QIODevice
|
||||
from kipris_web_from_playwright import WebScraper
|
||||
import logging
|
||||
import webbrowser
|
||||
from PIL import Image
|
||||
from io import BytesIO
|
||||
|
||||
# 로거 인스턴스 가져오기
|
||||
logger = logging.getLogger('default_logger')
|
||||
|
||||
class MainApp(QWidget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.initUI()
|
||||
self.scraper = WebScraper()
|
||||
self.scraper.setup_browser()
|
||||
|
||||
|
||||
def initUI(self):
|
||||
# 검색 레이아웃
|
||||
|
|
@ -32,7 +36,6 @@ class MainApp(QWidget):
|
|||
logLayout = QVBoxLayout()
|
||||
self.logTextEdit = QTextEdit(self)
|
||||
self.logTextEdit.setReadOnly(True)
|
||||
|
||||
logLayout.addWidget(self.logTextEdit)
|
||||
|
||||
# 메인 레이아웃
|
||||
|
|
@ -45,18 +48,15 @@ class MainApp(QWidget):
|
|||
self.setGeometry(300, 300, 300, 400)
|
||||
|
||||
def wrap_text(self, text, width=40):
|
||||
"""주어진 너비에 맞게 텍스트를 줄바꿈합니다."""
|
||||
words = text.split()
|
||||
wrapped_text = ''
|
||||
line_length = 0
|
||||
|
||||
for word in words:
|
||||
if line_length + len(word) + 1 > width:
|
||||
wrapped_text += '\n'
|
||||
line_length = 0
|
||||
wrapped_text += word + ' '
|
||||
line_length += len(word) + 1
|
||||
|
||||
return wrapped_text.strip()
|
||||
|
||||
def start_search(self):
|
||||
|
|
@ -64,7 +64,6 @@ class MainApp(QWidget):
|
|||
if not term:
|
||||
self.logTextEdit.append("검색어를 입력해주세요.")
|
||||
return
|
||||
|
||||
self.logTextEdit.append("검색을 시작합니다...")
|
||||
results = self.scraper.search_for_term(term)
|
||||
if results:
|
||||
|
|
@ -72,18 +71,16 @@ class MainApp(QWidget):
|
|||
self.show_results(results)
|
||||
else:
|
||||
self.logTextEdit.append("검색 결과가 없거나 오류가 발생했습니다.")
|
||||
QMessageBox.information(self, "검색 결과 없음", "검색 결과가 없으므로 지재권에 안심하시면 됩니다.", QMessageBox.Ok)
|
||||
|
||||
QMessageBox.information(self, "검색 결과 없음",
|
||||
"검색 결과가 없으므로 지재권에 안심하시면 됩니다.",
|
||||
QMessageBox.Ok)
|
||||
|
||||
def show_results(self, results):
|
||||
|
||||
try:
|
||||
# 결과 위젯 생성
|
||||
self.results_widget = QWidget()
|
||||
layout = QVBoxLayout()
|
||||
self.results_widget.setLayout(layout)
|
||||
|
||||
# 결과 갯수 확인 및 레이아웃 동적 생성
|
||||
total_count = int(results['total_count'])
|
||||
set_count = min(total_count, 10)
|
||||
grid_layout = QGridLayout()
|
||||
|
|
@ -95,52 +92,38 @@ class MainApp(QWidget):
|
|||
result_key = f"result_{i}"
|
||||
if result_key in results:
|
||||
result = results[result_key]
|
||||
|
||||
# 테두리 설정
|
||||
border_style = ''
|
||||
if result['admin_status'] == '등록':
|
||||
border_style = 'border: 4px solid red;'
|
||||
elif result['admin_status'] == '공고':
|
||||
border_style = 'border: 3px solid black;'
|
||||
|
||||
# 각 결과에 대한 레이아웃 생성
|
||||
item_layout = QVBoxLayout()
|
||||
item_widget = QWidget() # 위젯 생성
|
||||
|
||||
# item_layout의 크기 정책 설정
|
||||
item_widget = QWidget()
|
||||
item_widget.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.MinimumExpanding)
|
||||
|
||||
# 이미지 처리
|
||||
image_label = QLabel()
|
||||
image_label.setFixedSize(150, 150)
|
||||
image_data = self.scraper.fetch_image_data(result['IDimageURL'])
|
||||
pixmap = QPixmap()
|
||||
pixmap.loadFromData(image_data)
|
||||
# QLabel의 크기에 맞게 이미지 크기 조정
|
||||
scaled_pixmap = pixmap.scaled(image_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
||||
image_label.setPixmap(scaled_pixmap)
|
||||
# QLabel의 가로 세로 중앙에 이미지 표시
|
||||
image_label.setAlignment(Qt.AlignCenter)
|
||||
# 이미지 표시 위젯의 크기 조정 정책 설정
|
||||
image_label.setScaledContents(True)
|
||||
|
||||
#이미지 중앙배치를 위해
|
||||
horizontal_layout = QHBoxLayout()
|
||||
horizontal_layout.addWidget(image_label)
|
||||
horizontal_layout.setAlignment(Qt.AlignCenter)
|
||||
item_layout.addLayout(horizontal_layout)
|
||||
|
||||
# item_layout.addWidget(image_label)
|
||||
|
||||
# 정보 텍스트
|
||||
# info_text = f"상표권명: {result['title']}\n등록상태: {result['admin_status']}\nCategory: {result['product_category']}\nApplicant: {result['applicant']}\nPublication Date: {result['publication_date']}\nRegistration Date: {result['registration_date']}"
|
||||
info_text = f"<span style='font-size: 11pt; font-weight: bold; text-decoration: underline;'>상표권명: {result['title']}</span><br>\n" \
|
||||
f"<span style='font-size: 11pt; font-weight: bold; text-decoration: underline;'>등록상태: {result['admin_status']}</span><br>\n" \
|
||||
f"<span style='font-size: 9pt;'>카테고리: {result['product_category']}</span><br>\n" \
|
||||
f"<span style='font-size: 9pt;'>권리자: {result['applicant']}</span><br>\n" \
|
||||
f"<span style='font-size: 9pt;'> {result['publication_date']}</span><br>\n" \
|
||||
f"<span style='font-size: 9pt;'> {result['registration_date']}</span>"
|
||||
|
||||
info_text = (f"<span style='font-size: 11pt; font-weight: bold; text-decoration: underline;'>"
|
||||
f"상표권명: {result['title']}</span><br>\n"
|
||||
f"<span style='font-size: 11pt; font-weight: bold; text-decoration: underline;'>"
|
||||
f"등록상태: {result['admin_status']}</span><br>\n"
|
||||
f"<span style='font-size: 9pt;'>카테고리: {result['product_category']}</span><br>\n"
|
||||
f"<span style='font-size: 9pt;'>권리자: {result['applicant']}</span><br>\n"
|
||||
f"<span style='font-size: 9pt;'> {result['publication_date']}</span><br>\n"
|
||||
f"<span style='font-size: 9pt;'> {result['registration_date']}</span>")
|
||||
info_label = QLabel(info_text)
|
||||
info_label.setToolTip(self.wrap_text(result['category_description'], 50))
|
||||
image_label.setToolTip(self.wrap_text(result['category_description'], 50))
|
||||
|
|
@ -149,31 +132,25 @@ class MainApp(QWidget):
|
|||
image_label.setStyleSheet(border_style)
|
||||
info_label.setStyleSheet(border_style)
|
||||
|
||||
# 레이아웃에 위젯 추가
|
||||
row = grid_index // grid_columns
|
||||
col = grid_index % grid_columns
|
||||
grid_layout.addLayout(item_layout, row, col)
|
||||
grid_index += 1
|
||||
|
||||
# 결과 위젯에 닫기 버튼 추가
|
||||
close_button = QPushButton("Close")
|
||||
close_button.clicked.connect(self.close_results_widget)
|
||||
layout.addWidget(close_button)
|
||||
|
||||
# 결과 위젯을 메인 윈도우에 추가
|
||||
self.results_widget.setGeometry(300, 300, 600, 300) # 위치와 크기 설정
|
||||
self.results_widget.setWindowTitle('Search Results') # 타이틀 설정
|
||||
self.results_widget.setGeometry(300, 300, 600, 300)
|
||||
self.results_widget.setWindowTitle('Search Results')
|
||||
self.results_widget.show()
|
||||
|
||||
except Exception as e:
|
||||
logger.debug(f"Error displaying results: {e}")
|
||||
|
||||
self.logger.log(f"Error displaying results: {e}", level=logging.DEBUG)
|
||||
|
||||
def close_results_widget(self):
|
||||
# 결과 위젯닫기 함수를 호출할 때 사용하는 메서드
|
||||
self.results_widget.close()
|
||||
|
||||
|
||||
def closeEvent(self, event):
|
||||
self.scraper.close_browser()
|
||||
event.accept()
|
||||
|
|
@ -182,4 +159,4 @@ if __name__ == '__main__':
|
|||
app = QApplication(sys.argv)
|
||||
ex = MainApp()
|
||||
ex.show()
|
||||
sys.exit(app.exec_())
|
||||
sys.exit(app.exec())
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import os
|
||||
import asyncio
|
||||
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QPushButton
|
||||
from PySide6.QtWidgets import QDialog, QVBoxLayout, QPushButton
|
||||
from playwright.async_api import async_playwright
|
||||
|
||||
class optionTrans(QDialog):
|
||||
|
|
@ -15,29 +15,24 @@ class optionTrans(QDialog):
|
|||
self.setWindowTitle("Macro Control")
|
||||
layout = QVBoxLayout()
|
||||
|
||||
# 실행 버튼
|
||||
self.start_button = QPushButton("실행")
|
||||
self.start_button.clicked.connect(self.start_browser_task) # 실행 버튼을 비동기 작업과 연결
|
||||
self.start_button.clicked.connect(self.start_browser_task)
|
||||
layout.addWidget(self.start_button)
|
||||
|
||||
# 중지 버튼
|
||||
self.stop_button = QPushButton("중지")
|
||||
self.stop_button.clicked.connect(self.stop_browser_task)
|
||||
layout.addWidget(self.stop_button)
|
||||
|
||||
# 매크로 1 버튼
|
||||
self.macro1_button = QPushButton("매크로 1 실행")
|
||||
self.macro1_button.clicked.connect(self.start_macro1_task)
|
||||
layout.addWidget(self.macro1_button)
|
||||
|
||||
# 매크로 2 버튼 (아직 구현하지 않음)
|
||||
self.macro2_button = QPushButton("매크로 2 실행")
|
||||
layout.addWidget(self.macro2_button)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
def start_browser_task(self):
|
||||
# 비동기 작업을 생성하고 이벤트 루프에 실행
|
||||
asyncio.create_task(self.run_browser())
|
||||
|
||||
def stop_browser_task(self):
|
||||
|
|
@ -47,32 +42,19 @@ class optionTrans(QDialog):
|
|||
asyncio.create_task(self.run_macro1())
|
||||
|
||||
def get_latest_version(self, directory):
|
||||
# 디렉터리 내에서 버전 폴더를 찾아서 숫자로 정렬한 뒤 최신 버전을 반환
|
||||
versions = os.listdir(directory)
|
||||
versions.sort(key=lambda s: [int(part) for part in s.replace('_', '.').split('.')])
|
||||
return versions[-1] # 최신 버전 반환
|
||||
return versions[-1]
|
||||
|
||||
async def run_browser(self):
|
||||
if self.browser is None:
|
||||
# main.py가 위치한 디렉터리 경로
|
||||
current_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # OptionTranslator.py 기준 상위 폴더로 이동
|
||||
current_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
user_data_dir = os.path.join(current_dir, "user_data")
|
||||
|
||||
# 확장 프로그램 경로 설정 (동적으로 최신 버전의 확장 프로그램 폴더를 찾음)
|
||||
extension_dir1 = os.path.join(user_data_dir, "Default", "Extensions", "jlcdjppbpplpdgfeknhioedbhfceaben")
|
||||
|
||||
# 확장 프로그램이 존재하는지 확인
|
||||
if not os.path.exists(extension_dir1):
|
||||
raise FileNotFoundError(f"확장 프로그램 디렉터리가 존재하지 않습니다: {extension_dir1}")
|
||||
|
||||
# 최신 버전 폴더 찾기 (숫자 기반 비교)
|
||||
extension_version1 = self.get_latest_version(extension_dir1)
|
||||
extension_path1 = os.path.join(extension_dir1, extension_version1)
|
||||
|
||||
# 최신 버전 폴더 찾기 (숫자 기반 비교)
|
||||
extension_version1 = self.get_latest_version(extension_dir1) # self로 메서드 호출
|
||||
extension_path1 = os.path.join(extension_dir1, extension_version1)
|
||||
|
||||
self.playwright = await async_playwright().start()
|
||||
self.browser = await self.playwright.chromium.launch_persistent_context(
|
||||
user_data_dir=user_data_dir,
|
||||
|
|
@ -95,16 +77,13 @@ class optionTrans(QDialog):
|
|||
self.macro_running = True
|
||||
try:
|
||||
element_to_right_click = await self.page.query_selector('css_selector_for_element')
|
||||
await element_to_right_click.click(button="right") # 우클릭
|
||||
|
||||
await element_to_right_click.click(button="right")
|
||||
translate_button = await self.page.query_selector('css_selector_for_translate')
|
||||
await translate_button.click() # 번역 버튼 클릭
|
||||
|
||||
await translate_button.click()
|
||||
second_element = await self.page.query_selector('css_selector_for_drag')
|
||||
await second_element.hover() # 요소 위에 마우스 올리기
|
||||
await second_element.hover()
|
||||
await self.page.mouse.down()
|
||||
await self.page.mouse.move(150, 0) # 오른쪽으로 150픽셀 이동
|
||||
await self.page.mouse.move(150, 0)
|
||||
await self.page.mouse.up()
|
||||
|
||||
finally:
|
||||
self.macro_running = False
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
from PyQt5.QtWidgets import QLineEdit
|
||||
from PyQt5.QtCore import Qt
|
||||
from PySide6.QtWidgets import QLineEdit
|
||||
from PySide6.QtCore import Qt
|
||||
|
||||
class LineEditWithHistory(QLineEdit):
|
||||
def __init__(self, completer, parent=None):
|
||||
|
|
|
|||
|
|
@ -1,78 +1,77 @@
|
|||
from PyQt5.QtCore import QThread, pyqtSignal, QObject
|
||||
from PySide6.QtCore import QThread, Signal, QObject
|
||||
import time
|
||||
from src.web_scraper_async import *
|
||||
from src.web_scraper_async import * # 필요한 모듈들
|
||||
import logging
|
||||
|
||||
# 로거 인스턴스 가져오기
|
||||
logger = logging.getLogger('default_logger')
|
||||
class APISearchWorker(QObject):
|
||||
finished = pyqtSignal(dict, float)
|
||||
finished = Signal(dict, float)
|
||||
|
||||
def __init__(self, kiprisObject, keyword, set_status):
|
||||
def __init__(self, logger, kiprisObject, keyword, set_status):
|
||||
super().__init__()
|
||||
self.logger = logger
|
||||
self.kiprisObject = kiprisObject
|
||||
self.keyword = keyword
|
||||
self.set_status = set_status
|
||||
|
||||
def run(self):
|
||||
start_time = time.time() # 검색 시작 시간
|
||||
logger.debug(f"Search keyword : [{self.keyword}], self.set_status : [{self.set_status}]")
|
||||
start_time = time.time()
|
||||
self.logger.log(f"Search keyword : [{self.keyword}], set_status : [{self.set_status}]", level=logging.DEBUG)
|
||||
result = self.kiprisObject.run(self.keyword, self.set_status)
|
||||
logger.debug(f"Search finished | result \n {result}")
|
||||
elapsed_time = time.time() - start_time # 경과 시간 계산
|
||||
self.logger.log(f"Search finished | result:\n{result}", level=logging.DEBUG)
|
||||
elapsed_time = time.time() - start_time
|
||||
self.finished.emit(result, elapsed_time)
|
||||
|
||||
class SearchThread(QThread):
|
||||
def __init__(self, worker):
|
||||
def __init__(self, logger, worker):
|
||||
super().__init__()
|
||||
self.worker = worker
|
||||
self.logger = logger
|
||||
self.worker.moveToThread(self)
|
||||
self.worker.finished.connect(self.handle_finished)
|
||||
|
||||
def run(self):
|
||||
self.worker.run()
|
||||
# self.quit()
|
||||
self.exec_()
|
||||
self.exec()
|
||||
|
||||
def start_search(self):
|
||||
self.start()
|
||||
|
||||
def handle_finished(self, result, elapsed_time):
|
||||
# 검색 작업이 완료되면 이 시그널이 발생합니다.
|
||||
logger.debug(f"Search finished : [{elapsed_time}]초 경과")
|
||||
|
||||
self.logger.log(f"Search finished : [{elapsed_time}]초 경과", level=logging.DEBUG)
|
||||
|
||||
class AsyncWebSearchWorker(QObject):
|
||||
finished = pyqtSignal(object, float) # 결과와 소요 시간을 전달할 신호 정의
|
||||
finished = Signal(object, float)
|
||||
|
||||
def __init__(self, term, set_status):
|
||||
def __init__(self, logger, term, set_status):
|
||||
super().__init__()
|
||||
self.term = term
|
||||
self.logger = logger
|
||||
self.set_status = set_status
|
||||
self.scraper = WebScraper() # WebScraper 인스턴스 생성
|
||||
self.thread = QThread() # 별도의 스레드 생성
|
||||
self.moveToThread(self.thread) # 이 객체를 새 스레드로 이동
|
||||
self.thread.started.connect(self.run) # 스레드가 시작되면 run 메서드 실행
|
||||
self.moveToThread(self.thread)
|
||||
self.thread.started.connect(self.run)
|
||||
self.start_time = None
|
||||
|
||||
def start(self):
|
||||
self.thread.start() # 스레드 시작
|
||||
self.thread.start()
|
||||
|
||||
def run(self):
|
||||
self.start_time = time.time() # 검색 시작 시간 기록
|
||||
self.start_time = time.time()
|
||||
import asyncio
|
||||
asyncio.set_event_loop(asyncio.new_event_loop())
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.run_until_complete(self.async_run())
|
||||
|
||||
async def async_run(self):
|
||||
try:
|
||||
await self.scraper.setup_browser() # 브라우저 설정
|
||||
result = await self.scraper.run(self.term, self.set_status) # 검색어를 사용하여 검색 실행
|
||||
elapsed_time = time.time() - self.start_time # 소요 시간 계산
|
||||
self.finished.emit(result, elapsed_time) # 작업 완료 신호 전송
|
||||
await self.scraper.setup_browser()
|
||||
result = await self.scraper.run(self.term, self.set_status)
|
||||
elapsed_time = time.time() - self.start_time
|
||||
self.finished.emit(result, elapsed_time)
|
||||
except Exception as e:
|
||||
logger.debug(f"Error in AsyncWebSearchWorker: {e}")
|
||||
self.finished.emit(None, 0) # 에러 발생 시 None 전송
|
||||
self.logger.log(f"Error in AsyncWebSearchWorker: {e}", level=logging.DEBUG)
|
||||
self.finished.emit(None, 0)
|
||||
finally:
|
||||
await self.scraper.close_Kipris() # 리소스 정리
|
||||
self.thread.quit() # 스레드 종료
|
||||
await self.scraper.close_Kipris()
|
||||
self.thread.quit()
|
||||
|
|
|
|||
|
|
@ -1,18 +1,16 @@
|
|||
from PyQt5 import QtWidgets, QtCore
|
||||
from PyQt5.QtCore import QUrl
|
||||
from PyQt5.QtGui import QDesktopServices
|
||||
from PySide6 import QtWidgets, QtCore
|
||||
from PySide6.QtCore import QUrl
|
||||
from PySide6.QtGui import QDesktopServices
|
||||
from src.toggleSwitch import ToggleSwitch
|
||||
import logging
|
||||
|
||||
# 로거 인스턴스 가져오기
|
||||
logger = logging.getLogger('default_logger')
|
||||
class SettingsDialog(QtWidgets.QDialog):
|
||||
def __init__(self, parent=None, initial_settings=None):
|
||||
def __init__(self, parent=None, logger=None, initial_settings=None):
|
||||
super().__init__(parent)
|
||||
self.logger = logger
|
||||
if parent is not None:
|
||||
self.setModal(True)
|
||||
self.setParent(parent)
|
||||
|
||||
else:
|
||||
self.resize(300, 150) # 단독 실행 시 크기 설정
|
||||
|
||||
|
|
@ -25,8 +23,6 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||
self.setCNY = None
|
||||
|
||||
self.setWindowTitle('키프리스 설정')
|
||||
|
||||
|
||||
self.setupUI()
|
||||
|
||||
if initial_settings:
|
||||
|
|
@ -42,60 +38,37 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||
self.width(), self.height()
|
||||
)
|
||||
|
||||
|
||||
def setupUI(self):
|
||||
logger.debug(f"setupUI 시작")
|
||||
# 셋업 메인 레이아웃
|
||||
self.logger.log("setupUI 시작", level=logging.DEBUG)
|
||||
# 메인 레이아웃
|
||||
self.mainLayout = QtWidgets.QVBoxLayout(self)
|
||||
|
||||
# 메인 레이아웃 1 : 키프리스 사용여부 위젯 및 레이아웃
|
||||
# --- 1. 키프리스 사용여부 위젯 ---
|
||||
self.isUseKiprisWidget = QtWidgets.QWidget(self)
|
||||
isUseKipris_layout = QtWidgets.QHBoxLayout(self.isUseKiprisWidget)
|
||||
self.isUseKiprisWidget.setLayout(isUseKipris_layout)
|
||||
|
||||
# 메인 레이아웃 1-1 : 키프리스 사용여부 스위치
|
||||
# 키프리스 사용여부 스위치
|
||||
self.isUseKiprisSwitch = ToggleSwitch(self.isUseKiprisWidget)
|
||||
self.isUseKiprisSwitch.setChecked(False)
|
||||
self.isUseKiprisSwitch.clicked.connect(self.toggleKiprisUsage)
|
||||
isUseKipris_layout.addLayout(self.create_label_and_switch(self.isUseKiprisWidget, "키프리스 사용여부", self.isUseKiprisSwitch))
|
||||
|
||||
# 메인 레이아웃 1-1 : 키프리스 사용여부 도움말 버튼
|
||||
# 도움말 버튼
|
||||
self.helpKiprisBTN = QtWidgets.QPushButton("도움말", self.isUseKiprisWidget)
|
||||
self.helpKiprisBTN.clicked.connect(self.helpKipris)
|
||||
isUseKipris_layout.addWidget(self.helpKiprisBTN)
|
||||
|
||||
# # 메인 레이아웃 2 : 환율 레이아웃
|
||||
# self.exchangeWONSwitchWidget = QtWidgets.QWidget(self)
|
||||
# self.exchangeWON_layout = QtWidgets.QHBoxLayout(self.exchangeWONSwitchWidget)
|
||||
|
||||
# # 메인 레이아웃 2-1 : CNY 환율 레이아웃 스위치
|
||||
# exchangeCNYSwitch_layout = QtWidgets.QHBoxLayout(self.exchangeWONSwitchWidget)
|
||||
# self.exchangeWON_layout.addLayout(exchangeCNYSwitch_layout)
|
||||
# self.exchangeCNYSwitch = ToggleSwitch(self.exchangeWONSwitchWidget)
|
||||
# self.exchangeCNYSwitch.setChecked(False)
|
||||
# self.exchangeCNYSwitch.clicked.connect(self.toggleCNYexchange)
|
||||
# exchangeCNYSwitch_layout.addLayout(self.create_label_and_switch(self.exchangeWONSwitchWidget, "CNY/KRW 표시", self.exchangeCNYSwitch))
|
||||
|
||||
# # 메인 레이아웃 2-2 : USD 환율 레이아웃 스위치
|
||||
# exchangeUSDSwitch_layout = QtWidgets.QHBoxLayout(self.exchangeWONSwitchWidget)
|
||||
# self.exchangeWON_layout.addLayout(exchangeUSDSwitch_layout)
|
||||
# self.exchangeUSDSwitch = ToggleSwitch(self.exchangeWONSwitchWidget)
|
||||
# self.exchangeUSDSwitch.setChecked(False)
|
||||
# self.exchangeUSDSwitch.clicked.connect(self.toggleUSDexchange)
|
||||
# exchangeUSDSwitch_layout.addLayout(self.create_label_and_switch(self.exchangeWONSwitchWidget, "USD/KRW 표시", self.exchangeUSDSwitch))
|
||||
|
||||
# 메인 레이아웃에 추가
|
||||
# self.mainLayout.addWidget(self.exchangeWONSwitchWidget)
|
||||
self.mainLayout.addWidget(self.isUseKiprisWidget)
|
||||
|
||||
# 키프리스 설정 위젯 및 레이아웃
|
||||
# --- 2. 키프리스 설정 위젯 ---
|
||||
self.settingKiprisWidget = QtWidgets.QWidget(self)
|
||||
settingKipris_layout = QtWidgets.QHBoxLayout(self.settingKiprisWidget)
|
||||
self.settingKiprisWidget.setLayout(settingKipris_layout)
|
||||
self.settingKiprisWidget.setVisible(False)
|
||||
self.mainLayout.addWidget(self.settingKiprisWidget)
|
||||
|
||||
# API 방식 사용 위젯 및 레이아웃
|
||||
# API 방식 사용 위젯
|
||||
self.apiLayoutWidget = QtWidgets.QWidget(self.settingKiprisWidget)
|
||||
apiLayout = QtWidgets.QVBoxLayout(self.apiLayoutWidget)
|
||||
self.apiLayoutWidget.setLayout(apiLayout)
|
||||
|
|
@ -108,13 +81,13 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||
self.editAPIWidget = QtWidgets.QWidget(self.apiLayoutWidget)
|
||||
editAPI_layout = self.create_label_and_edit(self.editAPIWidget, "APIKEY", "editable")
|
||||
self.editAPIWidget.setLayout(editAPI_layout)
|
||||
self.editAPIWidget.findChild(QtWidgets.QLineEdit).setText(self.api_key)
|
||||
# 초기 api_key 텍스트 설정
|
||||
self.editAPIWidget.findChild(QtWidgets.QLineEdit).setText(self.api_key or "")
|
||||
self.editAPIWidget.findChild(QtWidgets.QLineEdit).textChanged.connect(self.updateApiKey)
|
||||
self.editAPIWidget.setVisible(False)
|
||||
self.mainLayout.addWidget(self.editAPIWidget)
|
||||
|
||||
|
||||
# 체크박스만 추가
|
||||
# --- 3. 체크박스들 ---
|
||||
self.all_checkbox = QtWidgets.QCheckBox("전체 체크")
|
||||
self.right_rejected_checkbox = QtWidgets.QCheckBox("거절")
|
||||
self.right_registered_checkbox = QtWidgets.QCheckBox("등록")
|
||||
|
|
@ -124,7 +97,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||
self.right_remise_checkbox = QtWidgets.QCheckBox("포기")
|
||||
self.right_Disclosure_checkbox = QtWidgets.QCheckBox("공개")
|
||||
|
||||
# 체크박스 상태 변경 시 메서드 연결
|
||||
# 시그널 연결
|
||||
self.all_checkbox.stateChanged.connect(self.handle_all_checked)
|
||||
self.right_rejected_checkbox.stateChanged.connect(lambda state: self.update_status_list(state, "거절"))
|
||||
self.right_registered_checkbox.stateChanged.connect(lambda state: self.update_status_list(state, "등록"))
|
||||
|
|
@ -134,58 +107,30 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||
self.right_remise_checkbox.stateChanged.connect(lambda state: self.update_status_list(state, "포기"))
|
||||
self.right_Disclosure_checkbox.stateChanged.connect(lambda state: self.update_status_list(state, "공개"))
|
||||
|
||||
# 체크박스 툴팁 추가
|
||||
self.right_rejected_checkbox.setToolTip("출원 후 특허 심사과정에서 실체적인 특허 등록요건을 \n 만족하지 못할 경우에 심사관이 취하는 행정처분")
|
||||
self.right_registered_checkbox.setToolTip("심사관이 심사한 결과 등록요건에 적합하여 \n 설정등록을 받을 수 있다는 내용의 행정처분")
|
||||
self.right_expiration_checkbox.setToolTip("특허등록 후 존속기간이 만료되어 \n 권리가 소멸된 상태")
|
||||
self.right_void_checkbox.setToolTip("출원 또는 등록된 상태에 대하여 특정 사유로 인해 \n 그 권리나 행위가 무효화 된 상태")
|
||||
self.right_Withdrawal_checkbox.setToolTip("출원한 특허가 등록되기전 여러 사유로 인하여 \n 출원이 취소된 상태")
|
||||
self.right_remise_checkbox.setToolTip("출원인의 포기서 제출, 등록료 불납 등으로 \n 등록결정이나 권리를 포기한 상태")
|
||||
self.right_Disclosure_checkbox.setToolTip("출원이나 등록사실이 일반 공중에게 공표된 상태로 \n 출원 후 18개월이 지난 건\n(조기공개신청시 18개월 미만도 공개가능)")
|
||||
|
||||
|
||||
# # 체크박스 추가
|
||||
# self.right_rejected_checkbox = QtWidgets.QCheckBox("거절")
|
||||
# self.right_rejected_layout = self.create_label_and_check(self.right_rejected_checkbox, "거절", "출원 후 특허 심사과정에서 실체적인 특허 등록요건을 \n 만족하지 못할 경우에 심사관이 취하는 행정처분")
|
||||
# right_registered_checkbox = QtWidgets.QCheckBox()
|
||||
# self.right_registered_layout = self.create_label_and_check(right_registered_checkbox, "등록", "심사관이 심사한 결과 등록요건에 적합하여 \n 설정등록을 받을 수 있다는 내용의 행정처분")
|
||||
# right_expiration_checkbox = QtWidgets.QCheckBox()
|
||||
# self.right_expiration_layout = self.create_label_and_check(right_expiration_checkbox, "소멸", "특허등록 후 존속기간이 만료되어 \n 권리가 소멸된 상태")
|
||||
# right_void_checkbox = QtWidgets.QCheckBox()
|
||||
# self.right_void_layout = self.create_label_and_check(right_void_checkbox, "무효", "출원 또는 등록된 상태에 대하여 특정 사유로 인해 \n 그 권리나 행위가 무효화 된 상태")
|
||||
# right_Withdrawal_checkbox = QtWidgets.QCheckBox()
|
||||
# self.right_Withdrawal_layout = self.create_label_and_check(right_Withdrawal_checkbox, "취하", "출원한 특허가 등록되기전 여러 사유로 인하여 \n 출원이 취소된 상태")
|
||||
# right_remise_checkbox = QtWidgets.QCheckBox()
|
||||
# self.right_remise_layout = self.create_label_and_check(right_remise_checkbox, "포기", "출원인의 포기서 제출, 등록료 불납 등으로 \n 등록결정이나 권리를 포기한 상태")
|
||||
# right_Disclosure_checkbox = QtWidgets.QCheckBox()
|
||||
# self.right_Disclosure_layout = self.create_label_and_check(right_Disclosure_checkbox, "공개", "출원이나 등록사실이 일반 공중에게 공표된 상태로 \n 출원 후 18개월이 지난 건\n*조기공개신청시 18개월 미만도 공개가능")
|
||||
# 체크박스 툴팁 설정
|
||||
self.right_rejected_checkbox.setToolTip("출원 후 특허 심사과정에서 ...")
|
||||
self.right_registered_checkbox.setToolTip("심사관이 심사한 결과 ...")
|
||||
self.right_expiration_checkbox.setToolTip("특허등록 후 존속기간이 ...")
|
||||
self.right_void_checkbox.setToolTip("출원 또는 등록된 상태에 ...")
|
||||
self.right_Withdrawal_checkbox.setToolTip("출원한 특허가 등록되기전 ...")
|
||||
self.right_remise_checkbox.setToolTip("출원인의 포기서 제출, ...")
|
||||
self.right_Disclosure_checkbox.setToolTip("출원이나 등록사실이 일반 ...")
|
||||
|
||||
self.checkWidget = QtWidgets.QWidget()
|
||||
self.check_layout = QtWidgets.QGridLayout()
|
||||
|
||||
self.checkWidget.setLayout(self.check_layout)
|
||||
self.check_layout.addWidget(self.all_checkbox,1,1)
|
||||
self.check_layout.addWidget(self.right_rejected_checkbox,2,1)
|
||||
self.check_layout.addWidget(self.right_registered_checkbox,2,2)
|
||||
self.check_layout.addWidget(self.right_expiration_checkbox,2,3)
|
||||
self.check_layout.addWidget(self.right_void_checkbox,3,1)
|
||||
self.check_layout.addWidget(self.right_Withdrawal_checkbox,3,2)
|
||||
self.check_layout.addWidget(self.right_remise_checkbox,3,3)
|
||||
self.check_layout.addWidget(self.right_Disclosure_checkbox,4,1)
|
||||
# self.check_layout.addLayout(self.right_rejected_layout,1,1)
|
||||
# self.check_layout.addLayout(self.right_registered_layout,1,2)
|
||||
# self.check_layout.addLayout(self.right_expiration_layout,2,1)
|
||||
# self.check_layout.addLayout(self.right_void_layout,2,2)
|
||||
# self.check_layout.addLayout(self.right_Withdrawal_layout,3,1)
|
||||
# self.check_layout.addLayout(self.right_remise_layout,3,2)
|
||||
# self.check_layout.addLayout(self.right_Disclosure_layout,4,1)
|
||||
self.check_layout.addWidget(self.all_checkbox, 1, 1)
|
||||
self.check_layout.addWidget(self.right_rejected_checkbox, 2, 1)
|
||||
self.check_layout.addWidget(self.right_registered_checkbox, 2, 2)
|
||||
self.check_layout.addWidget(self.right_expiration_checkbox, 2, 3)
|
||||
self.check_layout.addWidget(self.right_void_checkbox, 3, 1)
|
||||
self.check_layout.addWidget(self.right_Withdrawal_checkbox, 3, 2)
|
||||
self.check_layout.addWidget(self.right_remise_checkbox, 3, 3)
|
||||
self.check_layout.addWidget(self.right_Disclosure_checkbox, 4, 1)
|
||||
self.checkWidget.setVisible(False)
|
||||
self.mainLayout.addWidget(self.checkWidget)
|
||||
|
||||
|
||||
settingKipris_layout.addWidget(self.apiLayoutWidget)
|
||||
|
||||
# 웹방식 사용 위젯 및 레이아웃
|
||||
# 웹방식 사용 위젯
|
||||
self.webLayoutWidget = QtWidgets.QWidget(self.settingKiprisWidget)
|
||||
webLayout = QtWidgets.QVBoxLayout(self.webLayoutWidget)
|
||||
self.webLayoutWidget.setLayout(webLayout)
|
||||
|
|
@ -195,36 +140,31 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||
self.useWebSwitch.clicked.connect(self.toggleWebUsage)
|
||||
webLayout.addLayout(self.create_label_and_switch(self.webLayoutWidget, "웹방식 사용", self.useWebSwitch))
|
||||
|
||||
settingKipris_layout.addWidget(self.apiLayoutWidget)
|
||||
settingKipris_layout.addWidget(self.webLayoutWidget)
|
||||
|
||||
# 확인 및 취소 버튼
|
||||
buttons = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel, parent=self)
|
||||
buttons = QtWidgets.QDialogButtonBox(
|
||||
QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel,
|
||||
parent=self)
|
||||
buttons.accepted.connect(self.onAccepted)
|
||||
buttons.rejected.connect(self.reject)
|
||||
self.mainLayout.addWidget(buttons)
|
||||
|
||||
def onAccepted(self):
|
||||
# 각 위젯의 상태를 클래스 변수에 저장
|
||||
# 위젯 상태를 클래스 변수에 저장
|
||||
self.use_kipris = self.isUseKiprisSwitch.isChecked()
|
||||
self.usage_mode = 'api' if self.apikeySwitch.isChecked() else 'web'
|
||||
self.api_key = self.editAPIWidget.findChild(QtWidgets.QLineEdit).text()
|
||||
self.accept()
|
||||
|
||||
def loadSettings(self, settings):
|
||||
logger.debug(f"loadSettings 시작")
|
||||
self.logger.log("loadSettings 시작", level=logging.DEBUG)
|
||||
self.use_kipris = settings.get('use_kipris', False)
|
||||
self.usage_mode = settings.get('usage_mode', 'web')
|
||||
self.api_key = settings.get('api_key', '')
|
||||
self.set_status = settings.get('set_status', [])
|
||||
|
||||
# logger.debug(f"SettingsDialog settings : {settings}")
|
||||
|
||||
self.use_kipris = settings.get('use_kipris', False) # 기본값 False로 설정
|
||||
self.usage_mode = settings.get('usage_mode', 'web') # 기본값 'web'로 설정
|
||||
self.api_key = settings.get('api_key', '') # 기본값 빈 문자열로 설정
|
||||
self.set_status = settings.get('set_status', []) # 기본값 빈 리스트로 설정
|
||||
|
||||
# 상태 업데이트 로그 출력
|
||||
# logger.debug(f"SettingsDialog Loaded settings: use_kipris={self.use_kipris}, usage_mode={self.usage_mode}, api_key={self.api_key}")
|
||||
|
||||
|
||||
# logger.debug(f"SettingsDialog self.use_kipris : {self.use_kipris}")
|
||||
# UI 업데이트
|
||||
self.isUseKiprisSwitch.setChecked(self.use_kipris)
|
||||
self.apikeySwitch.setChecked(self.usage_mode == 'api')
|
||||
|
|
@ -247,39 +187,37 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||
|
||||
def helpKipris(self):
|
||||
dialog = HelpDialog(self)
|
||||
dialog.exec_()
|
||||
dialog.exec() # exec() 사용
|
||||
|
||||
def toggleCNYexchange(self, checked):
|
||||
self.exchangeCNYSwitch.setChecked(checked)
|
||||
self.setCNY = checked
|
||||
logger.debug(f"self.setCNY : {self.setCNY}")
|
||||
self.logger.log(f"self.setCNY : {self.setCNY}", level=logging.DEBUG)
|
||||
|
||||
def toggleUSDexchange(self, checked):
|
||||
self.exchangeUSDSwitch.setChecked(checked)
|
||||
self.setUSD = checked
|
||||
logger.debug(f"self.setUSD : {self.setUSD}")
|
||||
self.logger.log(f"self.setUSD : {self.setUSD}", level=logging.DEBUG)
|
||||
|
||||
def toggleKiprisUsage(self, checked):
|
||||
self.settingKiprisWidget.setVisible(checked)
|
||||
self.checkWidget.setVisible(checked)
|
||||
self.use_kipris = checked
|
||||
logger.debug(f"self.use_kipris : {self.use_kipris}")
|
||||
|
||||
# self.kiprisFrame.setVisible(False)
|
||||
self.logger.log(f"self.use_kipris : {self.use_kipris}", level=logging.DEBUG)
|
||||
|
||||
def toggleAPIUsage(self, checked):
|
||||
self.apikeySwitch.setChecked(checked)
|
||||
self.useWebSwitch.setChecked(not checked)
|
||||
self.editAPIWidget.setVisible(checked)
|
||||
self.usage_mode = 'api' if checked else 'web'
|
||||
logger.debug(f"self.usage_mode : {self.usage_mode}")
|
||||
self.logger.log(f"self.usage_mode : {self.usage_mode}", level=logging.DEBUG)
|
||||
|
||||
def toggleWebUsage(self, checked):
|
||||
self.useWebSwitch.setChecked(checked)
|
||||
self.apikeySwitch.setChecked(not checked)
|
||||
self.editAPIWidget.setVisible(not checked)
|
||||
self.usage_mode = 'web' if checked else 'api'
|
||||
logger.debug(f"self.usage_mode : {self.usage_mode}")
|
||||
self.logger.log(f"self.usage_mode : {self.usage_mode}", level=logging.DEBUG)
|
||||
|
||||
def create_label_and_switch(self, widget, label_text, target_switch):
|
||||
layout = QtWidgets.QHBoxLayout()
|
||||
|
|
@ -297,7 +235,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||
layout.addWidget(label)
|
||||
layout.addWidget(textField)
|
||||
return layout
|
||||
|
||||
|
||||
def create_label_and_check(self, target_check, label_text, tooltip):
|
||||
layout = QtWidgets.QHBoxLayout()
|
||||
label = QtWidgets.QLabel(label_text)
|
||||
|
|
@ -315,10 +253,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||
elif state == QtCore.Qt.Unchecked:
|
||||
if status in self.set_status:
|
||||
self.set_status.remove(status)
|
||||
|
||||
logger.debug(f"self.set_status : {self.set_status}")
|
||||
|
||||
# logger.debug("Current Status List:", self.set_status)
|
||||
self.logger.log(f"self.set_status : {self.set_status}", level=logging.DEBUG)
|
||||
|
||||
def handle_all_checked(self, state):
|
||||
if state == QtCore.Qt.Checked:
|
||||
|
|
@ -329,7 +264,6 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||
self.right_Withdrawal_checkbox.setChecked(True)
|
||||
self.right_remise_checkbox.setChecked(True)
|
||||
self.right_Disclosure_checkbox.setChecked(True)
|
||||
|
||||
elif state == QtCore.Qt.Unchecked:
|
||||
self.right_rejected_checkbox.setChecked(False)
|
||||
self.right_expiration_checkbox.setChecked(False)
|
||||
|
|
@ -337,32 +271,10 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||
self.right_Withdrawal_checkbox.setChecked(False)
|
||||
self.right_remise_checkbox.setChecked(False)
|
||||
self.right_Disclosure_checkbox.setChecked(False)
|
||||
self.right_registered_checkbox.setChecked(True) # "등록"은 항상 체크
|
||||
self.logger.log(f"all_checked : {state}", level=logging.DEBUG)
|
||||
|
||||
self.right_registered_checkbox.setChecked(True) # "등록" 체크박스는 항상 체크
|
||||
|
||||
logger.debug(f"all_checked : {state}")
|
||||
|
||||
# def handle_checkbox_state_changed(self):
|
||||
# for checkbox in self.checkboxes:
|
||||
# # 글자를 진하게 만들기
|
||||
# font = checkbox.font()
|
||||
# font.setBold(checkbox.isChecked())
|
||||
# checkbox.setFont(font)
|
||||
|
||||
# # 전체 체크 상태 업데이트
|
||||
# all_checked = all(checkbox.isChecked() for checkbox in self.checkboxes)
|
||||
# all_unchecked = all(not checkbox.isChecked() for checkbox in self.checkboxes[1:]) # "등록" 제외
|
||||
|
||||
# self.all_checkbox.blockSignals(True) # 시그널 일시 중지
|
||||
# if all_checked:
|
||||
# self.all_checkbox.setCheckState(QtCore.Qt.Checked)
|
||||
# elif all_unchecked:
|
||||
# self.all_checkbox.setCheckState(QtCore.Qt.Unchecked)
|
||||
# else:
|
||||
# self.all_checkbox.setCheckState(QtCore.Qt.PartiallyChecked)
|
||||
# self.all_checkbox.blockSignals(False) # 시그널 재개
|
||||
|
||||
|
||||
# --- HelpDialog 클래스 ---
|
||||
class HelpDialog(QtWidgets.QDialog):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
|
@ -370,7 +282,6 @@ class HelpDialog(QtWidgets.QDialog):
|
|||
if parent is not None:
|
||||
self.setModal(True)
|
||||
self.setParent(parent)
|
||||
# 위치를 부모 윈도우의 중앙으로 설정
|
||||
parent_geometry = parent.geometry()
|
||||
self.setGeometry(
|
||||
parent_geometry.x() + (parent_geometry.width() - 200) // 2,
|
||||
|
|
@ -378,52 +289,28 @@ class HelpDialog(QtWidgets.QDialog):
|
|||
400, 300
|
||||
)
|
||||
else:
|
||||
self.resize(400, 300) # 단독 실행 시 크기 설정
|
||||
|
||||
logger.debug(f"HelpDialog 초기화")
|
||||
|
||||
self.resize(400, 300)
|
||||
self.logger.log("HelpDialog 초기화", level=logging.DEBUG)
|
||||
self.setupUI()
|
||||
|
||||
def setupUI(self):
|
||||
logger.debug(f"HelpDialog setupUI 로드")
|
||||
|
||||
self.logger.log("HelpDialog setupUI 로드", level=logging.DEBUG)
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
textBrowser = QtWidgets.QTextBrowser(self)
|
||||
textBrowser.setOpenExternalLinks(False) # 외부 링크 자동 열기 비활성화
|
||||
self.resize(600, 400) # 크기 설정
|
||||
|
||||
textBrowser.setOpenExternalLinks(False)
|
||||
self.resize(600, 400)
|
||||
textBrowser.setHtml("""
|
||||
<h1>사용 방법 안내</h1>
|
||||
<p><b>1.</b> 블라블라블라~#@!!!!!!!!!!!!!!!!!!!!!!!!!!!</p>
|
||||
<p><b>2.</b> 블라블라블라42333333333rf3rw3r</p>
|
||||
<p>자세한 정보는 <a href='http://example.com'>여기</a>를 클릭하세요.</p>
|
||||
<img src='path/to/image.png' alt='이미지 설명'>
|
||||
<h1>사용 방법 안내</h1>
|
||||
<p><b>1.</b> 블라블라블라~#@!!!!!!!!!!!!!!!!!!!!!!!!!!!</p>
|
||||
<p><b>2.</b> 블라블라블라42333333333rf3rw3r</p>
|
||||
<p>자세한 정보는 <a href='http://example.com'>여기</a>를 클릭하세요.</p>
|
||||
<img src='path/to/image.png' alt='이미지 설명'>
|
||||
""")
|
||||
layout.addWidget(textBrowser)
|
||||
|
||||
textBrowser.anchorClicked.connect(self.handleLinkClick)
|
||||
|
||||
# 확인 버튼 추가
|
||||
closeButton = QtWidgets.QPushButton("닫기", self)
|
||||
closeButton.clicked.connect(self.close)
|
||||
layout.addWidget(closeButton)
|
||||
|
||||
def handleLinkClick(self, url):
|
||||
QDesktopServices.openUrl(url)
|
||||
|
||||
|
||||
# ※ 행정 상태 도움말
|
||||
# 거절 : 출원 후 특허 심사과정에서 실체적인 특허 등록요건을 만족하지 못할 경우에 심사관이 취하는 행정처분
|
||||
# 등록 : 심사관이 심사한 결과 등록요건에 적합하여 설정등록을 받을 수 있다는 내용의 행정처분
|
||||
# 소멸 : 특허등록 후 존속기간이 만료되어 권리가 소멸된 상태
|
||||
# 무효 : 출원 또는 등록된 상태에 대하여 특정 사유로 인해 그 권리나 행위가 무효화 된 상태
|
||||
# 취하 : 출원한 특허가 등록되기전 여러 사유로 인하여 출원이 취소된 상태
|
||||
# 포기 : 출원인의 포기서 제출, 등록료 불납 등으로 등록결정이나 권리를 포기한 상태
|
||||
# 공개 : 출원이나 등록사실이 일반 공중에게 공표된 상태로 출원 후 18개월이 지난 건
|
||||
# *조기공개신청시 18개월 미만도 공개가능
|
||||
#
|
||||
|
|
@ -1,115 +1,99 @@
|
|||
import logging
|
||||
import os
|
||||
from PyQt5.QtCore import pyqtSignal, QObject
|
||||
from logging.handlers import RotatingFileHandler
|
||||
from PySide6.QtCore import QObject, Signal
|
||||
import traceback
|
||||
import inspect
|
||||
|
||||
def setup_logger(name, log_file, level=logging.DEBUG, max_bytes=10*1024*1024, backup_count=5):
|
||||
"""로거 설정을 위한 함수
|
||||
DEBUG: 프로그램의 내부 상황을 상세하게 알고 싶을 때 사용합니다. 가장 낮은 레벨입니다.
|
||||
INFO: 프로그램의 정상적인 작동 정보를 알릴 때 사용합니다.
|
||||
WARNING: 예상치 못한 일이 발생했거나, 문제가 될 가능성이 있는 상황에 대해 경고할 때 사용합니다.
|
||||
ERROR: 프로그램이 일부 문제로 인해 정상적으로 작동하지 않을 때 사용합니다.
|
||||
CRITICAL: 매우 심각한 문제가 발생하여 프로그램이 실행을 계속할 수 없을 때 사용합니다.
|
||||
|
||||
|
||||
main.py파일
|
||||
------------------------------------------------------------
|
||||
from logger_module import setup_logger
|
||||
import logging
|
||||
class Logger(QObject):
|
||||
log_signal = Signal(str) # GUI로 로그 메시지를 전달할 시그널
|
||||
|
||||
# 로그 레벨을 DEBUG로 설정하여 로거를 초기화합니다.
|
||||
logger = setup_logger('default_logger', 'application.log', level=logging.DEBUG)
|
||||
def __init__(self, gui_logger=None, log_file="app.log", logger_name="MainLogger", level=logging.INFO):
|
||||
"""
|
||||
Logger 초기화
|
||||
:param gui_logger: GUI에 로그를 출력할 콜백 함수
|
||||
:param log_file: 로그 파일 이름
|
||||
:param logger_name: 로거 이름
|
||||
:param level: 기본 로그 레벨
|
||||
"""
|
||||
super().__init__()
|
||||
self.gui_logger = gui_logger
|
||||
|
||||
# 사용 예시
|
||||
logger.debug('디버그 메시지입니다.')
|
||||
logger.info('정보 메시지입니다.')
|
||||
------------------------------------------------------------
|
||||
# 로그 설정
|
||||
self.logger = logging.getLogger(logger_name)
|
||||
self.logger.setLevel(level) # 로거 레벨 설정
|
||||
|
||||
|
||||
main.py에 import된 파일
|
||||
------------------------------------------------------------
|
||||
import logging
|
||||
# 포맷 설정
|
||||
self.simple_format = "[%(asctime)s] [%(levelname)s] %(message)s"
|
||||
self.detailed_format = (
|
||||
"[%(asctime)s] [%(threadName)s] [%(levelname)s] "
|
||||
"[%(filename)s:%(funcName)s:%(lineno)d] %(message)s"
|
||||
)
|
||||
|
||||
# 로거 인스턴스 가져오기
|
||||
logger = logging.getLogger('default_logger')
|
||||
|
||||
def login_function():
|
||||
# 로깅 예시
|
||||
logger.info("로그인 시도 중...")
|
||||
try:
|
||||
# 로그인 성공 로직
|
||||
logger.info("로그인 성공")
|
||||
except Exception as e:
|
||||
logger.error(f"로그인 실패: {e}")
|
||||
------------------------------------------------------------
|
||||
# 핸들러 추가
|
||||
self._add_console_handler(level)
|
||||
self._add_file_handler(log_file, level)
|
||||
|
||||
"""
|
||||
# formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
formatter = logging.Formatter('%(asctime)s - %(filename)s:%(lineno)d - %(name)s - %(levelname)s - %(message)s')
|
||||
# GUI Logger 연결
|
||||
if self.gui_logger:
|
||||
self.log_signal.connect(self.gui_logger)
|
||||
|
||||
|
||||
# RotatingFileHandler를 사용하여 로그 파일 설정
|
||||
handler = RotatingFileHandler(log_file, maxBytes=max_bytes, backupCount=backup_count, encoding='utf-8')
|
||||
handler.setFormatter(formatter)
|
||||
|
||||
logger = logging.getLogger(name)
|
||||
logger.setLevel(level)
|
||||
logger.addHandler(handler)
|
||||
|
||||
# 콘솔 로그 출력을 위한 핸들러가 이미 추가되었는지 확인
|
||||
if not any(isinstance(h, logging.StreamHandler) for h in logger.handlers):
|
||||
def _add_console_handler(self, level):
|
||||
"""콘솔 핸들러 추가"""
|
||||
console_handler = logging.StreamHandler()
|
||||
console_handler.setFormatter(formatter)
|
||||
console_handler.setLevel(level)
|
||||
logger.addHandler(console_handler)
|
||||
formatter = logging.Formatter(
|
||||
self.detailed_format if level <= logging.DEBUG else self.simple_format
|
||||
)
|
||||
console_handler.setFormatter(formatter)
|
||||
self.logger.addHandler(console_handler)
|
||||
|
||||
# logger.propagate = False # 로그 이벤트가 루트 로거로 전파되지 않도록 설정
|
||||
def set_gui_logger(self, gui_logger):
|
||||
self.gui_logger = gui_logger
|
||||
|
||||
return logger
|
||||
def _add_file_handler(self, log_file, level):
|
||||
"""파일 핸들러 추가"""
|
||||
file_handler = RotatingFileHandler(
|
||||
log_file, maxBytes=10 * 1024 * 1024, backupCount=5, encoding="utf-8"
|
||||
)
|
||||
file_handler.setLevel(level)
|
||||
formatter = logging.Formatter(
|
||||
self.detailed_format if level <= logging.DEBUG else self.simple_format
|
||||
)
|
||||
file_handler.setFormatter(formatter)
|
||||
self.logger.addHandler(file_handler)
|
||||
|
||||
# # 기본 로거 설정
|
||||
# log_directory = "logs"
|
||||
# if not os.path.exists(log_directory):
|
||||
# os.makedirs(log_directory)
|
||||
def log(self, message, level=logging.INFO, exc_info=False):
|
||||
"""로그 메시지 기록"""
|
||||
if exc_info:
|
||||
message = f"{message}\n{traceback.format_exc()}"
|
||||
|
||||
# default_logger = setup_logger('default_logger', os.path.join(log_directory, 'application.log'))
|
||||
# 호출 위치 정보를 동적으로 추출
|
||||
caller_frame = logging.currentframe().f_back
|
||||
record = self.logger.makeRecord(
|
||||
self.logger.name, level, caller_frame.f_code.co_filename,
|
||||
caller_frame.f_lineno, message, None, None, caller_frame.f_code.co_name
|
||||
)
|
||||
|
||||
class QTextEditLogger(logging.Handler, QObject):
|
||||
#appendPlainText = pyqtSignal(str) # 로그 메시지를 전달할 시그널
|
||||
appendHtml = pyqtSignal(str) # HTML 메시지를 전달할 시그널 정의
|
||||
scrollToBottom = pyqtSignal() # 스크롤을 최하단으로 이동시키는 시그널
|
||||
# 로거에 메시지 전달
|
||||
self.logger.handle(record)
|
||||
|
||||
def __init__(self):
|
||||
logging.Handler.__init__(self)
|
||||
QObject.__init__(self)
|
||||
# GUI 로그로 전달 (포맷 적용)
|
||||
if self.gui_logger:
|
||||
formatter = logging.Formatter(
|
||||
self.detailed_format if self.logger.level <= logging.DEBUG else self.simple_format
|
||||
)
|
||||
formatted_message = formatter.format(record)
|
||||
colored_message = self.format_gui_message(formatted_message, level)
|
||||
self.log_signal.emit(colored_message)
|
||||
|
||||
def emit(self, record):
|
||||
msg = self.format(record) # 로그 레코드를 문자열로 포매팅
|
||||
|
||||
if record.levelno == logging.DEBUG:
|
||||
color = "black"
|
||||
elif record.levelno == logging.INFO:
|
||||
color = "grey"
|
||||
elif record.levelno == logging.WARNING:
|
||||
color = "orange"
|
||||
elif record.levelno == logging.ERROR:
|
||||
color = "red"
|
||||
elif record.levelno == logging.CRITICAL:
|
||||
color = "purple"
|
||||
else:
|
||||
color = "black"
|
||||
|
||||
# HTML 스타일을 적용한 메시지 생성
|
||||
message = f"<span style=\"color:{color};\">{msg}</span><br/>"
|
||||
self.appendHtml.emit(message) # HTML 메시지로 변경
|
||||
self.scrollToBottom.emit() # 스크롤 시그널 발생
|
||||
|
||||
def close(self):
|
||||
# 핸들러 종료 시 필요한 작업 구현
|
||||
self.flush()
|
||||
logging.Handler.close(self)
|
||||
|
||||
def flush(self):
|
||||
# 커스텀 flush 구현
|
||||
# 필요한 경우 안전한 정리 작업을 수행
|
||||
pass
|
||||
def format_gui_message(self, message, level):
|
||||
"""GUI 로그 메시지의 HTML 색상 지정"""
|
||||
color_map = {
|
||||
logging.DEBUG: "gray",
|
||||
logging.INFO: "black",
|
||||
logging.WARNING: "orange",
|
||||
logging.ERROR: "red",
|
||||
logging.CRITICAL: "purple",
|
||||
}
|
||||
color = color_map.get(level, "black")
|
||||
return f'<span style="color:{color};">{message}</span>'
|
||||
|
|
|
|||
|
|
@ -1,116 +1,85 @@
|
|||
import sys
|
||||
from PyQt5.QtWidgets import QSizePolicy, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QGridLayout
|
||||
from PyQt5.QtGui import QPixmap
|
||||
from PyQt5.QtCore import Qt
|
||||
# from PyQt5.Qt import QDesktopServices
|
||||
import webbrowser
|
||||
from PySide6.QtWidgets import QSizePolicy, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QGridLayout
|
||||
from PySide6.QtGui import QPixmap
|
||||
from PySide6.QtCore import Qt
|
||||
import requests
|
||||
from PIL import Image
|
||||
from io import BytesIO
|
||||
import asyncio, aiofiles, aiohttp
|
||||
import logging
|
||||
import asyncio, aiohttp
|
||||
|
||||
# 로거 인스턴스 가져오기
|
||||
logger = logging.getLogger('default_logger')
|
||||
class ResultWidget(QWidget):
|
||||
def __init__(self):
|
||||
def __init__(self, logger):
|
||||
super().__init__()
|
||||
self.logger = logger
|
||||
self.initUI()
|
||||
|
||||
|
||||
def initUI(self):
|
||||
self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint)
|
||||
|
||||
def show_results(self, results, searchType, elapsed_time, currentURL=''):
|
||||
# 결과를 표시하기 전에 이전 결과를 지웁니다.
|
||||
self.clear_results()
|
||||
|
||||
searchType = searchType
|
||||
elapsed_time = elapsed_time
|
||||
currentURL = currentURL
|
||||
logger.debug(f"show_results - searchType : {searchType}")
|
||||
logger.debug(f"show_results - elapsed_time : {elapsed_time}")
|
||||
# try:
|
||||
# 결과 위젯 생성
|
||||
self.logger.log(f"show_results - searchType : {searchType}", level=logging.DEBUG)
|
||||
self.logger.log(f"show_results - elapsed_time : {elapsed_time}", level=logging.DEBUG)
|
||||
self.results_widget = QWidget()
|
||||
layout = QVBoxLayout()
|
||||
self.results_widget.setLayout(layout)
|
||||
|
||||
# 결과 갯수 확인 및 레이아웃 동적 생성
|
||||
total_count = int(results['total_count'])
|
||||
set_count = min(total_count, 10)
|
||||
grid_layout = QGridLayout()
|
||||
layout.addLayout(grid_layout)
|
||||
grid_index = 0
|
||||
grid_columns = 5
|
||||
logger.debug(f"show_results - set_count : {set_count}")
|
||||
|
||||
for i in range(1, set_count + 1):
|
||||
result_key = f"result_{i}"
|
||||
if result_key in results:
|
||||
result = results[result_key]
|
||||
logger.debug(f"show_results - result_key : {result_key}")
|
||||
|
||||
# 테두리 설정
|
||||
border_style = ''
|
||||
if result['application_status'] == '등록':
|
||||
border_style = 'border: 4px solid red;'
|
||||
elif result['application_status'] == '공고':
|
||||
border_style = 'border: 3px solid black;'
|
||||
|
||||
# 각 결과에 대한 레이아웃 생성
|
||||
item_layout = QVBoxLayout()
|
||||
item_widget = QWidget() # 위젯 생성
|
||||
|
||||
# item_layout의 크기 정책 설정
|
||||
item_widget = QWidget()
|
||||
item_widget.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.MinimumExpanding)
|
||||
|
||||
# 이미지 처리
|
||||
image_label = QLabel()
|
||||
image_label.setFixedSize(150, 150)
|
||||
image_data = self.fetch_image_data(result['drawing_url'])
|
||||
pixmap = QPixmap()
|
||||
pixmap.loadFromData(image_data)
|
||||
# QLabel의 크기에 맞게 이미지 크기 조정
|
||||
scaled_pixmap = pixmap.scaled(image_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
||||
image_label.setPixmap(scaled_pixmap)
|
||||
# QLabel의 가로 세로 중앙에 이미지 표시
|
||||
image_label.setAlignment(Qt.AlignCenter)
|
||||
# 이미지 표시 위젯의 크기 조정 정책 설정
|
||||
image_label.setScaledContents(True)
|
||||
|
||||
#이미지 중앙배치를 위해
|
||||
horizontal_layout = QHBoxLayout()
|
||||
horizontal_layout.addWidget(image_label)
|
||||
horizontal_layout.setAlignment(Qt.AlignCenter)
|
||||
item_layout.addLayout(horizontal_layout)
|
||||
|
||||
# item_layout.addWidget(image_label)
|
||||
|
||||
if searchType =='api':
|
||||
# API 정보 텍스트
|
||||
# info_text = f"상표권명: {result['title']}\n등록상태: {result['admin_status']}\nCategory: {result['product_category']}\nApplicant: {result['applicant']}\nPublication Date: {result['publication_date']}\nRegistration Date: {result['registration_date']}"
|
||||
info_text = f"<span style='font-size: 11pt; font-weight: bold; text-decoration: underline;'>상표권명: {result['title']}</span><br>\n" \
|
||||
f"<span style='font-size: 11pt; font-weight: bold; text-decoration: underline;'>등록상태: {result['application_status']}</span><br>\n" \
|
||||
f"<span style='font-size: 9pt;'>카테고리: {result['classification_code']}</span><br>\n" \
|
||||
f"<span style='font-size: 9pt;'>권리자: {result['applicant_name']}</span><br>\n" \
|
||||
f"<span style='font-size: 9pt;'>출원일자 {result['application_date']}</span><br>\n" \
|
||||
f"<span style='font-size: 9pt;'>공고일자 {result['publication_date']}</span><br>\n" \
|
||||
f"<span style='font-size: 9pt;'>등록일자 {result['registration_date']}</span>\n" \
|
||||
f"<span style='font-size: 9pt;'>전문 {result['full_text']}</span><br>\n"
|
||||
elif searchType =='web':
|
||||
# WEB 정보 텍스트
|
||||
# info_text = f"상표권명: {result['title']}\n등록상태: {result['admin_status']}\nCategory: {result['product_category']}\nApplicant: {result['applicant']}\nPublication Date: {result['publication_date']}\nRegistration Date: {result['registration_date']}"
|
||||
info_text = f"<span style='font-size: 11pt; font-weight: bold; text-decoration: underline;'>상표권명: {result['title']}</span><br>\n" \
|
||||
f"<span style='font-size: 11pt; font-weight: bold; text-decoration: underline;'>등록상태: {result['application_status']}</span><br>\n" \
|
||||
f"<span style='font-size: 9pt;'>카테고리: {result['product_category']}</span><br>\n" \
|
||||
f"<span style='font-size: 9pt;'>권리자: {result['applicant_name']}</span><br>\n" \
|
||||
f"<span style='font-size: 9pt;'> {result['publication_date']}</span><br>\n" \
|
||||
f"<span style='font-size: 9pt;'> {result['registration_date']}</span>"
|
||||
|
||||
if searchType == 'api':
|
||||
info_text = (f"<span style='font-size: 11pt; font-weight: bold; text-decoration: underline;'>"
|
||||
f"상표권명: {result['title']}</span><br>\n"
|
||||
f"<span style='font-size: 11pt; font-weight: bold; text-decoration: underline;'>"
|
||||
f"등록상태: {result['application_status']}</span><br>\n"
|
||||
f"<span style='font-size: 9pt;'>카테고리: {result['classification_code']}</span><br>\n"
|
||||
f"<span style='font-size: 9pt;'>권리자: {result['applicant_name']}</span><br>\n"
|
||||
f"<span style='font-size: 9pt;'>출원일자 {result['application_date']}</span><br>\n"
|
||||
f"<span style='font-size: 9pt;'>공고일자 {result['publication_date']}</span><br>\n"
|
||||
f"<span style='font-size: 9pt;'>등록일자 {result['registration_date']}</span><br>\n"
|
||||
f"<span style='font-size: 9pt;'>전문 {result['full_text']}</span><br>\n")
|
||||
elif searchType == 'web':
|
||||
info_text = (f"<span style='font-size: 11pt; font-weight: bold; text-decoration: underline;'>"
|
||||
f"상표권명: {result['title']}</span><br>\n"
|
||||
f"<span style='font-size: 11pt; font-weight: bold; text-decoration: underline;'>"
|
||||
f"등록상태: {result['application_status']}</span><br>\n"
|
||||
f"<span style='font-size: 9pt;'>카테고리: {result['product_category']}</span><br>\n"
|
||||
f"<span style='font-size: 9pt;'>권리자: {result['applicant_name']}</span><br>\n"
|
||||
f"<span style='font-size: 9pt;'> {result['publication_date']}</span><br>\n"
|
||||
f"<span style='font-size: 9pt;'> {result['registration_date']}</span>")
|
||||
info_label = QLabel(info_text)
|
||||
if searchType =='web':
|
||||
currentURL_btn = QPushButton("웹 열기")
|
||||
# currentURL_btn.clicked.connect(self.openCurrentPage(currentURL))
|
||||
info_label.setToolTip(self.wrap_text(result['category_description'], 50))
|
||||
image_label.setToolTip(self.wrap_text(result['category_description'], 50))
|
||||
item_layout.addWidget(info_label)
|
||||
|
|
@ -118,110 +87,82 @@ class ResultWidget(QWidget):
|
|||
image_label.setStyleSheet(border_style)
|
||||
info_label.setStyleSheet(border_style)
|
||||
|
||||
# 레이아웃에 위젯 추가
|
||||
row = grid_index // grid_columns
|
||||
col = grid_index % grid_columns
|
||||
grid_layout.addLayout(item_layout, row, col)
|
||||
grid_index += 1
|
||||
|
||||
# 결과 위젯에 닫기 버튼 추가
|
||||
close_button = QPushButton("Close")
|
||||
close_button.clicked.connect(self.close_results_widget)
|
||||
layout.addWidget(close_button)
|
||||
|
||||
# e
|
||||
elapsed_time_Label = QLabel(f"Elapsed Time : {elapsed_time}")
|
||||
layout.addWidget(elapsed_time_Label)
|
||||
|
||||
# 결과 위젯을 메인 윈도우에 추가
|
||||
self.results_widget.setGeometry(300, 300, 600, 300) # 위치와 크기 설정
|
||||
self.results_widget.setWindowTitle('Search Results') # 타이틀 설정
|
||||
self.results_widget.setGeometry(300, 300, 600, 300)
|
||||
self.results_widget.setWindowTitle('Search Results')
|
||||
self.results_widget.show()
|
||||
|
||||
# except Exception as e:
|
||||
# logger.debug(f"Error displaying results: {e}")
|
||||
|
||||
def clear_results(self):
|
||||
# 기존 텍스트를 초기화
|
||||
if hasattr(self, 'results_widget'):
|
||||
self.results_widget.deleteLater()
|
||||
|
||||
|
||||
def close_results_widget(self):
|
||||
# 결과 위젯닫기 함수를 호출할 때 사용하는 메서드
|
||||
self.results_widget.close()
|
||||
|
||||
def openCurrentPage(self, currentURL):
|
||||
logger.debug(f"open the page : {currentURL}")
|
||||
webbrowser.open('currentURL')
|
||||
pass
|
||||
# QDesktopServices.openUrl(self.currentURL)
|
||||
self.logger.log(f"open the page : {currentURL}", level=logging.DEBUG)
|
||||
webbrowser.open(currentURL)
|
||||
|
||||
def wrap_text(self, text, width=40):
|
||||
"""주어진 너비에 맞게 텍스트를 줄바꿈합니다."""
|
||||
words = text.split()
|
||||
wrapped_text = ''
|
||||
line_length = 0
|
||||
|
||||
for word in words:
|
||||
if line_length + len(word) + 1 > width:
|
||||
wrapped_text += '\n'
|
||||
line_length = 0
|
||||
wrapped_text += word + ' '
|
||||
line_length += len(word) + 1
|
||||
|
||||
return wrapped_text.strip()
|
||||
|
||||
|
||||
async def fetch_image_data_async(self, url):
|
||||
"""주어진 URL로부터 이미지 데이터를 비동기적으로 가져와 반환합니다."""
|
||||
async with aiohttp.ClientSession() as session:
|
||||
# logger.debug(f"download_image session Start!!")
|
||||
async with session.get(url) as response:
|
||||
logger.debug(f"download_image url : {url}")
|
||||
self.logger.log(f"download_image url : {url}", level=logging.DEBUG)
|
||||
if response.status == 200:
|
||||
# logger.debug(f"response : {response}")
|
||||
content_type = response.headers.get('Content-Type', '') # await 제거
|
||||
logger.debug(f"content_type : {content_type}")
|
||||
content_type = response.headers.get('Content-Type', '')
|
||||
self.logger.log(f"content_type : {content_type}", level=logging.DEBUG)
|
||||
if 'image' in content_type or 'octet-stream' in content_type:
|
||||
# logger.debug(f"image content type or octet-stream : {content_type}")
|
||||
return await response.read()
|
||||
else:
|
||||
try:
|
||||
# Content-Type이 이미지가 아니면, 데이터를 이미지로 변환
|
||||
data = await response.read()
|
||||
# logger.debug(f"Content-Type이 이미지가 아님 : {data}")
|
||||
image = Image.open(BytesIO(data))
|
||||
with BytesIO() as buffer:
|
||||
image.save(buffer, 'JPEG')
|
||||
logger.debug(f"image 를 JPEG로 저장")
|
||||
self.logger.log("image 를 JPEG로 저장", level=logging.DEBUG)
|
||||
return buffer.getvalue()
|
||||
except Exception as e:
|
||||
logger.debug(f"이미지 변환 실패: {e}")
|
||||
self.logger.log(f"이미지 변환 실패: {e}", level=logging.DEBUG)
|
||||
return None
|
||||
else:
|
||||
logger.debug(f"이미지 다운로드 실패: HTTP {response.status}")
|
||||
self.logger.log(f"이미지 다운로드 실패: HTTP {response.status}", level=logging.DEBUG)
|
||||
return None
|
||||
|
||||
|
||||
def fetch_image_data(self, url):
|
||||
"""주어진 URL로부터 이미지 데이터를 가져와 반환합니다."""
|
||||
response = requests.get(url)
|
||||
if response.status_code == 200:
|
||||
# 서버 응답 헤더에서 Content-Type 확인
|
||||
content_type = response.headers.get('Content-Type', '')
|
||||
if 'image' in content_type:
|
||||
return response.content
|
||||
else:
|
||||
# Content-Type이 이미지가 아니면, 데이터를 이미지로 변환
|
||||
try:
|
||||
image = Image.open(BytesIO(response.content))
|
||||
with BytesIO() as buffer:
|
||||
image.save(buffer, 'JPEG') # 예시로 JPEG 포맷을 사용
|
||||
image.save(buffer, 'JPEG')
|
||||
return buffer.getvalue()
|
||||
except Exception as e:
|
||||
logger.debug(f"이미지 변환 실패: {e}")
|
||||
self.logger.log(f"이미지 변환 실패: {e}", level=logging.DEBUG)
|
||||
return None
|
||||
else:
|
||||
logger.debug(f"이미지 다운로드 실패: HTTP {response.status_code}")
|
||||
self.logger.log(f"이미지 다운로드 실패: HTTP {response.status_code}", level=logging.DEBUG)
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -1,36 +1,21 @@
|
|||
import requests, os
|
||||
from PyQt5.QtWidgets import QWidget, QTextBrowser, QVBoxLayout
|
||||
from PyQt5.QtCore import Qt
|
||||
import os
|
||||
import requests
|
||||
from PySide6.QtWidgets import QWidget, QTextBrowser, QVBoxLayout
|
||||
from PySide6.QtCore import Qt
|
||||
from PIL import Image
|
||||
import logging
|
||||
|
||||
# 로거 인스턴스 가져오기
|
||||
logger = logging.getLogger('default_logger')
|
||||
|
||||
class TrademarkSearchDisplay(QWidget):
|
||||
def __init__(self, parent=None):
|
||||
def __init__(self, logger, parent=None):
|
||||
super().__init__()
|
||||
self.logger =logger
|
||||
self.initUI(parent)
|
||||
|
||||
# def showEvent(self, event):
|
||||
# super().showEvent(event)
|
||||
# if self.parent() is not None:
|
||||
# parent_geometry = self.parent().geometry()
|
||||
# self.setGeometry(
|
||||
# parent_geometry.x() + (parent_geometry.width() - self.width()) // 2,
|
||||
# parent_geometry.y() + (parent_geometry.height() - self.height()) // 2,
|
||||
# self.width(), self.height()
|
||||
# )
|
||||
# self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint)
|
||||
|
||||
|
||||
def initUI(self, parent):
|
||||
|
||||
self.setWindowTitle("도움말")
|
||||
if parent is not None:
|
||||
self.setModal(True)
|
||||
self.setParent(parent)
|
||||
# 위치를 부모 윈도우의 중앙으로 설정
|
||||
parent_geometry = parent.geometry()
|
||||
self.setGeometry(
|
||||
parent_geometry.x() + (parent_geometry.width() - 200) // 2,
|
||||
|
|
@ -38,26 +23,18 @@ class TrademarkSearchDisplay(QWidget):
|
|||
1200, 600
|
||||
)
|
||||
self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint)
|
||||
|
||||
else:
|
||||
self.resize(1200, 600) # 단독 실행 시 크기 설정
|
||||
|
||||
|
||||
# self.setGeometry(100, 100, 1200, 600)
|
||||
self.resize(1200, 600)
|
||||
self.setWindowTitle('Trademark Search Results')
|
||||
|
||||
self.text_browser = QTextBrowser(self)
|
||||
self.text_browser.setOpenExternalLinks(True) # Allows opening links
|
||||
|
||||
self.text_browser.setOpenExternalLinks(True)
|
||||
layout = QVBoxLayout()
|
||||
layout.addWidget(self.text_browser)
|
||||
self.setLayout(layout)
|
||||
|
||||
|
||||
def display_api_results(self, data, elapsed_time):
|
||||
|
||||
for item in data:
|
||||
downloaded_image_path = self.download_image(item.get("drawing_url"), item.get("ID"))
|
||||
|
||||
html_content = f'''
|
||||
<div style="border: 1px solid #ccc; margin: 10px; padding: 10px;">
|
||||
<h2>{item.get("title")}</h2>
|
||||
|
|
@ -72,27 +49,22 @@ class TrademarkSearchDisplay(QWidget):
|
|||
</div>
|
||||
'''
|
||||
self.text_browser.append(html_content)
|
||||
|
||||
|
||||
def display_web_results(self, data, elapsed_time):
|
||||
logger.debug(f"Processing results... Elapsed time: {elapsed_time}s")
|
||||
# data 딕셔너리 내의 키 중 'result_'로 시작하는 키를 찾아 그 값을 처리
|
||||
self.logger.log(f"Processing results... Elapsed time: {elapsed_time}s", level=logging.DEBUG)
|
||||
for key, item in data.items():
|
||||
logger.debug(f"Checking key: {key}") # 로그 추가
|
||||
if key.startswith('result_'): # 'result_'로 시작하는 키 확인
|
||||
logger.debug(f"Found valid key: {key}, Processing item...") # 로그 추가
|
||||
if isinstance(item, dict): # item이 딕셔너리인지 확인
|
||||
logger.debug(f"Item is a dictionary. Generating HTML for item with title: {item.get('title')}") # 로그 추가
|
||||
|
||||
# 이미지 다운로드 시도
|
||||
self.logger.log(f"Checking key: {key}", level=logging.DEBUG)
|
||||
if key.startswith('result_'):
|
||||
self.logger.log(f"Found valid key: {key}, Processing item...", level=logging.DEBUG)
|
||||
if isinstance(item, dict):
|
||||
self.logger.log(f"Item is a dictionary. Generating HTML for item with title: {item.get('title', level=logging.DEBUG)}")
|
||||
downloaded_image_path = self.download_image(item.get("drawing_url"), item.get("ID"))
|
||||
if downloaded_image_path:
|
||||
logger.debug(f"Image downloaded and saved to {downloaded_image_path}")
|
||||
self.logger.log(f"Image downloaded and saved to {downloaded_image_path}", level=logging.DEBUG)
|
||||
image_html = f'<img src="{downloaded_image_path}" style="width:100%; max-width:300px; height:auto;">'
|
||||
else:
|
||||
logger.debug("Failed to download image.")
|
||||
self.logger.log("Failed to download image.", level=logging.DEBUG)
|
||||
image_html = 'Image not available'
|
||||
|
||||
# HTML 콘텐츠 생성
|
||||
html_content = f'''
|
||||
<table style="width: 100%; border-collapse: collapse; border: 1px solid #ccc; margin-bottom: 20px;">
|
||||
<tr>
|
||||
|
|
@ -102,58 +74,47 @@ class TrademarkSearchDisplay(QWidget):
|
|||
<tr>
|
||||
<td rowspan="4" style="width: 40%; text-align: center; border-right: 2px solid #000;">
|
||||
<img src="file:///{downloaded_image_path}" alt="Trademark Image" style="width: 100px; height: 100px;">
|
||||
|
||||
</td>
|
||||
<td style="width: 30%; text-align: right; padding-right: 10px;">Admin Status:</td>
|
||||
<td style="width: 30%; padding-left: 10px;">{item.get("application_status", "정보 없음")}</td>
|
||||
<td style="text-align: right; padding-right: 10px;">Admin Status:</td>
|
||||
<td style="padding-left: 10px;">{item.get("application_status", "정보 없음")}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: left; padding-right: 10px;">Product Category:</td>
|
||||
<td style="width: 30%; padding-left: 10px;">{item.get("product_category", "정보 없음")} - {item.get("category_description", "정보 없음")}</td>
|
||||
<td style="padding-left: 10px;">{item.get("product_category", "정보 없음")} - {item.get("category_description", "정보 없음")}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: left; padding-right: 10px;">Applicant:</td>
|
||||
<td style="width: 30%; padding-left: 10px;">{item.get("applicant_name", "정보 없음")}</td>
|
||||
<td style="padding-left: 10px;">{item.get("applicant_name", "정보 없음")}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: left; padding-right: 10px; border-right: 2px solid #000;">Publication Date:</td>
|
||||
<td style="width: 30%; padding-left: 10px;">{item.get("publication_date", "정보 없음")}</td>
|
||||
<td style="padding-left: 10px;">{item.get("publication_date", "정보 없음")}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: left; padding-right: 10px; border-right: 2px solid #000;">Registration Date:</td>
|
||||
<td style="width: 30%; padding-left: 10px;">{item.get("registration_date", "정보 없음")}</td>
|
||||
<td style="padding-left: 10px;">{item.get("registration_date", "정보 없음")}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div style="margin-bottom: 40px;"></div> <!-- Additional separation for visual distinction -->
|
||||
<div style="margin-bottom: 40px;"></div>
|
||||
'''
|
||||
|
||||
self.text_browser.append(html_content)
|
||||
logger.debug("HTML content appended to QTextBrowser.") # 로그 추가
|
||||
self.logger.log("HTML content appended to QTextBrowser.", level=logging.DEBUG)
|
||||
else:
|
||||
logger.debug(f"Error: Item associated with {key} is not a dictionary.") # 오류 로그
|
||||
self.logger.log(f"Error: Item associated with {key} is not a dictionary.", level=logging.DEBUG)
|
||||
else:
|
||||
logger.debug(f"Ignored key: {key}") # 무시된 키 로그
|
||||
|
||||
self.logger.log(f"Ignored key: {key}", level=logging.DEBUG)
|
||||
|
||||
def download_image(self, image_url, identifier):
|
||||
"""Download an image and save it to a local directory."""
|
||||
# 현재 실행 중인 스크립트의 디렉토리 경로를 가져온다
|
||||
base_path = os.path.dirname(os.path.realpath(__file__))
|
||||
image_folder = os.path.join(base_path, "kipris_image")
|
||||
|
||||
# kipris_image 폴더가 없다면 생성
|
||||
if not os.path.exists(image_folder):
|
||||
os.makedirs(image_folder)
|
||||
|
||||
# 이미지 파일의 경로를 설정 (고유 식별자를 파일명으로 사용)
|
||||
image_path = os.path.join(image_folder, f"{identifier}.jpg")
|
||||
|
||||
# 이미지 다운로드 및 저장
|
||||
response = requests.get(image_url)
|
||||
if response.status_code == 200:
|
||||
with open(image_path, 'wb') as file:
|
||||
file.write(response.content)
|
||||
image_path = self.resize_image(image_path)
|
||||
image_path = self.resize_image(image_path)
|
||||
return image_path
|
||||
else:
|
||||
return None
|
||||
|
|
@ -165,8 +126,5 @@ class TrademarkSearchDisplay(QWidget):
|
|||
img_resized.save(image_path)
|
||||
return image_path
|
||||
except Exception as e:
|
||||
logger.debug(f"Error resizing image: {e}")
|
||||
self.logger.log(f"Error resizing image: {e}", level=logging.DEBUG)
|
||||
return None
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +1,24 @@
|
|||
from PyQt5.QtCore import Qt, QRect, QPropertyAnimation, pyqtProperty, pyqtSignal, QPoint
|
||||
from PyQt5.QtGui import QPainter, QColor
|
||||
from PyQt5.QtWidgets import QWidget
|
||||
from PySide6.QtCore import Qt, QRect, QPropertyAnimation, Property, Signal, QPoint
|
||||
from PySide6.QtGui import QPainter, QColor
|
||||
from PySide6.QtWidgets import QWidget
|
||||
import logging
|
||||
|
||||
# 로거 인스턴스 가져오기
|
||||
logger = logging.getLogger('default_logger')
|
||||
|
||||
class ToggleSwitch(QWidget):
|
||||
clicked = pyqtSignal(bool)
|
||||
clicked = Signal(bool)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(ToggleSwitch, self).__init__(parent)
|
||||
super().__init__(parent)
|
||||
self.setFixedSize(40, 20)
|
||||
self._checked = False
|
||||
self._circle_color_checked = QColor('red')
|
||||
self._circle_color_unchecked = QColor('gray')
|
||||
self._background_color = QColor('white')
|
||||
self._circle_pos = QPoint(0, 0) # Circle's initial position.
|
||||
self._circle_pos = QPoint(0, 0)
|
||||
self.animation = QPropertyAnimation(self, b"circle_pos")
|
||||
self.animation.setDuration(250)
|
||||
|
||||
self._init_position()
|
||||
|
||||
@pyqtProperty(QPoint)
|
||||
@Property(QPoint)
|
||||
def circle_pos(self):
|
||||
return self._circle_pos
|
||||
|
||||
|
|
@ -43,7 +39,7 @@ class ToggleSwitch(QWidget):
|
|||
self.clicked.emit(self._checked)
|
||||
self._update_animation()
|
||||
self.update()
|
||||
super(ToggleSwitch, self).mousePressEvent(event)
|
||||
super().mousePressEvent(event)
|
||||
|
||||
def _update_animation(self):
|
||||
if self._checked:
|
||||
|
|
@ -60,9 +56,7 @@ class ToggleSwitch(QWidget):
|
|||
painter.setPen(Qt.NoPen)
|
||||
painter.setBrush(self._background_color)
|
||||
painter.drawRoundedRect(QRect(0, 0, 40, 20), 10, 10)
|
||||
|
||||
circle_color = self._circle_color_checked if self._checked else self._circle_color_unchecked
|
||||
|
||||
painter.setBrush(circle_color)
|
||||
painter.drawEllipse(self._circle_pos.x(), self._circle_pos.y(), 20, 20)
|
||||
|
||||
|
|
@ -71,18 +65,13 @@ class ToggleSwitch(QWidget):
|
|||
self._checked = checked
|
||||
self._update_animation()
|
||||
self.update()
|
||||
|
||||
|
||||
def isChecked(self):
|
||||
return self._checked
|
||||
|
||||
def setState(self, state):
|
||||
"""ToggleSwitch의 상태를 설정합니다.
|
||||
|
||||
Args:
|
||||
state (bool): True로 설정하면 스위치를 체크 상태로, False로 설정하면 언체크 상태로 변경합니다.
|
||||
"""
|
||||
def setState(self, state):
|
||||
if self._checked != state:
|
||||
self._checked = state
|
||||
self._update_animation()
|
||||
self.clicked.emit(self._checked)
|
||||
self.update()
|
||||
self.update()
|
||||
|
|
|
|||
Loading…
Reference in New Issue