From 13b48be802693897cc590e26d2d2143b806d4a56 Mon Sep 17 00:00:00 2001 From: BarsTiger Date: Mon, 6 Feb 2023 21:40:47 +0200 Subject: [PATCH] First working release. Other files (not .docx) support is not guaranteed --- README.md | 2 +- gui/gui.py | 300 ++++++++++++++- gui/gui.ui | 465 ++++++++++++++++++++++- gui/modules/core/blur.py | 133 ------- gui/modules/document_loader/__init__.py | 0 gui/modules/document_loader/from_gui.py | 49 +++ gui/modules/document_loader/to_gui.py | 35 ++ gui/modules/gui_helpers/__init__.py | 0 gui/modules/gui_helpers/other_options.py | 16 + gui/modules/initialize/handlers.py | 50 +++ gui/modules/initialize/setup_ui.py | 36 +- gui/modules/initialize/styles.py | 330 +++++++++++++++- modules/document/__init__.py | 0 modules/document/document_file.py | 30 ++ modules/document/document_properties.py | 36 ++ modules/helpers/__init__.py | 0 modules/helpers/convert.py | 6 + modules/helpers/xml.py | 22 ++ modules/time_tools/__init__.py | 0 modules/time_tools/time_diff.py | 9 + requirements.txt | 2 + 21 files changed, 1378 insertions(+), 143 deletions(-) delete mode 100644 gui/modules/core/blur.py create mode 100644 gui/modules/document_loader/__init__.py create mode 100644 gui/modules/document_loader/from_gui.py create mode 100644 gui/modules/document_loader/to_gui.py create mode 100644 gui/modules/gui_helpers/__init__.py create mode 100644 gui/modules/gui_helpers/other_options.py create mode 100644 gui/modules/initialize/handlers.py create mode 100644 modules/document/__init__.py create mode 100644 modules/document/document_file.py create mode 100644 modules/document/document_properties.py create mode 100644 modules/helpers/__init__.py create mode 100644 modules/helpers/convert.py create mode 100644 modules/helpers/xml.py create mode 100644 modules/time_tools/__init__.py create mode 100644 modules/time_tools/time_diff.py diff --git a/README.md b/README.md index e00a363..f0aec4f 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,4 @@ # DOCXUNTRACE Ultimate and powerful util to spoof .docx (and other .*x MS Office files) private properties, such as author name, -creation and save date, words, pages and other \ No newline at end of file +creation and save date, words, pages and other data, that cannot be changed from `Properties` tab in explorer \ No newline at end of file diff --git a/gui/gui.py b/gui/gui.py index a2800c8..2be2840 100644 --- a/gui/gui.py +++ b/gui/gui.py @@ -17,12 +17,286 @@ class Ui_MainWindow(object): def setupUi(self, MainWindow): if not MainWindow.objectName(): MainWindow.setObjectName(u"MainWindow") - MainWindow.resize(800, 460) + MainWindow.resize(400, 570) icon = QIcon() icon.addFile(u":/img/img/icon.ico", QSize(), QIcon.Normal, QIcon.Off) MainWindow.setWindowIcon(icon) + MainWindow.setStyleSheet(u"") self.centralwidget = QWidget(MainWindow) self.centralwidget.setObjectName(u"centralwidget") + self.verticalLayout = QVBoxLayout(self.centralwidget) + self.verticalLayout.setObjectName(u"verticalLayout") + self.docxuntracelabel = QLabel(self.centralwidget) + self.docxuntracelabel.setObjectName(u"docxuntracelabel") + sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.docxuntracelabel.sizePolicy().hasHeightForWidth()) + self.docxuntracelabel.setSizePolicy(sizePolicy) + self.docxuntracelabel.setStyleSheet(u"font: 87 30pt \"Segoe UI Black\";") + self.docxuntracelabel.setAlignment(Qt.AlignCenter) + + self.verticalLayout.addWidget(self.docxuntracelabel) + + self.line_name_top_openfile = QFrame(self.centralwidget) + self.line_name_top_openfile.setObjectName(u"line_name_top_openfile") + self.line_name_top_openfile.setFrameShape(QFrame.HLine) + self.line_name_top_openfile.setFrameShadow(QFrame.Sunken) + + self.verticalLayout.addWidget(self.line_name_top_openfile) + + self.path_to_original_widget = QWidget(self.centralwidget) + self.path_to_original_widget.setObjectName(u"path_to_original_widget") + self.horizontalLayout = QHBoxLayout(self.path_to_original_widget) + self.horizontalLayout.setObjectName(u"horizontalLayout") + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.path_to_original_box = QLineEdit(self.path_to_original_widget) + self.path_to_original_box.setObjectName(u"path_to_original_box") + sizePolicy1 = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + sizePolicy1.setHorizontalStretch(0) + sizePolicy1.setVerticalStretch(0) + sizePolicy1.setHeightForWidth(self.path_to_original_box.sizePolicy().hasHeightForWidth()) + self.path_to_original_box.setSizePolicy(sizePolicy1) + self.path_to_original_box.setMinimumSize(QSize(0, 30)) + + self.horizontalLayout.addWidget(self.path_to_original_box) + + self.open_document_button = QPushButton(self.path_to_original_widget) + self.open_document_button.setObjectName(u"open_document_button") + self.open_document_button.setMinimumSize(QSize(80, 30)) + + self.horizontalLayout.addWidget(self.open_document_button) + + + self.verticalLayout.addWidget(self.path_to_original_widget) + + self.line_openfile_authors = QFrame(self.centralwidget) + self.line_openfile_authors.setObjectName(u"line_openfile_authors") + self.line_openfile_authors.setFrameShape(QFrame.HLine) + self.line_openfile_authors.setFrameShadow(QFrame.Sunken) + + self.verticalLayout.addWidget(self.line_openfile_authors) + + self.authors_widget = QWidget(self.centralwidget) + self.authors_widget.setObjectName(u"authors_widget") + self.verticalLayout_2 = QVBoxLayout(self.authors_widget) + self.verticalLayout_2.setSpacing(6) + self.verticalLayout_2.setObjectName(u"verticalLayout_2") + self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) + self.authors_label = QLabel(self.authors_widget) + self.authors_label.setObjectName(u"authors_label") + + self.verticalLayout_2.addWidget(self.authors_label) + + self.creator_label = QLabel(self.authors_widget) + self.creator_label.setObjectName(u"creator_label") + + self.verticalLayout_2.addWidget(self.creator_label) + + self.creator_box = QLineEdit(self.authors_widget) + self.creator_box.setObjectName(u"creator_box") + self.creator_box.setMinimumSize(QSize(0, 30)) + + self.verticalLayout_2.addWidget(self.creator_box) + + self.last_modified_by_label = QLabel(self.authors_widget) + self.last_modified_by_label.setObjectName(u"last_modified_by_label") + + self.verticalLayout_2.addWidget(self.last_modified_by_label) + + self.last_modified_by_box = QLineEdit(self.authors_widget) + self.last_modified_by_box.setObjectName(u"last_modified_by_box") + self.last_modified_by_box.setMinimumSize(QSize(0, 30)) + + self.verticalLayout_2.addWidget(self.last_modified_by_box) + + + self.verticalLayout.addWidget(self.authors_widget) + + self.line_authors_datetime = QFrame(self.centralwidget) + self.line_authors_datetime.setObjectName(u"line_authors_datetime") + self.line_authors_datetime.setFrameShape(QFrame.HLine) + self.line_authors_datetime.setFrameShadow(QFrame.Sunken) + + self.verticalLayout.addWidget(self.line_authors_datetime) + + self.date_edit_widget = QWidget(self.centralwidget) + self.date_edit_widget.setObjectName(u"date_edit_widget") + self.verticalLayout_3 = QVBoxLayout(self.date_edit_widget) + self.verticalLayout_3.setObjectName(u"verticalLayout_3") + self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) + self.dateandtime_label = QLabel(self.date_edit_widget) + self.dateandtime_label.setObjectName(u"dateandtime_label") + + self.verticalLayout_3.addWidget(self.dateandtime_label) + + self.dateandtime_created_label = QLabel(self.date_edit_widget) + self.dateandtime_created_label.setObjectName(u"dateandtime_created_label") + + self.verticalLayout_3.addWidget(self.dateandtime_created_label) + + self.dateandtime_created_box = QDateTimeEdit(self.date_edit_widget) + self.dateandtime_created_box.setObjectName(u"dateandtime_created_box") + self.dateandtime_created_box.setMinimumSize(QSize(0, 30)) + self.dateandtime_created_box.setCalendarPopup(True) + + self.verticalLayout_3.addWidget(self.dateandtime_created_box) + + self.dateandtime_edited_label = QLabel(self.date_edit_widget) + self.dateandtime_edited_label.setObjectName(u"dateandtime_edited_label") + + self.verticalLayout_3.addWidget(self.dateandtime_edited_label) + + self.dateandtime_edited_box = QDateTimeEdit(self.date_edit_widget) + self.dateandtime_edited_box.setObjectName(u"dateandtime_edited_box") + self.dateandtime_edited_box.setMinimumSize(QSize(0, 30)) + self.dateandtime_edited_box.setCalendarPopup(True) + + self.verticalLayout_3.addWidget(self.dateandtime_edited_box) + + + self.verticalLayout.addWidget(self.date_edit_widget) + + self.line_datetime_other = QFrame(self.centralwidget) + self.line_datetime_other.setObjectName(u"line_datetime_other") + self.line_datetime_other.setFrameShape(QFrame.HLine) + self.line_datetime_other.setFrameShadow(QFrame.Sunken) + + self.verticalLayout.addWidget(self.line_datetime_other) + + self.other_properties_widget = QWidget(self.centralwidget) + self.other_properties_widget.setObjectName(u"other_properties_widget") + self.other_properties_widget.setMaximumSize(QSize(16777215, 0)) + self.verticalLayout_4 = QVBoxLayout(self.other_properties_widget) + self.verticalLayout_4.setObjectName(u"verticalLayout_4") + self.verticalLayout_4.setContentsMargins(0, 0, 0, 0) + self.other_label = QLabel(self.other_properties_widget) + self.other_label.setObjectName(u"other_label") + + self.verticalLayout_4.addWidget(self.other_label) + + self.revision_label = QLabel(self.other_properties_widget) + self.revision_label.setObjectName(u"revision_label") + + self.verticalLayout_4.addWidget(self.revision_label) + + self.revision_box = QLineEdit(self.other_properties_widget) + self.revision_box.setObjectName(u"revision_box") + self.revision_box.setMinimumSize(QSize(0, 30)) + + self.verticalLayout_4.addWidget(self.revision_box) + + self.template_label = QLabel(self.other_properties_widget) + self.template_label.setObjectName(u"template_label") + + self.verticalLayout_4.addWidget(self.template_label) + + self.template_box = QLineEdit(self.other_properties_widget) + self.template_box.setObjectName(u"template_box") + self.template_box.setMinimumSize(QSize(0, 30)) + + self.verticalLayout_4.addWidget(self.template_box) + + self.pages_words_symbols_label = QLabel(self.other_properties_widget) + self.pages_words_symbols_label.setObjectName(u"pages_words_symbols_label") + + self.verticalLayout_4.addWidget(self.pages_words_symbols_label) + + self.pages_words_symbols_widget = QWidget(self.other_properties_widget) + self.pages_words_symbols_widget.setObjectName(u"pages_words_symbols_widget") + self.horizontalLayout_2 = QHBoxLayout(self.pages_words_symbols_widget) + self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") + self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) + self.pages_box = QSpinBox(self.pages_words_symbols_widget) + self.pages_box.setObjectName(u"pages_box") + + self.horizontalLayout_2.addWidget(self.pages_box) + + self.words_box = QSpinBox(self.pages_words_symbols_widget) + self.words_box.setObjectName(u"words_box") + + self.horizontalLayout_2.addWidget(self.words_box) + + self.symbols_box = QSpinBox(self.pages_words_symbols_widget) + self.symbols_box.setObjectName(u"symbols_box") + + self.horizontalLayout_2.addWidget(self.symbols_box) + + self.lines_box = QSpinBox(self.pages_words_symbols_widget) + self.lines_box.setObjectName(u"lines_box") + + self.horizontalLayout_2.addWidget(self.lines_box) + + self.paragraphs_box = QSpinBox(self.pages_words_symbols_widget) + self.paragraphs_box.setObjectName(u"paragraphs_box") + + self.horizontalLayout_2.addWidget(self.paragraphs_box) + + + self.verticalLayout_4.addWidget(self.pages_words_symbols_widget) + + self.application_name_label = QLabel(self.other_properties_widget) + self.application_name_label.setObjectName(u"application_name_label") + + self.verticalLayout_4.addWidget(self.application_name_label) + + self.application_name_box = QLineEdit(self.other_properties_widget) + self.application_name_box.setObjectName(u"application_name_box") + self.application_name_box.setMinimumSize(QSize(0, 30)) + + self.verticalLayout_4.addWidget(self.application_name_box) + + self.custom_edit_time_label = QLabel(self.other_properties_widget) + self.custom_edit_time_label.setObjectName(u"custom_edit_time_label") + + self.verticalLayout_4.addWidget(self.custom_edit_time_label) + + self.custom_edit_time_box = QSpinBox(self.other_properties_widget) + self.custom_edit_time_box.setObjectName(u"custom_edit_time_box") + self.custom_edit_time_box.setMinimumSize(QSize(0, 30)) + self.custom_edit_time_box.setMinimum(-2147483647) + self.custom_edit_time_box.setMaximum(2147483647) + + self.verticalLayout_4.addWidget(self.custom_edit_time_box) + + + self.verticalLayout.addWidget(self.other_properties_widget) + + self.expand_other_options_button = QPushButton(self.centralwidget) + self.expand_other_options_button.setObjectName(u"expand_other_options_button") + self.expand_other_options_button.setMinimumSize(QSize(0, 30)) + + self.verticalLayout.addWidget(self.expand_other_options_button) + + self.spacer_content_to_save = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) + + self.verticalLayout.addItem(self.spacer_content_to_save) + + self.line_options_save = QFrame(self.centralwidget) + self.line_options_save.setObjectName(u"line_options_save") + self.line_options_save.setFrameShape(QFrame.HLine) + self.line_options_save.setFrameShadow(QFrame.Sunken) + + self.verticalLayout.addWidget(self.line_options_save) + + self.save_to_label = QLabel(self.centralwidget) + self.save_to_label.setObjectName(u"save_to_label") + + self.verticalLayout.addWidget(self.save_to_label) + + self.save_to_box = QLineEdit(self.centralwidget) + self.save_to_box.setObjectName(u"save_to_box") + self.save_to_box.setMinimumSize(QSize(0, 30)) + + self.verticalLayout.addWidget(self.save_to_box) + + self.save_button = QPushButton(self.centralwidget) + self.save_button.setObjectName(u"save_button") + self.save_button.setMinimumSize(QSize(0, 50)) + self.save_button.setStyleSheet(u"font: 20pt \"Segoe UI Black\";") + + self.verticalLayout.addWidget(self.save_button) + MainWindow.setCentralWidget(self.centralwidget) self.retranslateUi(MainWindow) @@ -32,5 +306,29 @@ class Ui_MainWindow(object): def retranslateUi(self, MainWindow): MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"D0CXUN7R4C3", None)) + self.docxuntracelabel.setText(QCoreApplication.translate("MainWindow", u"D0CXUN7R4C3", None)) + self.path_to_original_box.setPlaceholderText(QCoreApplication.translate("MainWindow", u"Path to document", None)) + self.open_document_button.setText(QCoreApplication.translate("MainWindow", u"Open", None)) + self.authors_label.setText(QCoreApplication.translate("MainWindow", u"Authors", None)) + self.creator_label.setText(QCoreApplication.translate("MainWindow", u"Creator", None)) + self.creator_box.setPlaceholderText(QCoreApplication.translate("MainWindow", u"BarsTiger", None)) + self.last_modified_by_label.setText(QCoreApplication.translate("MainWindow", u"Last modified by", None)) + self.last_modified_by_box.setPlaceholderText(QCoreApplication.translate("MainWindow", u"BarsTiger", None)) + self.dateandtime_label.setText(QCoreApplication.translate("MainWindow", u"Date and time (in global time)", None)) + self.dateandtime_created_label.setText(QCoreApplication.translate("MainWindow", u"Created", None)) + self.dateandtime_edited_label.setText(QCoreApplication.translate("MainWindow", u"Last edited", None)) + self.other_label.setText(QCoreApplication.translate("MainWindow", u"Other", None)) + self.revision_label.setText(QCoreApplication.translate("MainWindow", u"Revision", None)) + self.revision_box.setPlaceholderText(QCoreApplication.translate("MainWindow", u"0", None)) + self.template_label.setText(QCoreApplication.translate("MainWindow", u"Template", None)) + self.template_box.setPlaceholderText(QCoreApplication.translate("MainWindow", u"Normal.dotm", None)) + self.pages_words_symbols_label.setText(QCoreApplication.translate("MainWindow", u"Pages - Words - Symbols - Lines - Paragraphs", None)) + self.application_name_label.setText(QCoreApplication.translate("MainWindow", u"Application", None)) + self.application_name_box.setPlaceholderText(QCoreApplication.translate("MainWindow", u"Microsoft Office Word", None)) + self.custom_edit_time_label.setText(QCoreApplication.translate("MainWindow", u"Custom edit time (min)", None)) + self.expand_other_options_button.setText(QCoreApplication.translate("MainWindow", u"Other options", None)) + self.save_to_label.setText(QCoreApplication.translate("MainWindow", u"Save to", None)) + self.save_to_box.setPlaceholderText(QCoreApplication.translate("MainWindow", u"Path to new document", None)) + self.save_button.setText(QCoreApplication.translate("MainWindow", u"Save", None)) # retranslateUi diff --git a/gui/gui.ui b/gui/gui.ui index c3bcd61..11df015 100644 --- a/gui/gui.ui +++ b/gui/gui.ui @@ -6,8 +6,8 @@ 0 0 - 800 - 460 + 400 + 570 @@ -17,7 +17,466 @@ :/img/img/icon.ico:/img/img/icon.ico - + + + + + + + + + + 0 + 0 + + + + font: 87 30pt "Segoe UI Black"; + + + D0CXUN7R4C3 + + + Qt::AlignCenter + + + + + + + Qt::Horizontal + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 30 + + + + Path to document + + + + + + + + 80 + 30 + + + + Open + + + + + + + + + + Qt::Horizontal + + + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Authors + + + + + + + Creator + + + + + + + + 0 + 30 + + + + BarsTiger + + + + + + + Last modified by + + + + + + + + 0 + 30 + + + + BarsTiger + + + + + + + + + + Qt::Horizontal + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Date and time (in global time) + + + + + + + Created + + + + + + + + 0 + 30 + + + + true + + + + + + + Last edited + + + + + + + + 0 + 30 + + + + true + + + + + + + + + + Qt::Horizontal + + + + + + + + 16777215 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Other + + + + + + + Revision + + + + + + + + 0 + 30 + + + + 0 + + + + + + + Template + + + + + + + + 0 + 30 + + + + Normal.dotm + + + + + + + Pages - Words - Symbols - Lines - Paragraphs + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + + + + + + + + + + + + Application + + + + + + + + 0 + 30 + + + + Microsoft Office Word + + + + + + + Custom edit time (min) + + + + + + + + 0 + 30 + + + + -2147483647 + + + 2147483647 + + + + + + + + + + + 0 + 30 + + + + Other options + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + + + + + Save to + + + + + + + + 0 + 30 + + + + Path to new document + + + + + + + + 0 + 50 + + + + font: 20pt "Segoe UI Black"; + + + Save + + + + + diff --git a/gui/modules/core/blur.py b/gui/modules/core/blur.py deleted file mode 100644 index 44af303..0000000 --- a/gui/modules/core/blur.py +++ /dev/null @@ -1,133 +0,0 @@ -# source: https://github.com/Opticos/GWSL-Source/blob/master/blur.py, -# https://www.cnblogs.com/zhiyiYo/p/14659981.html , -# https://github.com/ifwe/digsby/blob/master/digsby/src/gui/vista.py -import platform -import ctypes - - -if platform.system() == 'Windows': - from ctypes.wintypes import DWORD, BOOL, HRGN, HWND - - user32 = ctypes.windll.user32 - dwm = ctypes.windll.dwmapi - - - class ACCENTPOLICY(ctypes.Structure): - _fields_ = [ - ("AccentState", ctypes.c_uint), - ("AccentFlags", ctypes.c_uint), - ("GradientColor", ctypes.c_uint), - ("AnimationId", ctypes.c_uint) - ] - - - class WINDOWCOMPOSITIONATTRIBDATA(ctypes.Structure): - _fields_ = [ - ("Attribute", ctypes.c_int), - ("Data", ctypes.POINTER(ctypes.c_int)), - ("SizeOfData", ctypes.c_size_t) - ] - - - class DWM_BLURBEHIND(ctypes.Structure): - _fields_ = [ - ('dwFlags', DWORD), - ('fEnable', BOOL), - ('hRgnBlur', HRGN), - ('fTransitionOnMaximized', BOOL) - ] - - - class MARGINS(ctypes.Structure): - _fields_ = [("cxLeftWidth", ctypes.c_int), - ("cxRightWidth", ctypes.c_int), - ("cyTopHeight", ctypes.c_int), - ("cyBottomHeight", ctypes.c_int) - ] - - - SetWindowCompositionAttribute = user32.SetWindowCompositionAttribute - SetWindowCompositionAttribute.argtypes = (HWND, WINDOWCOMPOSITIONATTRIBDATA) - SetWindowCompositionAttribute.restype = ctypes.c_int - - -def ExtendFrameIntoClientArea(hwnd): - margins = MARGINS(-1, -1, -1, -1) - dwm.DwmExtendFrameIntoClientArea(hwnd, ctypes.byref(margins)) - - -def Win7Blur(hwnd, Acrylic): - if not Acrylic: - DWM_BB_ENABLE = 0x01 - bb = DWM_BLURBEHIND() - bb.dwFlags = DWM_BB_ENABLE - bb.fEnable = 1 - bb.hRgnBlur = 1 - dwm.DwmEnableBlurBehindWindow(hwnd, ctypes.byref(bb)) - else: - ExtendFrameIntoClientArea(hwnd) - - -def HEXtoRGBAint(HEX: str): - alpha = HEX[7:] - blue = HEX[5:7] - green = HEX[3:5] - red = HEX[1:3] - - gradient_color = alpha + blue + green + red - return int(gradient_color, base=16) - - -def blur(hwnd, hex_color=False, acrylic=False, dark=False): - accent = ACCENTPOLICY() - accent.AccentState = 3 # Default window Blur #ACCENT_ENABLE_BLURBEHIND - - gradient_color = 0 - - if hex_color: - gradient_color = HEXtoRGBAint(hex_color) - accent.AccentFlags = 2 # Window Blur With Accent Color #ACCENT_ENABLE_TRANSPARENTGRADIENT - - if acrylic: - accent.AccentState = 4 # UWP but LAG #ACCENT_ENABLE_ACRYLICBLURBEHIND - if not hex_color: # UWP without color is translucent - accent.AccentFlags = 2 - gradient_color = HEXtoRGBAint('#12121240') # placeholder color - - accent.GradientColor = gradient_color - - data = WINDOWCOMPOSITIONATTRIBDATA() - data.Attribute = 19 # WCA_ACCENT_POLICY - data.SizeOfData = ctypes.sizeof(accent) - data.Data = ctypes.cast(ctypes.pointer(accent), ctypes.POINTER(ctypes.c_int)) - - SetWindowCompositionAttribute(int(hwnd), data) - - if dark: - data.Attribute = 26 # WCA_USEDARKMODECOLORS - SetWindowCompositionAttribute(int(hwnd), data) - - -def BlurLinux(WID): # may not work in all distros (working in Deepin) - import os - - c = "xprop -f _KDE_NET_WM_BLUR_BEHIND_REGION 32c -set _KDE_NET_WM_BLUR_BEHIND_REGION 0 -id " + str(WID) - os.system(c) - - -def GlobalBlur(hwnd, hex_color=False, acrylic=False, dark=False): - release = platform.release() - system = platform.system() - - if system == 'Windows': - if release == 'Vista': - Win7Blur(hwnd, acrylic) - else: - release = int(float(release)) - if release == 10 or release == 8 or release == 11: - blur(hwnd, hex_color, acrylic, dark) - else: - Win7Blur(hwnd, acrylic) - - if system == 'Linux': - BlurLinux(hwnd) diff --git a/gui/modules/document_loader/__init__.py b/gui/modules/document_loader/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gui/modules/document_loader/from_gui.py b/gui/modules/document_loader/from_gui.py new file mode 100644 index 0000000..55b447e --- /dev/null +++ b/gui/modules/document_loader/from_gui.py @@ -0,0 +1,49 @@ +import time +from gui.gui import Ui_MainWindow +from modules.document.document_properties import DocumentProps +from modules.helpers import xml +import datetime +from ezzthread import threaded + + +@threaded +def update_button(ui: Ui_MainWindow): + ui.save_button.setText('Success') + time.sleep(3) + ui.save_button.setText('Save') + + +def write_document(ui: Ui_MainWindow, document_props: DocumentProps): + if not document_props.parsed_: + return + + xml.set_value(document_props.app_xml, '//Application', ui.application_name_box.text()) + xml.set_value(document_props.app_xml, '//Paragraphs', ui.paragraphs_box.value()) + xml.set_value(document_props.app_xml, '//Lines', ui.lines_box.value()) + xml.set_value(document_props.app_xml, '//Characters', ui.symbols_box.value()) + xml.set_value(document_props.app_xml, '//Words', ui.words_box.value()) + xml.set_value(document_props.app_xml, '//Pages', ui.pages_box.value()) + xml.set_value(document_props.app_xml, '//TotalTime', ui.custom_edit_time_box.value()) + xml.set_value(document_props.app_xml, '//Template', ui.template_box.text()) + xml.set_value( + document_props.core_xml, 'dcterms:modified', + datetime.datetime.combine(ui.dateandtime_edited_box.date().toPython(), + ui.dateandtime_edited_box.time().toPython() + ).strftime('%Y-%m-%dT%H:%M:%SZ') + ) + xml.set_value( + document_props.core_xml, 'dcterms:created', + datetime.datetime.combine(ui.dateandtime_created_box.date().toPython(), + ui.dateandtime_created_box.time().toPython() + ).strftime('%Y-%m-%dT%H:%M:%SZ') + ) + xml.set_value(document_props.core_xml, 'cp:revision', ui.revision_box.text()) + xml.set_value(document_props.core_xml, 'cp:lastModifiedBy', ui.last_modified_by_box.text()) + xml.set_value(document_props.core_xml, 'dc:creator', ui.creator_box.text()) + + document_props.core_xml.write(document_props.extracted_document.core) + document_props.app_xml.write(document_props.extracted_document.app) + + document_props.extracted_document.pack(ui.save_to_box.text()) + + update_button(ui) diff --git a/gui/modules/document_loader/to_gui.py b/gui/modules/document_loader/to_gui.py new file mode 100644 index 0000000..494ff74 --- /dev/null +++ b/gui/modules/document_loader/to_gui.py @@ -0,0 +1,35 @@ +from PySide6 import QtCore +from gui.gui import Ui_MainWindow +from modules.document.document_properties import DocumentProps + + +def fill_gui(ui: Ui_MainWindow, document_props: DocumentProps): + if not document_props.parsed_: + return + + ui.remove_objects.append(document_props.extracted_document) + + ui.save_to_box.setText(ui.path_to_original_box.text()) + + ui.creator_box.setText(document_props.creator) + ui.last_modified_by_box.setText(document_props.last_modified_by) + + ui.dateandtime_created_box.setDateTime( + QtCore.QDateTime(QtCore.QDate(document_props.created.date()), QtCore.QTime(document_props.created.time())) + ) + ui.dateandtime_edited_box.setDateTime( + QtCore.QDateTime(QtCore.QDate(document_props.modified.date()), QtCore.QTime(document_props.modified.time())) + ) + + ui.revision_box.setText(document_props.revision) + ui.template_box.setText(document_props.template) + ui.pages_box.setValue(document_props.pages) + ui.words_box.setValue(document_props.words) + ui.symbols_box.setValue(document_props.characters) + ui.lines_box.setValue(document_props.lines) + ui.paragraphs_box.setValue(document_props.paragraphs) + ui.application_name_box.setText(document_props.application) + ui.custom_edit_time_box.setValue(document_props.total_time) + + ui.document = document_props + ui.save_button.setEnabled(True) diff --git a/gui/modules/gui_helpers/__init__.py b/gui/modules/gui_helpers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gui/modules/gui_helpers/other_options.py b/gui/modules/gui_helpers/other_options.py new file mode 100644 index 0000000..d3425f1 --- /dev/null +++ b/gui/modules/gui_helpers/other_options.py @@ -0,0 +1,16 @@ +from gui.gui import Ui_MainWindow +from PySide6 import QtCore + + +def on_other_clicked(ui: Ui_MainWindow): + ui.expand_other_options_button.hide() + + Ui_MainWindow.other_animation = QtCore.QPropertyAnimation(ui.other_properties_widget, b"maximumHeight") + Ui_MainWindow.other_animation.setDuration(300) + + Ui_MainWindow.other_animation.setStartValue(0) + Ui_MainWindow.other_animation.setEndValue(500) + + Ui_MainWindow.other_animation.setEasingCurve(QtCore.QEasingCurve.InOutQuart) + + Ui_MainWindow.other_animation.start() diff --git a/gui/modules/initialize/handlers.py b/gui/modules/initialize/handlers.py new file mode 100644 index 0000000..4ff5a88 --- /dev/null +++ b/gui/modules/initialize/handlers.py @@ -0,0 +1,50 @@ +from gui.gui import Ui_MainWindow +from modules.document.document_file import ExtractedDocument +from modules.document.document_properties import DocumentProps +from gui.modules.document_loader import to_gui, from_gui +from PySide6 import QtWidgets +from gui.modules.gui_helpers import other_options +from PySide6.QtWidgets import QFileDialog +from modules.time_tools import time_diff + + +def remobjects(ui: Ui_MainWindow): + for obj in ui.remove_objects: + try: + obj.remove() + except Exception as e: + assert e + + +def register_handlers(ui: Ui_MainWindow, MainWindow: QtWidgets.QMainWindow): + ui.path_to_original_box.textChanged.connect( + lambda: to_gui.fill_gui(ui, DocumentProps(ExtractedDocument(ui.path_to_original_box.text()))) + ) + MainWindow.closeEvent = lambda _: (remobjects(ui)) + ui.expand_other_options_button.clicked.connect( + lambda: other_options.on_other_clicked(ui) + ) + ui.creator_box.textEdited.connect( + lambda: ui.last_modified_by_box.setText(ui.creator_box.text()) + ) + ui.save_button.clicked.connect( + lambda: from_gui.write_document(ui, ui.document) + ) + ui.open_document_button.clicked.connect( + lambda: ui.path_to_original_box.setText( + QFileDialog.getOpenFileName(None, caption='Choose file to edit')[0] + ) + ) + + ui.dateandtime_created_box.dateTimeChanged.connect( + lambda: ui.custom_edit_time_box.setValue(time_diff.compute_time_diff( + ui.dateandtime_created_box.date().toPython(), ui.dateandtime_created_box.time().toPython(), + ui.dateandtime_edited_box.date().toPython(), ui.dateandtime_edited_box.time().toPython() + )) + ) + ui.dateandtime_edited_box.dateTimeChanged.connect( + lambda: ui.custom_edit_time_box.setValue(time_diff.compute_time_diff( + ui.dateandtime_created_box.date().toPython(), ui.dateandtime_created_box.time().toPython(), + ui.dateandtime_edited_box.date().toPython(), ui.dateandtime_edited_box.time().toPython() + )) + ) diff --git a/gui/modules/initialize/setup_ui.py b/gui/modules/initialize/setup_ui.py index e8f18c9..b1548fb 100644 --- a/gui/modules/initialize/setup_ui.py +++ b/gui/modules/initialize/setup_ui.py @@ -1,8 +1,36 @@ -from PySide6.QtWidgets import QMainWindow +import os.path +import sys +from PySide6.QtWidgets import QCalendarWidget from gui.gui import Ui_MainWindow -from gui.modules.core.blur import GlobalBlur from gui.modules.initialize import styles +from gui.modules.initialize.handlers import register_handlers +from PySide6 import QtWidgets -def on_load(ui: Ui_MainWindow, MainWindow: QMainWindow): - pass +def on_load(ui: Ui_MainWindow, MainWindow: QtWidgets.QMainWindow): + ui.dateandtime_created_box.calendarWidget().setHorizontalHeaderFormat( + QCalendarWidget.HorizontalHeaderFormat.NoHorizontalHeader + ) + ui.dateandtime_created_box.calendarWidget().setVerticalHeaderFormat( + QCalendarWidget.VerticalHeaderFormat.NoVerticalHeader + ) + ui.dateandtime_edited_box.calendarWidget().setHorizontalHeaderFormat( + QCalendarWidget.HorizontalHeaderFormat.NoHorizontalHeader + ) + ui.dateandtime_edited_box.calendarWidget().setVerticalHeaderFormat( + QCalendarWidget.VerticalHeaderFormat.NoVerticalHeader + ) + + if sys.executable == 'D0CXUN7R4C31337.exe' or '1337' in sys.argv: + ui.centralwidget.setStyleSheet(styles.centralwidget_h4ck3r) + else: + ui.centralwidget.setStyleSheet(styles.centralwidget_g) + + register_handlers(ui, MainWindow) + ui.remove_objects = list() + ui.save_button.setEnabled(False) + + for arg in sys.argv: + if arg.split('.')[-1] in ['docx', 'pptx', 'xlsx'] and os.path.isfile(arg): + ui.path_to_original_box.setText(arg) + break diff --git a/gui/modules/initialize/styles.py b/gui/modules/initialize/styles.py index 5210c8a..4448403 100644 --- a/gui/modules/initialize/styles.py +++ b/gui/modules/initialize/styles.py @@ -295,8 +295,26 @@ QProgressBar::chunk { background-color: rgba(132, 132, 132, 0.5); border-radius: 5px; } -""" +QDateTimeEdit +{ + border-width: 1px; + border-radius: 5px; + border-style: solid; + border-color: rgba(48, 48, 48, 0); + background-color: rgba(36, 36, 36, 0); + font: 10pt "Segoe UI"; +} + +QDateTimeEdit::drop-down { + border-width: 1px; + border-radius: 5px; + border-style: solid; + border-color: rgba(48, 48, 48, 0); + background-color: rgba(36, 36, 36, 0); + font: 10pt "Segoe UI"; +} +""" centralwidget_g = """ QWidget { @@ -595,4 +613,314 @@ QProgressBar::chunk { background-color: #848484; border-radius: 5px; } + +QDateTimeEdit +{ + border-width: 1px; + border-radius: 5px; + border-style: solid; + border-color: #303030; + background-color: #242424; + font: 10pt "Segoe UI"; +} + +QDateTimeEdit::drop-down { + border-width: 1px; + border-radius: 5px; + border-style: solid; + border-color: #303030; + background-color: #242424; + font: 10pt "Segoe UI"; +} +""" + +centralwidget_h4ck3r = """ +QWidget { + background-color: black; + border-color: green; + color: green; + font: 10pt "Segoe UI"; +} + +QScrollBar:vertical, +QScrollBar:horizontal { + background: #1e1e1e; +} +QScrollBar::handle:vertical, +QScrollBar::handle:horizontal { + background-color: black; +} +QScrollBar::handle:vertical:hover, +QScrollBar::handle:vertical:pressed, +QScrollBar::handle:horizontal:hover, +QScrollBar::handle:horizontal:pressed { + background-color: #080808; +} +QScrollBar::sub-line:vertical, +QScrollBar::add-line:vertical, +QScrollBar::up-arrow:vertical, +QScrollBar::down-arrow:vertical { + height: 0px; +} +QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical, +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical, +QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal, +QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { + background: none; +} + +QPushButton { + color: green; + border-width: 1px; + border-style: solid; + background-color: #080808; +} +QPushButton:hover { + border-width: 2px; + background-color: #323232; +} +QPushButton:pressed { + background-color: #262728; +} +QPushButton:disabled { + background-color: #434343; + border-color: #0000; +} + +QLineEdit, QTextBrowser, QPlainTextEdit, QTextEdit { + border-width: 1px; + border-style: solid; + background-color: #080808; + font: 10pt "Segoe UI"; +} + +QListWidget, QListView, QTreeView { + border-width: 1px; + border-style: solid; + background-color: #080808; + font: 10pt "Segoe UI"; +} +QListWidget:item, QListView:item, QTreeView:item { + selection-color: green; +} +QListWidget:item:hover, QListView:item:hover, QTreeView:item:hover { + background-color: #00cc03; +} +QListWidget:item:selected, QListView:item:selected, QTreeView:item:selected { + background-color: #777777; +} + +QTreeView::branch:has-children:closed { + image: url(":/img/img/down.svg"); +} + +QTreeView::branch:has-children:open { + image: url(":/img/img/up.svg"); +} + +QComboBox +{ + border-width: 1px; + border-style: solid; + background-color: #080808; + color: green; +} +QComboBox::disabled +{ + background-color: #434343; + color: #656565; + border-color: #434343; +} +QComboBox:hover +{ + background-color: #323232; +} +QComboBox:on +{ + background-color: #434343; +} +QComboBox QAbstractItemView +{ + background-color: #434343; + color: green; + selection-background-color: #777777; + selection-color: white; + outline: 0; +} +QComboBox::drop-down +{ + subcontrol-origin: padding; + subcontrol-position: top right; + border-radius: 6px; +} + +QTabBar::tab +{ + background-color: #080808; + color: green; + border-style: solid; + border-width: 1px; + border-top-left-radius: 3px; + border-top-right-radius: 3px; + padding: 5px; +} +QTabBar::tab:disabled +{ + background-color: #656565; + color: green; +} +QTabWidget::pane +{ + background-color: #a0a0a0; + color: green; + border: 1px solid; + border-color: green; +} +QTabBar::tab:selected +{ + background-color: #080808; + color: green; + border-style: solid; + border-width: 1px; + border-top-left-radius: 3px; + border-top-right-radius: 3px; + padding: 5px; +} +QTabBar::tab:selected:disabled +{ + background-color: #080808; + color: green; +} +QTabBar::tab:!selected +{ + background-color: #080808; +} +QTabBar::tab:!selected:hover +{ + background-color: #323232; +} +QTabBar::tab:top:!selected +{ + margin-top: 3px; +} +QTabBar::tab:bottom:!selected +{ + margin-bottom: 3px; +} +QTabBar::tab:top, QTabBar::tab:bottom +{ + min-width: 8ex; + margin-right: -1px; + padding: 5px 10px 5px 10px; +} +QTabBar::tab:top:selected +{ + border-bottom-color: none; +} +QTabBar::tab:bottom:selected +{ + border-top-color: none; +} +QTabBar::tab:top:last, QTabBar::tab:bottom:last, +QTabBar::tab:top:only-one, QTabBar::tab:bottom:only-one +{ + margin-right: 0; +} +QTabBar::tab:left:!selected +{ + margin-right: 3px; +} +QTabBar::tab:right:!selected +{ + margin-left: 3px; +} +QTabBar::tab:left, QTabBar::tab:right +{ + min-height: 8ex; + margin-bottom: -1px; + padding: 10px 5px 10px 5px; +} +QTabBar::tab:left:selected +{ + border-left-color: none; +} +QTabBar::tab:right:selected +{ + border-right-color: none; +} +QTabBar::tab:left:last, QTabBar::tab:right:last, +QTabBar::tab:left:only-one, QTabBar::tab:right:only-one +{ + margin-bottom: 0; +} + +QSpinBox { + border-width: 1px; + border-radius: 5px; + border-style: solid; + background-color: #242424; + font: 10pt "Segoe UI"; +} +QSpinBox::up-button { + border: none; + background: none; +} +QSpinBox::down-button { + border: none; + background: none; +} + +QToolBox::tab { + border-style: solid; + border-width: 1px; + border-radius: 5px; +} + +QSlider::groove:horizontal { + border-radius: 1px; + height: 10px; + margin: 0px; + background-color: #242424; +} +QSlider::groove:horizontal:hover { + background-color: #303030; +} +QSlider::handle:horizontal { + background-color: white; + border: none; + width: 5px; + border-radius: 40px; +} +QSlider::handle:horizontal:hover { + background-color: #bfbfbf; +} +QSlider::handle:horizontal:pressed { + background-color: #bfbfbf; +} + +QProgressBar { + text-align: center; + color: #00cc00; + border-width: 1px; + border-style: inset; + background-color: #080808; +} +QProgressBar::chunk { + background-color: green; +} + +QDateTimeEdit +{ + border-width: 1px; + border-style: solid; + border-color: green; + font: 10pt "Segoe UI"; +} + +QDateTimeEdit::drop-down { + border-width: 1px; + border-style: solid; + border-color: green; + font: 10pt "Segoe UI"; +} """ diff --git a/modules/document/__init__.py b/modules/document/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/document/document_file.py b/modules/document/document_file.py new file mode 100644 index 0000000..af316e8 --- /dev/null +++ b/modules/document/document_file.py @@ -0,0 +1,30 @@ +import os.path +import tempfile +import zipfile +import shutil + + +class ExtractedDocument: + def __init__(self, path: str): + self.documentroot = None + self.app = None + self.core = None + if zipfile.is_zipfile(path): + self.documentroot = tempfile.mkdtemp() + zipfile.ZipFile(path).extractall(self.documentroot) + self.app = os.path.join(self.documentroot, 'docProps', 'app.xml') + self.core = os.path.join(self.documentroot, 'docProps', 'core.xml') + + def pack(self, path): + with zipfile.ZipFile(path, "w", compresslevel=9, compression=zipfile.ZIP_DEFLATED) as z: + for root, dirs, files in os.walk(self.documentroot): + for file in files: + z.write(os.path.join(root, file), + os.path.relpath(os.path.join(root, file), + self.documentroot)) + + def remove(self): + try: + shutil.rmtree(self.documentroot, True) + except Exception as e: + print(f'Error while removing {self.documentroot}: {e}, remove it manually if you want') diff --git a/modules/document/document_properties.py b/modules/document/document_properties.py new file mode 100644 index 0000000..b8f6f5d --- /dev/null +++ b/modules/document/document_properties.py @@ -0,0 +1,36 @@ +import os.path +import lxml +from lxml import etree +from modules.document.document_file import ExtractedDocument +from modules.helpers import xml +from modules.helpers.convert import Int +from datetime import datetime + + +class DocumentProps: + def __init__(self, extracted_document: ExtractedDocument): + if not extracted_document.documentroot or not os.path.isdir(extracted_document.documentroot): + self.parsed_ = False + return + + self.parsed_ = True + + core_xml = etree.parse(extracted_document.core) + app_xml = etree.parse(extracted_document.app) + + self.extracted_document = extracted_document + self.application = xml.get_value(app_xml, '//Application') + self.paragraphs = Int(xml.get_value(app_xml, '//Paragraphs')) + self.lines = Int(xml.get_value(app_xml, '//Lines')) + self.characters = Int(xml.get_value(app_xml, '//Characters')) + self.words = Int(xml.get_value(app_xml, '//Words')) + self.pages = Int(xml.get_value(app_xml, '//Pages')) + self.total_time = Int(xml.get_value(app_xml, '//TotalTime')) + self.template = xml.get_value(app_xml, '//Template') + self.modified = datetime.strptime(xml.get_value(core_xml, 'dcterms:modified'), '%Y-%m-%dT%H:%M:%SZ') + self.created = datetime.strptime(xml.get_value(core_xml, 'dcterms:created'), '%Y-%m-%dT%H:%M:%SZ') + self.revision = xml.get_value(core_xml, 'cp:revision') + self.last_modified_by = xml.get_value(core_xml, 'cp:lastModifiedBy') + self.creator = xml.get_value(core_xml, 'dc:creator') + self.core_xml = core_xml + self.app_xml = app_xml diff --git a/modules/helpers/__init__.py b/modules/helpers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/helpers/convert.py b/modules/helpers/convert.py new file mode 100644 index 0000000..f109ada --- /dev/null +++ b/modules/helpers/convert.py @@ -0,0 +1,6 @@ +def Int(s: str) -> int | None: + try: + return int(s) + except Exception as e: + assert e + return 0 diff --git a/modules/helpers/xml.py b/modules/helpers/xml.py new file mode 100644 index 0000000..763abae --- /dev/null +++ b/modules/helpers/xml.py @@ -0,0 +1,22 @@ +namespaces = { + "cp": "http://schemas.openxmlformats.org/package/2006/metadata/core-properties", + "dc": "http://purl.org/dc/elements/1.1/", + "dcterms": "http://purl.org/dc/terms/", + "dcmitype": "http://purl.org/dc/dcmitype/", + "xsi": "http://www.w3.org/2001/XMLSchema-instance", + "vt": "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes", + "": "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" +} + + +def get_value(parsed, name): + return str(parsed.findall(name, namespaces)[0].text) \ + if parsed.findall(name, namespaces) else None + + +def set_value(parsed, name, value): + if value: + parsed.findall(name, namespaces)[0].text = str(value) + else: + parsed.findall(name, namespaces)[0].getparent().remove(parsed.findall(name, namespaces)[0]) \ + if parsed.findall(name, namespaces) else None diff --git a/modules/time_tools/__init__.py b/modules/time_tools/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/time_tools/time_diff.py b/modules/time_tools/time_diff.py new file mode 100644 index 0000000..d7ed278 --- /dev/null +++ b/modules/time_tools/time_diff.py @@ -0,0 +1,9 @@ +import datetime + + +def compute_time_diff(date_first, time_first, + date_second, time_second): + dt1 = datetime.datetime.combine(date_first, time_first) + dt2 = datetime.datetime.combine(date_second, time_second) + + return int((max(dt1, dt2) - min(dt1, dt2)).total_seconds() / 60) diff --git a/requirements.txt b/requirements.txt index d537b5c..d1d1d75 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,5 @@ wheel PySide6 pyinstaller +lxml +ezzthread