Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
ec64ed4
added base files for gui
Oct 31, 2019
cc5eceb
renamed files; added input section layout
Oct 31, 2019
dbd48e4
settings section
Oct 31, 2019
742aa5d
finished base ui layout
Nov 3, 2019
ffecbd5
added TOS to ui
Nov 3, 2019
f4e7830
implemented 'clear'-button
Nov 3, 2019
736de26
implemented 'add file'-button
Nov 3, 2019
deb3f78
adjusted ui checkboxes; made section-label bold
Nov 3, 2019
c854c46
adjusted width of listbox; only allowed adding of timetables if it wa…
Nov 3, 2019
95c3c7d
hooked up checkboxes to logic;
Nov 3, 2019
6b06284
started parsing -> need a way to let the user select modules from the…
Nov 3, 2019
b0ae8c4
continued working on parsing
Nov 3, 2019
ebeb6f9
finished parsing
Nov 9, 2019
53f7cec
added data_item_chooser to layout
Nov 9, 2019
a11f01f
displaying parsed modules in ui
Nov 9, 2019
68e2a35
redesigned selection process to only use 1 listbox
Nov 9, 2019
4ff6f5c
started working on creating the calendar with selected modules
Nov 9, 2019
6198bf4
patched everything together, does not support multiple files or respe…
Nov 9, 2019
7264e86
added errormessage for errors during parsing
Nov 9, 2019
61a6606
improved usability
Nov 9, 2019
3cf4916
added todo
Nov 9, 2019
73b593a
just 2 more todos and it should be good to go
Nov 9, 2019
c7ea72a
missing cache readability
Nov 10, 2019
b052963
fixed calendar creation
Nov 10, 2019
2f235c3
fixed caching of parsed files
Nov 10, 2019
d2e8ee4
catching exception during parsing
Nov 10, 2019
b0000d2
removed todo
Nov 10, 2019
0c87317
cleaned up main
Nov 10, 2019
1dc0a65
added select all and deselect all buttons for the module chooser
Nov 10, 2019
3bb3b0e
switched clear and add timetable buttons
Nov 10, 2019
af60387
allowing multiple file selection when adding timetables
Nov 10, 2019
0c8e1b9
added icon
Nov 10, 2019
871792e
fixed smiley-issue
Nov 10, 2019
387c658
updated quickstart
Nov 10, 2019
3903b6c
updated quickstart
Nov 10, 2019
678cb41
added release
Nov 10, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 38 additions & 19 deletions QuickStart.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,25 @@ pip install -r requirements.txt
```

## Verwendung

* Lege die auszulesende Stundenplan-PDF in den Input-Ordner ab (`data/input`)
* ```
python python-scripts/main.py
```
* Es folgt eine Konsolenabfrage zu den gewünschten Modulen.
* Formatierter Stundenplan ist in dem Output-Ordner in Form von einer `.csv`- oder `.ics`-Datei, zu finden (`data/output`)
* Importiere das gewünschte Format in den Kalender
* `.ics` = für Apple Anwendungen
* `.csv` = für Meisten anderen Kalenderanwendungen
* Windows
1. Führe TTP.exe in release/vX-X-X/ aus. Hinweis: Du musst evtl. die Datei vorher entpacken.
2. Füge Stundenpläne hinzu, die konvertiert werden sollen.
3. Setze die Einstellungen, die du willst.
4. Lese und erkläre dich mit den AGB/TOS einverstanden. Hinweis: Hierfür musst du Englisch verstehen können.
5. Drücke auf 'Parse Timetable(s)'.
6. Wähle die Module aus, die in den Kalendar integriert werden sollen.
7. Drücke auf 'Create Calendar'.
8. Der Calendar befindet sich im Verzeichnis ./data/output.

* Andere Betriebssysteme
1. Führe ```python python-scripts/main.py``` in dem Wurzelverzeichnis aus.
2. Füge Stundenpläne hinzu, die konvertiert werden sollen.
3. Setze die Einstellungen, die du willst.
4. Lese und erkläre dich mit den AGB/TOS einverstanden. Hinweis: Hierfür musst du Englisch verstehen können.
5. Drücke auf 'Parse Timetable(s)'.
6. Wähle die Module aus, die in den Kalendar integriert werden sollen.
7. Drücke auf 'Create Calendar'.
8. Der Calendar befindet sich im Verzeichnis ./data/output.

## Ordnerstruktur
```
Expand Down Expand Up @@ -69,15 +78,25 @@ pip install -r requirements.txt
```

## Usage
* Save timetable-PDF in input-folder (`data/input`)
* ```bash
python python-scripts/main.py
```
* A console query will ask you to choose your modules
* Formatted timetable will be created in form of a `.csv`- or `.ics`-file, depending on your choice, in the output-folder (`data/output`)
* Import your prefered file to your calendar
* `.ics` = for Apple Applications
* `.csv` = for most other Applications
* Windows
1. Run TTP.exe in release/vX-X-X/. Hint: You might need to unzip it first.
2. Add Timetables that are going to be parsed.
3. Adjust settings to your liking.
4. Read and agree to Terms of Service.
5. Press 'Parse Timetable(s)'.
6. Choose desired modules for the calendar.
7. Press 'Create Calendar'.
8. The calendar will be in ./data/output.

* Other OS
1. Run ```python python-scripts/main.py``` in root-directory.
2. Add Timetables that are going to be parsed.
3. Adjust settings to your liking.
4. Read and agree to Terms of Service.
5. Press 'Parse Timetable(s)'.
6. Choose desired modules for the calendar.
7. Press 'Create Calendar'.
8. The calendar will be in ./data/output.

## Folder Structure
```
Expand Down
Empty file removed data/input/.keep
Empty file.
133 changes: 133 additions & 0 deletions python-scripts/classes/controller/gui_controller.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
from tkinter import messagebox

