Skip to content

Commit 6b8adc8

Browse files
committed
Finishing touches for first release
1 parent 2b8e85a commit 6b8adc8

File tree

5 files changed

+70
-46
lines changed

5 files changed

+70
-46
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
*.pdf
2+
13
# Byte-compiled / optimized / DLL files
24
__pycache__/
35
*.py[cod]

README.md

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# PyPDF Builder
22

3-
A cross-platform clone of [PDFTK Builder](http://angusj.com/pdftkb/) written in Python. Yes, Python!
3+
A cross-platform utility to join, split, stamp, and rotate PDFs written in Python. Yes, Python!
44

5-
The project's goal is a simple, end-user friendly GUI for the [PyPDF2](https://github.com/mstamy2/PyPDF2) package that can join, split, stamp/number, and rotate PDFs.
5+
This project is inspired by Angus Johnson's [PDFTK Builder](http://angusj.com/pdftkb/). Its goal is a GUI that builds on [PyPDF2](https://github.com/mstamy2/PyPDF2) as well as other PDF related libraries and offers a unified and simple experience for end-users.
66

77
![](screenshot.png)
88

@@ -12,10 +12,10 @@ Grab a copy of `virtualenv` or `virtualenvwrapper` and set up a virtual environm
1212

1313
```
1414
git clone https://github.com/mrgnth/PyPDF-Builder.git
15-
pip install -r requirements
15+
pip install -r requirements.txt
1616
```
1717

18-
These instructions will get you a copy of the project up and running on your local machine for development ~~and testing~~ purposes. ~~See deployment for notes on how to deploy the project on a live system.~~
18+
These instructions will get you a copy of the project up and running on your local machine for development purposes.
1919

2020
### Prerequisites
2121

@@ -35,7 +35,16 @@ Python 3.6 was used in development… I haven't checked for compatibility with l
3535

3636
## Deployment
3737

38-
Distributable application for Windows, Linux and Mac OS using pyInstaller or similiar tool. This isn't all too clear yet.
38+
Distributable application for Windows, Linux and Mac OS using [PyInstaller](https://pyinstaller.readthedocs.io/en/stable/):
39+
40+
```
41+
pyinstaller --onefile --clean --windowed --add-data="mainwindow.ui:." \
42+
--hidden-import="pygubu.builder.ttkstdwidgets" \
43+
--hidden-import="pygubu.builder.widgets.dialog" \
44+
pypdfbuilder.py
45+
```
46+
47+
Subsequent builds can be managed by editing the `.spec` file created by the first build and then simply running `pyinstaller pypdfbuilder.spec` to build the executable.
3948

4049
Long term: Inclusion in Debian repos for direct installation on end-user systems.
4150

@@ -46,6 +55,7 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
4655
## Acknowledgments
4756

4857
* [Matthew Stamy](https://github.com/mstamy2): Creator and current maintainer of the PyPDF2 Python package
58+
* Angus Johnson: Creator of [PDFTK Builder](http://angusj.com/pdftkb/)
4959

5060
## To Do
5161

mainwindow.ui

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,7 @@
723723
<child>
724724
<object class="ttk.Button" id="RotateSaveButton">
725725
<property name="command">rotatetab_save_as</property>
726-
<property name="text" translatable="yes">Save As…</property>
726+
<property name="text" translatable="yes">Save As …</property>
727727
<layout>
728728
<property name="column">0</property>
729729
<property name="padx">10</property>
@@ -763,7 +763,6 @@
763763
</layout>
764764
<child>
765765
<object class="ttk.Label" id="StatusText">
766-
<property name="text" translatable="yes">PyPDF v1.0</property>
767766
<property name="textvariable">string:application_status_text</property>
768767
<layout>
769768
<property name="column">0</property>
@@ -908,6 +907,7 @@
908907
</layout>
909908
<child>
910909
<object class="ttk.Checkbutton" id="UsePopplerCheckbutton_1">
910+
<property name="state">disabled</property>
911911
<property name="text" translatable="yes">Use Poppler PDF Tools if available</property>
912912
<property name="variable">boolean:settings_use_poppler</property>
913913
<layout>

pypdfbuilder.py

Lines changed: 47 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#!/usr/bin/python
22

33
import os
4+
import sys
45
import appdirs
56
import json
67
from pathlib import Path as plPath
@@ -9,12 +10,18 @@
910

1011
from tkinter import filedialog
1112
from pygubu import Builder as pgBuilder
12-
from pygubu.builder import ttkstdwidgets
13+
14+
# if dist fails to start because it's missing these, uncomment these two imports
15+
# import pygubu.builder.ttkstdwidgets
16+
# import pygubu.builder.widgets.dialog
1317

1418
from PyPDF2 import PdfFileMerger, PdfFileReader, PdfFileWriter
1519

16-
APPNAME = 'pypdfbuilder'
17-
CURRENT_DIR = os.path.abspath(os.path.dirname(__file__))
20+
# check to see if we're running from stand-alone one-file executable:
21+
if hasattr(sys, '_MEIPASS'):
22+
CURRENT_DIR = sys._MEIPASS
23+
else:
24+
CURRENT_DIR = os.path.abspath(os.path.dirname(__file__))
1825
USER_DIR = str(plPath.home())
1926
CONFIG_DIR = appdirs.user_config_dir(APPNAME)
2027
DATA_DIR = appdirs.user_data_dir(APPNAME)
@@ -185,7 +192,7 @@ def concat_filename(self, max_length=35):
185192
186193
'''
187194
basename = os.path.basename(self.__filepath)
188-
concat_filename = f'{basename[0:35]}'
195+
concat_filename = f'{basename[0:max_length]}'
189196
if len(basename) > max_length:
190197
concat_filename += '…'
191198
return concat_filename
@@ -513,17 +520,17 @@ def __init__(self):
513520
self.builder = pgBuilder()
514521
self.builder.add_from_file(os.path.join(CURRENT_DIR, 'mainwindow.ui'))
515522

516-
self.mainwindow = self.builder.get_object('MainWindow')
517-
self.settings_dialog = self.builder.get_object('SettingsDialog', self.mainwindow)
518-
self.notebook = self.builder.get_object('AppNotebook')
519-
self.tabs = {
523+
self.__mainwindow = self.builder.get_object('MainWindow')
524+
self.__settings_dialog = self.builder.get_object('SettingsDialog', self.__mainwindow)
525+
self.__notebook = self.builder.get_object('AppNotebook')
526+
self.__tabs = {
520527
'join': self.builder.get_object('JoinFrame'),
521528
'split': self.builder.get_object('SplitFrame'),
522529
'bg': self.builder.get_object('BgFrame'),
523530
'rotate': self.builder.get_object('RotateFrame'),
524531
}
525-
self.mainmenu = self.builder.get_object('MainMenu')
526-
self.mainwindow.config(menu=self.mainmenu)
532+
self.__mainmenu = self.builder.get_object('MainMenu')
533+
self.__mainwindow.config(menu=self.__mainmenu)
527534
self.__status_text_variable = self.builder.get_variable('application_status_text')
528535
self.__settings_use_poppler_variable = self.builder.get_variable('settings_use_poppler')
529536
self.status_text = None
@@ -532,10 +539,12 @@ def __init__(self):
532539
self.user_data = UserData()
533540
self.settings_data = SettingsData()
534541

535-
self.jointab = JoinTabManager(self)
536-
self.splittab = SplitTabManager(self)
537-
self.bgtab = BgTabManager(self)
538-
self.rotatetab = RotateTabManager(self)
542+
self.__jointab = JoinTabManager(self)
543+
self.__splittab = SplitTabManager(self)
544+
self.__bgtab = BgTabManager(self)
545+
self.__rotatetab = RotateTabManager(self)
546+
547+
self.status_text = DEFAULT_STATUS
539548

540549
@property
541550
def status_text(self):
@@ -549,55 +558,55 @@ def status_text(self, val):
549558
def select_tab_join(self, *args, **kwargs):
550559
'''Gets called when menu item "View > Join Files" is selected.
551560
Pops appropriate tab into view.'''
552-
self.notebook.select(self.tabs['join'])
561+
self.__notebook.select(self.__tabs['join'])
553562

554563
def select_tab_split(self, *args, **kwargs):
555564
'''Gets called when menu item "View > Split File" is selected.
556565
Pops appropriate tab into view.'''
557-
self.notebook.select(self.tabs['split'])
566+
self.__notebook.select(self.__tabs['split'])
558567

559568
def select_tab_bg(self, *args, **kwargs):
560569
'''Gets called when menu item "View > Background/Stamp/Number" is selected.
561570
Pops appropriate tab into view.'''
562-
self.notebook.select(self.tabs['bg'])
571+
self.__notebook.select(self.__tabs['bg'])
563572

564573
def select_tab_rotate(self, *args, **kwargs):
565574
'''Gets called when menu item "View > Rotate Pages" is selected.
566575
Pops appropriate tab into view.'''
567-
self.notebook.select(self.tabs['rotate'])
576+
self.__notebook.select(self.__tabs['rotate'])
568577

569578
def jointab_add_file(self):
570-
self.jointab.add_file()
579+
self.__jointab.add_file()
571580

572581
def jointab_on_file_select(self, event):
573-
self.jointab.on_file_select(event)
582+
self.__jointab.on_file_select(event)
574583

575584
def jointab_enter_page_selection(self, event):
576-
self.jointab.enter_page_selection(event)
585+
self.__jointab.enter_page_selection(event)
577586

578587
def jointab_save_as(self):
579-
self.jointab.save_as()
588+
self.__jointab.save_as()
580589

581590
def jointab_move_up(self):
582-
self.jointab.move_up()
591+
self.__jointab.move_up()
583592

584593
def jointab_move_down(self):
585-
self.jointab.move_down()
594+
self.__jointab.move_down()
586595

587596
def jointab_remove(self):
588-
self.jointab.remove_file()
597+
self.__jointab.remove_file()
589598

590599
def splittab_open_file(self):
591-
self.splittab.open_file()
600+
self.__splittab.open_file()
592601

593602
def splittab_save_as(self):
594-
self.splittab.save_as()
603+
self.__splittab.save_as()
595604

596605
def bgtab_choose_bg_option(self):
597-
self.bgtab.choose_bg_option()
606+
self.__bgtab.choose_bg_option()
598607

599608
def bgtab_choose_stamp_option(self):
600-
self.bgtab.choose_stamp_option()
609+
self.__bgtab.choose_stamp_option()
601610

602611
def bgtab_choose_number_option(self):
603612
'''
@@ -607,19 +616,19 @@ def bgtab_choose_number_option(self):
607616
pass
608617

609618
def bgtab_choose_source_file(self):
610-
self.bgtab.choose_source_file()
619+
self.__bgtab.choose_source_file()
611620

612621
def bgtab_choose_bg_file(self):
613-
self.bgtab.choose_bg_file()
622+
self.__bgtab.choose_bg_file()
614623

615624
def bgtab_save_as(self):
616-
self.bgtab.save_as()
625+
self.__bgtab.save_as()
617626

618627
def rotatetab_open_file(self):
619-
self.rotatetab.open_file()
628+
self.__rotatetab.open_file()
620629

621630
def rotatetab_save_as(self):
622-
self.rotatetab.save_as()
631+
self.__rotatetab.save_as()
623632

624633
def save_success(self, status_text=DEFAULT_STATUS):
625634
'''Gets called when a PDF file was processed successfully. Currently only
@@ -633,12 +642,12 @@ def show_settings(self, *args, **kwargs):
633642
and all the settings management is handled there. Args and kwargs are included in
634643
method definition in case it is triggered by the keyboard shortcut, in which
635644
case `event` gets passed into the call.'''
636-
self.settings_dialog.run()
645+
self.__settings_dialog.run()
637646
self.__settings_use_poppler_variable.set(self.settings_data.use_poppler_tools)
638647

639648
def close_settings(self, *args, **kwargs):
640649
self.settings_data.use_poppler_tools = self.__settings_use_poppler_variable.get()
641-
self.settings_dialog.close()
650+
self.__settings_dialog.close()
642651

643652
def cancel_settings(self, *args, **kwargs):
644653
pass
@@ -657,10 +666,10 @@ def get_file_dialog(self, func, widget_title='Choose File(s) …'):
657666
return f
658667

659668
def quit(self, event=None):
660-
self.mainwindow.quit()
669+
self.__mainwindow.quit()
661670

662671
def run(self):
663-
self.mainwindow.mainloop()
672+
self.__mainwindow.mainloop()
664673

665674

666675
if __name__ == '__main__':

settings.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
APPNAME = 'pypdfbuilder'
2+
APPVERSION = '0.9'
3+
14
# Constants for indexing into the values stored in the TreeView (e.g. in the Join View)
25

36
PDF_FILENAME = 0
@@ -12,4 +15,4 @@
1215
JOIN_FILE_SUCCESS = 'Files joined successfully to {}!'
1316
ROTATE_FILE_SUCCESS = 'Pages in {} rotated successfully!'
1417
BG_FILE_SUCCESS = 'File saved successfully to {}!'
15-
DEFAULT_STATUS = 'PyPDF Builder v1.0'
18+
DEFAULT_STATUS = F'PyPDF Builder v{APPVERSION}'

0 commit comments

Comments
 (0)