Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extensión del prototipo de GUI y primera invocacion al querier.py #27

Merged
merged 10 commits into from
Aug 12, 2023
5 changes: 5 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from gui.App import App

if __name__ == "__main__":
app = App()
app.mainloop()
12 changes: 12 additions & 0 deletions config/template_querier_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@ repos:
enabled: true
logger: 'default'

pubmed:
url: ''
apikey: WRITE YOUR API KEY HERE!
enabled: true
logger: 'default'

springer:
url: ''
apikey: WRITE YOUR API KEY HERE!
enabled: true
logger: 'default'

params:
tool-name: repository-reviewer
version: 0.1.2
Expand Down
1 change: 1 addition & 0 deletions engine/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__all__ = ["querier"]
45 changes: 45 additions & 0 deletions engine/querier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/python3
# -*- coding: utf8

import yaml
import logging
import logging.config
import traceback
from repos import *


def read_yaml(file_path):
with open(file_path, "r") as f:
return yaml.safe_load(f)


def querier(debug: bool, query: str = "", content: str = "", from_year: str = "",
to_year: str = "", title: str = "", abstract: str = "", keywords: str = "", redirect_logs = False):
print("Cargando archivo de configuración")
cfg = read_yaml("config/querier_config.yml") # TODO: Pendiente hacer chequeo de errores

if debug:
print("El debug esta habilitado")

print("Cargando clases de repositorios")
for repo in cfg['repos'].keys():
try:
# La línea siguiente invoca a la clase dentro del package.
# Ejemplo: invoca al constructor ieee() de repos.ieee_def
if cfg['repos'][repo]['enabled'] is True:
id = getattr(globals()[repo + '_def'], repo)(cfg['repos'][repo], cfg['params'], debug)
if id is not None:
id.say_hello()
if query == "" or query is None:
id.add_query_param(content, 'content')
id.add_query_param(from_year, 'from_year')
id.add_query_param(title, 'title')
id.add_query_param(to_year, 'to_year')
id.add_query_param(abstract, 'abstract')
else:
id.load_query(args.query)
id.search()
del id
except Exception:
traceback.print_exc()
print("Fin de ejecución")
139 changes: 139 additions & 0 deletions gui/App.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import customtkinter as ctk

from .history_page import HistoryPage
from .indexer_page import IndexerPage
from .log_frame import LogsFrame
from .querier_page import QuerierPage

ctk.set_appearance_mode("System") # Modes: "System" (standard), "Dark", "Light"
ctk.set_default_color_theme("blue") # Themes: "blue" (standard), "green", "dark-blue"


class App(ctk.CTk):
def __init__(self):
super().__init__()

# configure window
self.title("Repository Reviewer")
self.geometry(f"{1100}x{580}")
self.status = False

# configure grid layout (4x4)
self.grid_columnconfigure(1, weight=1)
self.grid_columnconfigure(2, weight=0)
self.grid_rowconfigure((0, 1, 2), weight=1)

# Pages
# NOTE: ver https://stackoverflow.com/questions/7546050/switch-between-two-frames-in-tkinter

container = ctk.CTkFrame(self)
# container.pack(expand=True)
container.grid(row=0, column=1, padx=(20, 20), pady=(20, 20), sticky="nsew")
container.grid_columnconfigure(0, weight=1)
container.grid_rowconfigure(0, weight=1)

self.frames = {}
for F in (QuerierPage, IndexerPage, HistoryPage):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
# put all of the pages in the same location;
# the one on the top of the stacking order
# will be the one that is visible.
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("QuerierPage")

# Results and logs
self.log_frame = LogsFrame(parent=container, controller=self)
self.log_frame.grid(row=1, column=0, sticky="nsew", pady=(10, 0))

# Sidebar
# FIXME: Intente encapsularlo pero no me gusta como quedo. Hm....
# El problema es que esto crea variables atributo que despues se usan en el propio init. No se como resolverlo
self.sidebar_frame = ctk.CTkFrame(self, width=140, corner_radius=0)
self.create_sidebar(self.sidebar_frame)

def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()