from classes.controller.timetable_controller import TimetableController
from classes.file_management.loader import Loader
from classes.models.timetable import Timetable
from classes.view import gui
from helper.data_handler import get_module_names_from_data_items
from helper.data_item_from_json import data_items_from_json
from helper.data_output import create_ics, create_csv, create_json_from_data_item
from helper.folder_manager import path_leaf, get_cached_file_for
from helper.get_pdf_pages import count_pdf_pages


class GuiController:

def __init__(self):
self.input_files = []
self.selectable_modules = []
self._parsed_data_items = []

def clear_inputs(self):
self.input_files.clear()
self.selectable_modules.clear()
self._parsed_data_items.clear()

def create_calendar(self, agreed_to_tos, export_as_ics, selected_module_indices):
if not agreed_to_tos:
messagebox.showerror(gui.title, "You need to agree to the Terms Of Service to do that.")
return

if len(self._parsed_data_items) == 0:
messagebox.showinfo(gui.title, "There are no modules to select.\nPlease parse a timetable.")
return

if len(selected_module_indices) == 0:
messagebox.showinfo(gui.title, "There are no modules selected.\n"
"Please select modules to fill the calendar with.")
return

selected_module_names = []
for index in selected_module_indices:
selected_module_names.append(self.selectable_modules[index])

selected_modules = []
for data_item in self._parsed_data_items:
if selected_module_names.__contains__(data_item.module):
selected_modules.append(data_item)

if export_as_ics:
create_ics(selected_modules)
else:
create_csv(selected_modules)

messagebox.showinfo(gui.title, "Created the calendar. Check the /data/output folder! :)")

def parse_input_files(self, use_cache, agreed_to_tos):
if not agreed_to_tos:
messagebox.showerror(gui.title, "You need to agree to the Terms Of Service to do that.")
return

if len(self.input_files) == 0:
messagebox.showinfo(gui.title, "There are no timetables to parse. "
"To parse a timetable add it via the 'Add Timetable'-Button.")
return

# reset from previous parse
self.selectable_modules = []
self._parsed_data_items = []

messagebox.showinfo(gui.title, "This process may take a while. Grab a something to drink! :)")

for file in self.input_files:
try:
cached_file = get_cached_file_for(path_leaf(file))
file_is_parsed_already = cached_file.is_file()

data_items_in_file = get_data_items_from_file(cached_file) if file_is_parsed_already and use_cache \
else get_data_items_from_file(file)

for data_item in data_items_in_file:
self._parsed_data_items.append(data_item)

modules_in_data_items = get_module_names_from_data_items(data_items_in_file)
for module in modules_in_data_items:
self.selectable_modules.append(module)

if not (file_is_parsed_already and use_cache):
create_json_from_data_item(data_items_in_file, path_leaf(cached_file).replace('.json', ''))
print(path_leaf(file) + " was successfully parsed.")

except Exception as e:
messagebox.showerror(gui.title,
"Couldn't parse the timetable '" + path_leaf(file) + "' because:\n" + str(e))

messagebox.showinfo(gui.title, "Parsing finished! :)")


def get_data_items_from_file(file):
"""
Summary
-------
Retrieves the data items from the given file.

Parameter
---------
file : path # Absolute path of the file that's going to be parsed.
Supports *.json and *.pdf files.
timetable : timetable # The timetable to retrieve the info with.
"""

data_items = []

if str(file).endswith('.pdf'):
# get data items from *.pdf file
timetable = Timetable()

