texcleaner 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- texcleaner-0.3.0/LICENSE +32 -0
- texcleaner-0.3.0/PKG-INFO +94 -0
- texcleaner-0.3.0/README.md +78 -0
- texcleaner-0.3.0/pyproject.toml +33 -0
- texcleaner-0.3.0/setup.cfg +4 -0
- texcleaner-0.3.0/texclean/__init__.py +24 -0
- texcleaner-0.3.0/texclean/__main__.py +4 -0
- texcleaner-0.3.0/texclean/app.py +308 -0
- texcleaner-0.3.0/texclean/scripts/changes/0-text.tex +225 -0
- texcleaner-0.3.0/texclean/scripts/changes/1-text.tex +216 -0
- texcleaner-0.3.0/texclean/scripts/changes/pyMergeChanges.py +305 -0
- texcleaner-0.3.0/texclean/scripts/trackchanges-py3/0readme-acceptchanges3.txt +10 -0
- texcleaner-0.3.0/texclean/scripts/trackchanges-py3/0readme-arxiv_latex_cleaner +19 -0
- texcleaner-0.3.0/texclean/scripts/trackchanges-py3/AcceptChanges3/__init__.py +1 -0
- texcleaner-0.3.0/texclean/scripts/trackchanges-py3/AcceptChanges3/__pycache__/__init__.cpython-312.pyc +0 -0
- texcleaner-0.3.0/texclean/scripts/trackchanges-py3/AcceptChanges3/__pycache__/consoleoutput.cpython-312.pyc +0 -0
- texcleaner-0.3.0/texclean/scripts/trackchanges-py3/AcceptChanges3/__pycache__/linesegment.cpython-312.pyc +0 -0
- texcleaner-0.3.0/texclean/scripts/trackchanges-py3/AcceptChanges3/consoleoutput.py +225 -0
- texcleaner-0.3.0/texclean/scripts/trackchanges-py3/AcceptChanges3/linesegment.py +54 -0
- texcleaner-0.3.0/texclean/scripts/trackchanges-py3/__pycache__/acceptchanges3.cpython-312.pyc +0 -0
- texcleaner-0.3.0/texclean/scripts/trackchanges-py3/acceptAll.sh +24 -0
- texcleaner-0.3.0/texclean/scripts/trackchanges-py3/acceptchanges3.py +353 -0
- texcleaner-0.3.0/texclean/version.py +12 -0
- texcleaner-0.3.0/texclean/wrapper.py +282 -0
- texcleaner-0.3.0/texcleaner.egg-info/PKG-INFO +94 -0
- texcleaner-0.3.0/texcleaner.egg-info/SOURCES.txt +28 -0
- texcleaner-0.3.0/texcleaner.egg-info/dependency_links.txt +1 -0
- texcleaner-0.3.0/texcleaner.egg-info/entry_points.txt +2 -0
- texcleaner-0.3.0/texcleaner.egg-info/requires.txt +6 -0
- texcleaner-0.3.0/texcleaner.egg-info/top_level.txt +1 -0
texcleaner-0.3.0/LICENSE
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
GNU GENERAL PUBLIC LICENSE
|
|
2
|
+
Version 3, 29 June 2007
|
|
3
|
+
|
|
4
|
+
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
|
5
|
+
Everyone is permitted to copy and distribute verbatim copies
|
|
6
|
+
of this license document, but changing it is not allowed.
|
|
7
|
+
|
|
8
|
+
PREAMBLE
|
|
9
|
+
|
|
10
|
+
The GNU General Public License is a free, copyleft license for
|
|
11
|
+
software and other kinds of works.
|
|
12
|
+
|
|
13
|
+
The licenses for most software and other practical works are designed
|
|
14
|
+
to take away your freedom to share and change the works. By contrast,
|
|
15
|
+
the GNU General Public License is intended to guarantee your freedom to
|
|
16
|
+
share and change all versions of a program--to make sure it remains free
|
|
17
|
+
software for all its users.
|
|
18
|
+
|
|
19
|
+
TERMS AND CONDITIONS
|
|
20
|
+
|
|
21
|
+
This program is free software: you can redistribute it and/or modify
|
|
22
|
+
it under the terms of the GNU General Public License as published by
|
|
23
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
24
|
+
(at your option) any later version.
|
|
25
|
+
|
|
26
|
+
This program is distributed in the hope that it will be useful,
|
|
27
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
28
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
29
|
+
GNU General Public License for more details.
|
|
30
|
+
|
|
31
|
+
You should have received a copy of the GNU General Public License
|
|
32
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: texcleaner
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: A GUI front-end for cleaning LaTeX track changes
|
|
5
|
+
Author: Dan Shim
|
|
6
|
+
License-Expression: GPL-3.0-or-later
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: arxiv-latex-cleaner
|
|
11
|
+
Provides-Extra: dev
|
|
12
|
+
Requires-Dist: build; extra == "dev"
|
|
13
|
+
Requires-Dist: twine; extra == "dev"
|
|
14
|
+
Requires-Dist: pytest; extra == "dev"
|
|
15
|
+
Dynamic: license-file
|
|
16
|
+
|
|
17
|
+
# TeXClean
|
|
18
|
+
|
|
19
|
+
A GUI front-end for cleaning LaTeX documents of track changes markup.
|
|
20
|
+
|
|
21
|
+
## Features
|
|
22
|
+
|
|
23
|
+
TeXClean supports cleaning track changes from three different LaTeX packages:
|
|
24
|
+
|
|
25
|
+
1. **TrackChanges** - For documents using `trackchanges.sty`
|
|
26
|
+
2. **Changes** - For documents using `changes.sty`
|
|
27
|
+
3. **arXiv** - For preparing documents for arXiv submission
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
### From PyPI (Recommended)
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install texclean
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
After installation, you can run the application with:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
texclean
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### From Source
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
git clone https://github.com/yourusername/texclean.git
|
|
47
|
+
cd texclean
|
|
48
|
+
pip install -e .
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Requirements
|
|
52
|
+
|
|
53
|
+
- Python 3.8+
|
|
54
|
+
- `arxiv-latex-cleaner` (installed automatically with pip)
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
|
|
58
|
+
1. Run the application:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
texclean
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Or if running from source:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
python -m texclean.app
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
2. Select your input file or folder:
|
|
71
|
+
- For **TrackChanges** and **Changes**: Select a `.tex` file
|
|
72
|
+
- For **arXiv**: Select the project folder containing your LaTeX files
|
|
73
|
+
|
|
74
|
+
3. Choose the cleaning option:
|
|
75
|
+
- **Remove TrackChanges**: Accepts all changes and removes annotations from `trackchanges.sty`
|
|
76
|
+
- **Remove Changes**: Accepts all changes from `changes.sty`
|
|
77
|
+
- **Clean for arXiv**: Removes comments, resizes images, and organizes files for submission
|
|
78
|
+
|
|
79
|
+
4. Click **Clean** to process the file
|
|
80
|
+
|
|
81
|
+
## Output
|
|
82
|
+
|
|
83
|
+
- **TrackChanges/Changes**: Creates a new file with `_no_track` or `_cleaned` suffix
|
|
84
|
+
- **arXiv**: Creates a new folder with `_arXiv` suffix
|
|
85
|
+
|
|
86
|
+
## License
|
|
87
|
+
|
|
88
|
+
This project is licensed under the GNU General Public License v3.0 (GPL-3.0).
|
|
89
|
+
|
|
90
|
+
## Acknowledgments
|
|
91
|
+
|
|
92
|
+
- `acceptchanges3.py` - Felix Salfner (GPL)
|
|
93
|
+
- `pyMergeChanges.py` - Y. Cui (GPL)
|
|
94
|
+
- `arxiv-latex-cleaner` - Google Research
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# TeXClean
|
|
2
|
+
|
|
3
|
+
A GUI front-end for cleaning LaTeX documents of track changes markup.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
TeXClean supports cleaning track changes from three different LaTeX packages:
|
|
8
|
+
|
|
9
|
+
1. **TrackChanges** - For documents using `trackchanges.sty`
|
|
10
|
+
2. **Changes** - For documents using `changes.sty`
|
|
11
|
+
3. **arXiv** - For preparing documents for arXiv submission
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
### From PyPI (Recommended)
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install texclean
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
After installation, you can run the application with:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
texclean
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### From Source
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
git clone https://github.com/yourusername/texclean.git
|
|
31
|
+
cd texclean
|
|
32
|
+
pip install -e .
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Requirements
|
|
36
|
+
|
|
37
|
+
- Python 3.8+
|
|
38
|
+
- `arxiv-latex-cleaner` (installed automatically with pip)
|
|
39
|
+
|
|
40
|
+
## Usage
|
|
41
|
+
|
|
42
|
+
1. Run the application:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
texclean
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Or if running from source:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
python -m texclean.app
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
2. Select your input file or folder:
|
|
55
|
+
- For **TrackChanges** and **Changes**: Select a `.tex` file
|
|
56
|
+
- For **arXiv**: Select the project folder containing your LaTeX files
|
|
57
|
+
|
|
58
|
+
3. Choose the cleaning option:
|
|
59
|
+
- **Remove TrackChanges**: Accepts all changes and removes annotations from `trackchanges.sty`
|
|
60
|
+
- **Remove Changes**: Accepts all changes from `changes.sty`
|
|
61
|
+
- **Clean for arXiv**: Removes comments, resizes images, and organizes files for submission
|
|
62
|
+
|
|
63
|
+
4. Click **Clean** to process the file
|
|
64
|
+
|
|
65
|
+
## Output
|
|
66
|
+
|
|
67
|
+
- **TrackChanges/Changes**: Creates a new file with `_no_track` or `_cleaned` suffix
|
|
68
|
+
- **arXiv**: Creates a new folder with `_arXiv` suffix
|
|
69
|
+
|
|
70
|
+
## License
|
|
71
|
+
|
|
72
|
+
This project is licensed under the GNU General Public License v3.0 (GPL-3.0).
|
|
73
|
+
|
|
74
|
+
## Acknowledgments
|
|
75
|
+
|
|
76
|
+
- `acceptchanges3.py` - Felix Salfner (GPL)
|
|
77
|
+
- `pyMergeChanges.py` - Y. Cui (GPL)
|
|
78
|
+
- `arxiv-latex-cleaner` - Google Research
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "texcleaner"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "A GUI front-end for cleaning LaTeX track changes"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "GPL-3.0-or-later"
|
|
11
|
+
authors = [
|
|
12
|
+
{name = "Dan Shim"}
|
|
13
|
+
]
|
|
14
|
+
requires-python = ">=3.8"
|
|
15
|
+
dependencies = [
|
|
16
|
+
"arxiv-latex-cleaner"
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[project.optional-dependencies]
|
|
20
|
+
dev = [
|
|
21
|
+
"build",
|
|
22
|
+
"twine",
|
|
23
|
+
"pytest"
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.scripts]
|
|
27
|
+
texclean = "texclean.app:main"
|
|
28
|
+
|
|
29
|
+
[tool.setuptools]
|
|
30
|
+
package-data = {texclean = ["scripts/**/*.py", "scripts/**/*"]}
|
|
31
|
+
|
|
32
|
+
[tool.setuptools.dynamic]
|
|
33
|
+
version = {attr = "texclean.version.__version__"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TeXClean - A GUI front-end for cleaning LaTeX track changes.
|
|
3
|
+
|
|
4
|
+
Supports cleaning track changes from:
|
|
5
|
+
- trackchanges.sty
|
|
6
|
+
- changes.sty
|
|
7
|
+
- arXiv submission preparation
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from .version import __version__
|
|
11
|
+
from .wrapper import (
|
|
12
|
+
clean_trackchanges,
|
|
13
|
+
clean_changes,
|
|
14
|
+
clean_arxiv,
|
|
15
|
+
generate_output_filename
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"clean_trackchanges",
|
|
20
|
+
"clean_changes",
|
|
21
|
+
"clean_arxiv",
|
|
22
|
+
"generate_output_filename",
|
|
23
|
+
"__version__",
|
|
24
|
+
]
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
app.py - GUI front-end for cleaning LaTeX track changes
|
|
4
|
+
|
|
5
|
+
A simple Tkinter application to clean LaTeX documents of track changes markup
|
|
6
|
+
from TrackChanges, Changes, or arXiv submission packages.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
import threading
|
|
11
|
+
import tkinter as tk
|
|
12
|
+
from tkinter import ttk, filedialog, messagebox, scrolledtext
|
|
13
|
+
|
|
14
|
+
from .wrapper import (
|
|
15
|
+
clean_trackchanges,
|
|
16
|
+
clean_changes,
|
|
17
|
+
clean_arxiv,
|
|
18
|
+
generate_output_filename,
|
|
19
|
+
detect_cleaning_module
|
|
20
|
+
)
|
|
21
|
+
from .version import __version__
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TeXCleanApp:
|
|
25
|
+
def __init__(self, root):
|
|
26
|
+
self.root = root
|
|
27
|
+
self.root.title(f"TeXClean v{__version__} - LaTeX Track Changes Cleaner")
|
|
28
|
+
self.root.geometry("700x500")
|
|
29
|
+
self.root.resizable(True, True)
|
|
30
|
+
|
|
31
|
+
self.input_path = tk.StringVar()
|
|
32
|
+
|
|
33
|
+
self.create_widgets()
|
|
34
|
+
|
|
35
|
+
def create_widgets(self):
|
|
36
|
+
self.notebook = ttk.Notebook(self.root)
|
|
37
|
+
self.notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
|
|
38
|
+
|
|
39
|
+
self.trackchanges_tab = ttk.Frame(self.notebook)
|
|
40
|
+
self.arxiv_tab = ttk.Frame(self.notebook)
|
|
41
|
+
|
|
42
|
+
self.notebook.add(self.trackchanges_tab, text="Track Changes Cleaner")
|
|
43
|
+
self.notebook.add(self.arxiv_tab, text="arXiv Cleaner")
|
|
44
|
+
|
|
45
|
+
self._create_trackchanges_tab()
|
|
46
|
+
self._create_arxiv_tab()
|
|
47
|
+
|
|
48
|
+
def _create_trackchanges_tab(self):
|
|
49
|
+
main_frame = ttk.Frame(self.trackchanges_tab, padding="10")
|
|
50
|
+
main_frame.pack(fill=tk.BOTH, expand=True)
|
|
51
|
+
|
|
52
|
+
title_label = ttk.Label(
|
|
53
|
+
main_frame,
|
|
54
|
+
text="Clean LaTeX Track Changes",
|
|
55
|
+
font=("TkDefaultFont", 14, "bold")
|
|
56
|
+
)
|
|
57
|
+
title_label.pack(pady=(0, 20))
|
|
58
|
+
|
|
59
|
+
input_frame = ttk.LabelFrame(main_frame, text="Input File", padding="5")
|
|
60
|
+
input_frame.pack(fill=tk.X, pady=5)
|
|
61
|
+
input_frame.columnconfigure(0, weight=1)
|
|
62
|
+
|
|
63
|
+
self.trackchanges_entry = ttk.Entry(input_frame, textvariable=self.input_path)
|
|
64
|
+
self.trackchanges_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 5))
|
|
65
|
+
|
|
66
|
+
browse_btn = ttk.Button(input_frame, text="Browse...", command=self._browse_trackchanges_input)
|
|
67
|
+
browse_btn.pack(side=tk.RIGHT)
|
|
68
|
+
|
|
69
|
+
helper_label = ttk.Label(
|
|
70
|
+
input_frame,
|
|
71
|
+
text="Select a .tex file",
|
|
72
|
+
font=("TkDefaultFont", 9, "italic"),
|
|
73
|
+
foreground="gray"
|
|
74
|
+
)
|
|
75
|
+
helper_label.pack(anchor=tk.W, pady=(2, 0))
|
|
76
|
+
|
|
77
|
+
self.trackchanges_clean_btn = ttk.Button(
|
|
78
|
+
main_frame,
|
|
79
|
+
text="Detect & Clean",
|
|
80
|
+
command=self._start_trackchanges_cleaning
|
|
81
|
+
)
|
|
82
|
+
self.trackchanges_clean_btn.pack(pady=20)
|
|
83
|
+
|
|
84
|
+
log_label = ttk.Label(main_frame, text="Log Output:", font=("TkDefaultFont", 10, "bold"))
|
|
85
|
+
log_label.pack(anchor=tk.W, pady=(10, 5))
|
|
86
|
+
|
|
87
|
+
self.trackchanges_log = scrolledtext.ScrolledText(
|
|
88
|
+
main_frame,
|
|
89
|
+
height=12,
|
|
90
|
+
width=80,
|
|
91
|
+
state=tk.DISABLED,
|
|
92
|
+
wrap=tk.WORD
|
|
93
|
+
)
|
|
94
|
+
self.trackchanges_log.pack(fill=tk.BOTH, expand=True, pady=5)
|
|
95
|
+
|
|
96
|
+
self.trackchanges_progress = ttk.Progressbar(main_frame, mode="indeterminate")
|
|
97
|
+
self.trackchanges_progress.pack(fill=tk.X, pady=5)
|
|
98
|
+
|
|
99
|
+
def _create_arxiv_tab(self):
|
|
100
|
+
main_frame = ttk.Frame(self.arxiv_tab, padding="10")
|
|
101
|
+
main_frame.pack(fill=tk.BOTH, expand=True)
|
|
102
|
+
|
|
103
|
+
title_label = ttk.Label(
|
|
104
|
+
main_frame,
|
|
105
|
+
text="Clean for arXiv Submission",
|
|
106
|
+
font=("TkDefaultFont", 14, "bold")
|
|
107
|
+
)
|
|
108
|
+
title_label.pack(pady=(0, 20))
|
|
109
|
+
|
|
110
|
+
input_frame = ttk.LabelFrame(main_frame, text="Project Folder", padding="5")
|
|
111
|
+
input_frame.pack(fill=tk.X, pady=5)
|
|
112
|
+
input_frame.columnconfigure(0, weight=1)
|
|
113
|
+
|
|
114
|
+
self.arxiv_entry = ttk.Entry(input_frame)
|
|
115
|
+
self.arxiv_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 5))
|
|
116
|
+
|
|
117
|
+
browse_btn = ttk.Button(input_frame, text="Browse...", command=self._browse_arxiv_input)
|
|
118
|
+
browse_btn.pack(side=tk.RIGHT)
|
|
119
|
+
|
|
120
|
+
helper_label = ttk.Label(
|
|
121
|
+
input_frame,
|
|
122
|
+
text="Select a project folder",
|
|
123
|
+
font=("TkDefaultFont", 9, "italic"),
|
|
124
|
+
foreground="gray"
|
|
125
|
+
)
|
|
126
|
+
helper_label.pack(anchor=tk.W, pady=(2, 0))
|
|
127
|
+
|
|
128
|
+
self.arxiv_clean_btn = ttk.Button(
|
|
129
|
+
main_frame,
|
|
130
|
+
text="Clean for arXiv",
|
|
131
|
+
command=self._start_arxiv_cleaning
|
|
132
|
+
)
|
|
133
|
+
self.arxiv_clean_btn.pack(pady=20)
|
|
134
|
+
|
|
135
|
+
log_label = ttk.Label(main_frame, text="Log Output:", font=("TkDefaultFont", 10, "bold"))
|
|
136
|
+
log_label.pack(anchor=tk.W, pady=(10, 5))
|
|
137
|
+
|
|
138
|
+
self.arxiv_log = scrolledtext.ScrolledText(
|
|
139
|
+
main_frame,
|
|
140
|
+
height=12,
|
|
141
|
+
width=80,
|
|
142
|
+
state=tk.DISABLED,
|
|
143
|
+
wrap=tk.WORD
|
|
144
|
+
)
|
|
145
|
+
self.arxiv_log.pack(fill=tk.BOTH, expand=True, pady=5)
|
|
146
|
+
|
|
147
|
+
self.arxiv_progress = ttk.Progressbar(main_frame, mode="indeterminate")
|
|
148
|
+
self.arxiv_progress.pack(fill=tk.X, pady=5)
|
|
149
|
+
|
|
150
|
+
def _browse_trackchanges_input(self):
|
|
151
|
+
file_path = filedialog.askopenfilename(
|
|
152
|
+
title="Select LaTeX File",
|
|
153
|
+
filetypes=[("LaTeX files", "*.tex"), ("All files", "*.*")]
|
|
154
|
+
)
|
|
155
|
+
if file_path:
|
|
156
|
+
self.input_path.set(file_path)
|
|
157
|
+
|
|
158
|
+
def _browse_arxiv_input(self):
|
|
159
|
+
folder = filedialog.askdirectory(title="Select LaTeX Project Folder")
|
|
160
|
+
if folder:
|
|
161
|
+
self.arxiv_entry.delete(0, tk.END)
|
|
162
|
+
self.arxiv_entry.insert(0, folder)
|
|
163
|
+
|
|
164
|
+
def _log(self, message, log_widget):
|
|
165
|
+
log_widget.config(state=tk.NORMAL)
|
|
166
|
+
log_widget.insert(tk.END, message)
|
|
167
|
+
log_widget.see(tk.END)
|
|
168
|
+
log_widget.config(state=tk.DISABLED)
|
|
169
|
+
|
|
170
|
+
def _clear_log(self, log_widget):
|
|
171
|
+
log_widget.config(state=tk.NORMAL)
|
|
172
|
+
log_widget.delete(1.0, tk.END)
|
|
173
|
+
log_widget.config(state=tk.DISABLED)
|
|
174
|
+
|
|
175
|
+
def _validate_tex_input(self, input_path):
|
|
176
|
+
if not input_path:
|
|
177
|
+
return False, "Please select an input file."
|
|
178
|
+
if not os.path.exists(input_path):
|
|
179
|
+
return False, f"Path not found: {input_path}"
|
|
180
|
+
if not os.path.isfile(input_path):
|
|
181
|
+
return False, "Error: This operation requires a .tex file."
|
|
182
|
+
if not input_path.lower().endswith(".tex"):
|
|
183
|
+
return False, "Error: The selected file must have a .tex extension."
|
|
184
|
+
return True, ""
|
|
185
|
+
|
|
186
|
+
def _validate_folder_input(self, folder_path):
|
|
187
|
+
if not folder_path:
|
|
188
|
+
return False, "Please select a project folder."
|
|
189
|
+
if not os.path.exists(folder_path):
|
|
190
|
+
return False, f"Folder not found: {folder_path}"
|
|
191
|
+
if not os.path.isdir(folder_path):
|
|
192
|
+
return False, "Error: This operation requires a folder."
|
|
193
|
+
return True, ""
|
|
194
|
+
|
|
195
|
+
def _start_trackchanges_cleaning(self):
|
|
196
|
+
input_path = self.input_path.get().strip()
|
|
197
|
+
|
|
198
|
+
valid, error_msg = self._validate_tex_input(input_path)
|
|
199
|
+
if not valid:
|
|
200
|
+
messagebox.showerror("Input Error", error_msg)
|
|
201
|
+
return
|
|
202
|
+
|
|
203
|
+
detected = detect_cleaning_module(input_path)
|
|
204
|
+
|
|
205
|
+
if detected is None:
|
|
206
|
+
result = messagebox.askyesno(
|
|
207
|
+
"No Track Changes Detected",
|
|
208
|
+
"No track changes markup (trackchanges or changes package) was detected in the file.\n\n"
|
|
209
|
+
"Would you like to try cleaning anyway?"
|
|
210
|
+
)
|
|
211
|
+
if not result:
|
|
212
|
+
return
|
|
213
|
+
detected = "trackchanges"
|
|
214
|
+
else:
|
|
215
|
+
module_name = "TrackChanges (trackchanges.sty)" if detected == "trackchanges" else "Changes (changes.sty)"
|
|
216
|
+
result = messagebox.askyesno(
|
|
217
|
+
"Confirm Detected Module",
|
|
218
|
+
f"Detected '{module_name}' signatures in the file.\n\n"
|
|
219
|
+
f"Is this correct and would you like to proceed with cleaning?"
|
|
220
|
+
)
|
|
221
|
+
if not result:
|
|
222
|
+
return
|
|
223
|
+
|
|
224
|
+
self._clear_log(self.trackchanges_log)
|
|
225
|
+
self.trackchanges_clean_btn.config(state=tk.DISABLED)
|
|
226
|
+
self.trackchanges_progress.start(10)
|
|
227
|
+
self._log(f"Detected module: {detected}\n", self.trackchanges_log)
|
|
228
|
+
self._log("Starting cleaning...\n", self.trackchanges_log)
|
|
229
|
+
|
|
230
|
+
thread = threading.Thread(
|
|
231
|
+
target=self._run_trackchanges_cleaning,
|
|
232
|
+
args=(input_path, detected)
|
|
233
|
+
)
|
|
234
|
+
thread.daemon = True
|
|
235
|
+
thread.start()
|
|
236
|
+
|
|
237
|
+
def _run_trackchanges_cleaning(self, input_path, detected_module):
|
|
238
|
+
def callback(message):
|
|
239
|
+
self.root.after(0, self._log, message, self.trackchanges_log)
|
|
240
|
+
|
|
241
|
+
try:
|
|
242
|
+
output_path = generate_output_filename(input_path, "-cleaned")
|
|
243
|
+
|
|
244
|
+
if detected_module == "trackchanges":
|
|
245
|
+
success, message = clean_trackchanges(input_path, output_path, callback)
|
|
246
|
+
else:
|
|
247
|
+
success, message = clean_changes(input_path, output_path, callback)
|
|
248
|
+
|
|
249
|
+
callback("\n" + message + "\n")
|
|
250
|
+
|
|
251
|
+
if success:
|
|
252
|
+
self.root.after(0, lambda: messagebox.showinfo("Success", message))
|
|
253
|
+
else:
|
|
254
|
+
self.root.after(0, lambda: messagebox.showerror("Error", message))
|
|
255
|
+
|
|
256
|
+
except Exception as e:
|
|
257
|
+
error_msg = f"Unexpected error: {str(e)}"
|
|
258
|
+
self.root.after(0, self._log, error_msg, self.trackchanges_log)
|
|
259
|
+
self.root.after(0, lambda: messagebox.showerror("Error", error_msg))
|
|
260
|
+
|
|
261
|
+
finally:
|
|
262
|
+
self.root.after(0, self.trackchanges_progress.stop)
|
|
263
|
+
self.root.after(0, lambda: self.trackchanges_clean_btn.config(state=tk.NORMAL))
|
|
264
|
+
|
|
265
|
+
def _start_arxiv_cleaning(self):
|
|
266
|
+
folder_path = self.arxiv_entry.get().strip()
|
|
267
|
+
|
|
268
|
+
valid, error_msg = self._validate_folder_input(folder_path)
|
|
269
|
+
if not valid:
|
|
270
|
+
messagebox.showerror("Input Error", error_msg)
|
|
271
|
+
return
|
|
272
|
+
|
|
273
|
+
self._clear_log(self.arxiv_log)
|
|
274
|
+
self.arxiv_clean_btn.config(state=tk.DISABLED)
|
|
275
|
+
self.arxiv_progress.start(10)
|
|
276
|
+
|
|
277
|
+
thread = threading.Thread(target=self._run_arxiv_cleaning, args=(folder_path,))
|
|
278
|
+
thread.daemon = True
|
|
279
|
+
thread.start()
|
|
280
|
+
|
|
281
|
+
def _run_arxiv_cleaning(self, folder_path):
|
|
282
|
+
def callback(message):
|
|
283
|
+
self.root.after(0, self._log, message, self.arxiv_log)
|
|
284
|
+
|
|
285
|
+
try:
|
|
286
|
+
success, message = clean_arxiv(folder_path, callback=callback)
|
|
287
|
+
|
|
288
|
+
callback("\n" + message + "\n")
|
|
289
|
+
|
|
290
|
+
if success:
|
|
291
|
+
self.root.after(0, lambda: messagebox.showinfo("Success", message))
|
|
292
|
+
else:
|
|
293
|
+
self.root.after(0, lambda: messagebox.showerror("Error", message))
|
|
294
|
+
|
|
295
|
+
except Exception as e:
|
|
296
|
+
error_msg = f"Unexpected error: {str(e)}"
|
|
297
|
+
self.root.after(0, self._log, error_msg, self.arxiv_log)
|
|
298
|
+
self.root.after(0, lambda: messagebox.showerror("Error", error_msg))
|
|
299
|
+
|
|
300
|
+
finally:
|
|
301
|
+
self.root.after(0, self.arxiv_progress.stop)
|
|
302
|
+
self.root.after(0, lambda: self.arxiv_clean_btn.config(state=tk.NORMAL))
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def main():
|
|
306
|
+
root = tk.Tk()
|
|
307
|
+
app = TeXCleanApp(root)
|
|
308
|
+
root.mainloop()
|