def create_sidebar(self, sidebar_frame: ctk.CTkFrame):
# create sidebar frame with widgets
sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsew")
sidebar_frame.grid_rowconfigure(5, weight=1)
logo_label = ctk.CTkLabel(sidebar_frame, text="Stages",
font=ctk.CTkFont(size=20, weight="bold"))
logo_label.grid(row=0, column=0, padx=20, pady=(20, 10))
sidebar_button_1 = ctk.CTkButton(sidebar_frame, text="Querier",
command=self.sidebar_querier_button_event)
sidebar_button_1.grid(row=1, column=0, padx=20, pady=10)
sidebar_button_2 = ctk.CTkButton(sidebar_frame, text="Quality check",
command=self.sidebar_dummy_button_event)
sidebar_button_2.grid(row=2, column=0, padx=20, pady=10)
sidebar_button_3 = ctk.CTkButton(sidebar_frame, text="Indexer",
command=self.sidebar_indexer_button_event)
sidebar_button_3.grid(row=3, column=0, padx=20, pady=10)
sidebar_button_4 = ctk.CTkButton(sidebar_frame, text="History",
command=self.sidebar_history_button_event)
sidebar_button_4.grid(row=4, column=0, padx=20, pady=10)

show_logs_checkbox = self.log_frame.Get_enabling_checkBox(sidebar_frame)
show_logs_checkbox.grid(row=5, column=0, padx=20, pady=(15, 0))

appearance_mode_label = ctk.CTkLabel(sidebar_frame, text="Appearance Mode:", anchor="w")
appearance_mode_label.grid(row=7, column=0, padx=20, pady=(10, 0))
appearance_mode_optionemenu = ctk.CTkOptionMenu(sidebar_frame,
values=["Light", "Dark", "System"],
command=self.change_appearance_mode_event)
appearance_mode_optionemenu.grid(row=8, column=0, padx=20, pady=(10, 10))
scaling_label = ctk.CTkLabel(sidebar_frame, text="UI Scaling:", anchor="w")
scaling_label.grid(row=9, column=0, padx=20, pady=(10, 0))
scaling_optionemenu = ctk.CTkOptionMenu(sidebar_frame,
values=["80%", "90%", "100%", "110%", "120%"],
command=self.change_scaling_event)
scaling_optionemenu.grid(row=10, column=0, padx=20, pady=(10, 20))

# set default values
sidebar_button_2.configure(state="disabled")
appearance_mode_optionemenu.set("System")
scaling_optionemenu.set("100%")

def open_input_dialog_event(self):
dialog = ctk.CTkInputDialog(text="Type in a number:", title="CTkInputDialog")
print("CTkInputDialog:", dialog.get_input())

def change_appearance_mode_event(self, new_appearance_mode: str):
ctk.set_appearance_mode(new_appearance_mode)

def change_scaling_event(self, new_scaling: str):
new_scaling_float = int(new_scaling.replace("%", "")) / 100
ctk.set_widget_scaling(new_scaling_float)

def sidebar_dummy_button_event(self):
print("dummy function wip")
pass

def sidebar_querier_button_event(self):
# FIXME: Esto es solo un botón de juguete para probar funcionalidades
print("QUERIER BUTOOTN click")
self.show_frame("QuerierPage")
# if self.status == False:
# print(f'status is {self.status}')
# self.checkbox_slider_frame.destroy()
# self.slider_progressbar_frame._draw()
# self.status = True
# else:
# print(f'status is {self.status}')
# self.slider_progressbar_frame.destroy()
# self.status = False

def sidebar_indexer_button_event(self):
# FIXME: Esto es solo un botón de juguete para probar funcionalidades
print("INDEXER BUTOOTN click")
self.show_frame("IndexerPage")

def sidebar_history_button_event(self):
# FIXME: Esto es solo un botón de juguete para probar funcionalidades
print("HISTORY BUTOOTN click")
self.show_frame("HistoryPage")
1 change: 1 addition & 0 deletions gui/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__all__ = ["App.py", "history_page", "indexer_page", "log_frame", "misc", "querier_page"]
18 changes: 18 additions & 0 deletions gui/history_page.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

import customtkinter as ctk


class HistoryPage(ctk.CTkFrame):
def __init__(self, parent, controller):
ctk.CTkFrame.__init__(self, parent)
self.controller = controller
label = ctk.CTkLabel(self, text="This is History Page")
label.pack(side="top", fill="x", pady=10)
button = ctk.CTkButton(self, text="Go to the start page",
command=self.dummy_action)
button.pack()