page_count = count_pdf_pages(file)
for page_index in range(page_count):
timetable_controller = TimetableController(Loader(file, path_leaf(file), page_index), timetable)
timetable_controller.create_timetable_information()
timetable_controller.send_data_to_timetable()
timetable.search_modules()
timetable.get_weeks()
timetable.find_modules(data_items)

elif str(file).endswith('.json'):
# get data items from *.json file
data_items_from_json(data_items, file)

else:
throw: Exception("File type not supported. Please provide only *.pdf or *.json files.")

return data_items
31 changes: 16 additions & 15 deletions python-scripts/classes/models/timetable.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from .timetable_information import TimetableInformation
from helper.regex_parser import RegexParser
from classes.file_management.loader import Loader
import datetime
from .event_meta import EventMeta

from classes.file_management.loader import Loader
from classes.timetable_parts.week import Week
from helper.data_handler import create_event, string_to_datetime
from helper.regex_parser import RegexParser
from .event_meta import EventMeta
from .iterable import *
from .timetable_information import TimetableInformation


class Timetable:
Expand Down Expand Up @@ -54,7 +55,7 @@ def __calculate_date_from_week_number(self, week_number):
-------
String of current date in format YYYY-MM-DD
"""

total_weeks = self.__get_total_weeks_of_year()
# Gets from - to - years, can differ in the winter semester
years = self.__timetalbe_information.current_year
Expand Down Expand Up @@ -82,7 +83,7 @@ def __calculate_date_from_week_number(self, week_number):
def __get_total_weeks_of_year(self):
gemein_jahre = [2020, 2026, 2032, 2037]
total_weeks = 52
if self.__timetalbe_information.current_year[0]-1 in gemein_jahre:
if self.__timetalbe_information.current_year[0] - 1 in gemein_jahre:
total_weeks = 53
return total_weeks

Expand All @@ -93,7 +94,7 @@ def __fill_weeks(self):
self.__weeks = dict()
for week in self.__timetalbe_information.week_numbers:
self.__weeks[str(week)] = (Week(self.__calculate_date_from_week_number(week), week)
.fill_days(self.__timetalbe_information.week_days_per_week))
.fill_days(self.__timetalbe_information.week_days_per_week))

def find_modules(self, data: list):
"""
Expand All @@ -104,7 +105,7 @@ def find_modules(self, data: list):

# test is a list of all horizontal lines bigger than the default date (sorry for the variable naming)
test = RegexParser.extract_modules_pyquery_array(self.__loader.get_file(),
(self.__timetalbe_information.single_time_stamp_width*
(self.__timetalbe_information.single_time_stamp_width *
len(self.__timetalbe_information.time_stamp_information)),
self.__timetalbe_information.single_time_stamp_width)

Expand Down Expand Up @@ -146,7 +147,6 @@ def find_modules(self, data: list):

# Iterate over dictionary, because one page can contain multiple weeks. Sorry for the naming
for key, value in self.__weeks.items():

# Get current date of day
start_date = value.days[item.day_name].date_of_day.strftime("%d/%m/%Y")
start_end_time = self.__find_module_time(item)
Expand All @@ -173,13 +173,14 @@ def __find_module_time(self, item):
# Return dictionary with ["end" : "end time", "start" : "start time"]
return return_information

def __find_module_info(self, week_day_name : str, box: Box):
def __find_module_info(self, week_day_name: str, box: Box):

module_name_box = list()

# Definition of outer box, which contains strings
main_box = Box([box.x0, self.__timetalbe_information.week_day_information[week_day_name][1]-self.__word_margin,
box.x1, self.__timetalbe_information.week_day_information[week_day_name][3]])
main_box = Box(
[box.x0, self.__timetalbe_information.week_day_information[week_day_name][1] - self.__word_margin,
box.x1, self.__timetalbe_information.week_day_information[week_day_name][3]])

m_name_finder_initializer = ModuleNameFinder(main_box)
m_name_finder_initializer.min_box = main_box
Expand Down Expand Up @@ -208,9 +209,9 @@ def __iterator(self, iterable: Iterable):
"""
# Iterate over PyQuery-Items
for item in self.__loader.get_file().pq('LTTextLineHorizontal:in_bbox("'
+ str(iterable.main_box.x0)+', '+str(iterable.main_box.y0)+','
+ str(iterable.main_box.x1)+', '
+ str(iterable.main_box.y1)+'")').items():
+ str(iterable.main_box.x0) + ', ' + str(iterable.main_box.y0) + ','
+ str(iterable.main_box.x1) + ', '
+ str(iterable.main_box.y1) + '")').items():
description_box = Box(RegexParser.extract_coordinates_from_bbox(item))
iterable.get_information(BoxContent(description_box, item.text()))

Expand Down
Loading