def dummy_action(self):
print("dummy function wip")
pass

17 changes: 17 additions & 0 deletions gui/indexer_page.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import customtkinter as ctk


class IndexerPage(ctk.CTkFrame):
def __init__(self, parent, controller):
ctk.CTkFrame.__init__(self, parent)
self.controller = controller
label = ctk.CTkLabel(self, text="This is Indexer Page")
label.pack(side="top", fill="x", pady=10)
button = ctk.CTkButton(self, text="Go to the start page",
command=self.dummy_action)
button.pack()

def dummy_action(self):
print("dummy function wip")
pass

31 changes: 31 additions & 0 deletions gui/log_frame.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import customtkinter as ctk
from .misc import StdoutRedirector


class LogsFrame(ctk.CTkFrame):
PADX = 20
def __init__(self, parent, controller):
ctk.CTkFrame.__init__(self, parent)
self.controller = controller
self.logs_lbl = ctk.CTkLabel(self, text="Results and logs", anchor="w", font=ctk.CTkFont(weight="bold"))
self.logs_lbl.pack(side="top", padx=LogsFrame.PADX, pady=(10,0))
self.logs_box = ctk.CTkTextbox(self, width=2000, height=150, activate_scrollbars=True)
self.logs_box.pack(side="top", padx=LogsFrame.PADX, pady=(10, 20))
self.logs_box.configure(state="disabled")
self.show_logs_checkbox = None
self.stdout_redirector = StdoutRedirector(self.logs_box)

def Get_enabling_checkBox(self, parent) -> ctk.CTkCheckBox:
if (self.show_logs_checkbox is None):
self.show_logs_checkbox = ctk.CTkCheckBox(parent, text="Show results and logs", command=self._checkbox_event)
if bool(self.grid_info()): # This method led to know if the widget is visible now and so then syncronise the checkbox
self.show_logs_checkbox.select()
return self.show_logs_checkbox

def _checkbox_event(self):
value = self.show_logs_checkbox.get()
# Redirect the standar output between default stdout and self.logs_box
self.stdout_redirector.enable( value )
# Handle visibility on the front
self.grid() if value else self.grid_remove()
print("_checkbox_event( view_enabled={} )".format(value))
65 changes: 65 additions & 0 deletions gui/misc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import sys
import subprocess
import customtkinter as ctk
from typing import TextIO


class StdoutRedirector(TextIO):
def __init__(self,text_widget: ctk.CTkTextbox):
self._text_space = text_widget
#self._text_space.tag_config(tagName='ERROR', background="black", foreground="red")
self._default_stdout = None
self.enable()

def write(self, string):
# FIXME: Next line would be preffered to keep config after writing but get next incoherent exception
# ValueError: 'state' is not a supported argument. Look at the documentation for supported arguments.
# prev_state = self._text_space.cget("state")
self._text_space.configure(state="normal")
#try:
# # FIXME: No aplica el tag. De todas formas este codigo no se lo deseo ni a mi peor enemigo, hay que mejorar esta abominacion
# start_idx = string.index(bcolors.FAIL)
# string = string.replace(bcolors.FAIL,"")
# end_idx = string.index(bcolors.ENDC)
# string = string.replace(bcolors.ENDC,"")
# self._text_space.insert('end', string)
# self._text_space.tag_add(tagName='ERROR', index1=int(start_idx), index2=int(end_idx))
#except:
# pass
self._text_space.insert('end', string)
self._text_space.see('end')
#self._text_space.configure(prev_state)
self._text_space.configure(state="disabled")

def enable(self, on:bool=True):
if on:
self._default_stdout = sys.stdout
sys.stdout = self
else:
sys.stdout = self._default_stdout
self._enabled = on

def disable(self):
self.enable(False)


class bcolors:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKCYAN = '\033[96m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'


def execute(cmd) -> int:
#proc = subprocess.Popen( "python querier.py -h".split(), text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
#print( proc.stdout.read() )
proc = subprocess.Popen( cmd.split(), text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE )
out, err = proc.communicate()
if len(out) > 0: print( out )
if len(err) > 0: print( bcolors.FAIL + err + bcolors.ENDC ) # print in red
return proc.returncode
Loading