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

modifying behavior of login window #256

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions dtool_lookup_gui/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def do_activate(self):
# self.window = AppWindow(application=self, title="Main Window")
logger.debug("Build GUI.")

win = LoginWindow(application=self)
win = MainWindow(application=self)
glob_pattern = os.path.join(os.path.dirname(__file__), os.pardir, 'data','icons','*','dtool_logo.xpm')
icon_file_list = glob.glob(glob_pattern)
if len(icon_file_list) > 0:
Expand All @@ -114,7 +114,7 @@ def do_activate(self):
else:
logger.warning("Could not load app icons.")
win.connect('destroy', lambda _: self.loop.stop())
#self.loop.call_soon(win.refresh) # Populate widgets after event loop starts
self.loop.call_soon(win.refresh) # Populate widgets after event loop starts

logger.debug("Present main window.")
win.present()
Expand Down
41 changes: 15 additions & 26 deletions dtool_lookup_gui/views/login_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@
# Initialize logging
logger = logging.getLogger(__name__)

# Define the LoginWindow class and associate it with its corresponding UI file
@Gtk.Template(filename=f'{os.path.dirname(__file__)}/login_window.ui')
class LoginWindow(Gtk.ApplicationWindow):
class LoginWindow(Gtk.Window):
__gtype_name__ = 'LoginWindow'

# Map GTK Template Child widgets to Python attributes
Expand All @@ -23,16 +22,25 @@ class LoginWindow(Gtk.ApplicationWindow):
settings_button = Gtk.Template.Child()

# Initialize the LoginWindow instance
def __init__(self, *args, **kwargs):
def __init__(self, follow_up_action=None, *args, **kwargs):
super().__init__(*args, **kwargs)
self.application = self.get_application()
self.settings_dialog = SettingsDialog(application=self.application)
self._follow_up_action = follow_up_action

# Set the default values from the Config, ensuring they are not None
if Config.username is not None:
self.username_entry.set_text(Config.username)
if Config.password is not None: # Consider security implications
self.password_entry.set_text(Config.password)



# Handle the 'Login' button click event
@Gtk.Template.Callback()
def on_login_button_clicked(self, widget):
# Import MainWindow class to create an instance after successful login
from .main_window import MainWindow



# Fetch entered username and password
username = self.username_entry.get_text()
Expand All @@ -48,33 +56,14 @@ def on_login_button_clicked(self, widget):
# Trigger the 'renew-token' action for authentication
self.get_action_group("app").activate_action('renew-token', user_pass_auth_variant)

# Create and display the main window
main_win = MainWindow(application=self.get_application())
main_win.show()
if self._follow_up_action is not None:
self._follow_up_action()

# Trigger the 'refresh-view' action in the main window
action_group = main_win.get_action_group("win")
if action_group:
action_group.activate_action('refresh-view', None)

# Close the login window
self.close()

# Handle the 'Skip' button click event
@Gtk.Template.Callback()
def on_skip_button_clicked(self, widget):
# Import MainWindow to switch to it when 'Skip' is clicked
from .main_window import MainWindow

# Create and display the main window
main_win = MainWindow(application=self.get_application())
main_win.show()

# Trigger the 'refresh-view' action in the main window
action_group = main_win.get_action_group("win")
if action_group:
action_group.activate_action('refresh-view', None)

# Close the login window
self.close()

Expand Down
2 changes: 1 addition & 1 deletion dtool_lookup_gui/views/login_window.ui
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.24"/>
<template class="LoginWindow" parent="GtkApplicationWindow">
<template class="LoginWindow" parent="GtkWindow">
<property name="can-focus">False</property>
<property name="default-width">400</property>
<property name="default-height">300</property>
Expand Down
34 changes: 16 additions & 18 deletions dtool_lookup_gui/views/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,6 @@ class MainWindow(Gtk.ApplicationWindow):

search_entry = Gtk.Template.Child()

# copy_dataset_spinner = Gtk.Template.Child()

base_uri_list_box = Gtk.Template.Child()
dataset_list_box = Gtk.Template.Child()

Expand Down Expand Up @@ -202,10 +200,8 @@ def __init__(self, *args, **kwargs):
self.log_window = LogWindow(application=self.application)
self.settings_dialog = SettingsDialog(application=self.application)
self.about_dialog = AboutDialog(application=self.application)
self.server_versions_dialog = ServerVersionsDialog(application=self.application)

demo_server_versions = 1
self.server_versions_dialog = ServerVersionsDialog(server_versions=demo_server_versions)
self.login_window = LoginWindow(application=self.application)
# window-scoped actions

# search action
Expand Down Expand Up @@ -328,18 +324,11 @@ def contents_per_page_changed(self, widget):
self.contents_per_page_value = widget.get_active_text()
self.on_first_page_button_clicked(self.first_page_button) # Directly call the method





async def _fetch_search_results(self, keyword, on_show=None, page_number=1, page_size=10,widget=None):
async def _fetch_search_results(self, keyword, on_show=None, page_number=1, page_size=10, widget=None):
row = self.base_uri_list_box.search_results_row
row.start_spinner()
self.main_spinner.start()




self.pagination = {} # Add pagination dictionary
try:
if keyword:
Expand Down Expand Up @@ -367,7 +356,6 @@ async def _fetch_search_results(self, keyword, on_show=None, page_number=1, page
pagination=self.pagination
)


if len(datasets) > self._max_nb_datasets:
_logger.warning(
f"{len(datasets)} search results exceed allowed displayed maximum of {self._max_nb_datasets}. "
Expand All @@ -382,6 +370,20 @@ async def _fetch_search_results(self, keyword, on_show=None, page_number=1, page
if self.base_uri_list_box.get_selected_row() == row:
# Only update if the row is still selected
self.dataset_list_box.fill(datasets, on_show=on_show)
except RuntimeError as e:
# TODO: There should probably be a more explicit test on authentication failure.
self.show_error(e)

async def retry():
await asyncio.sleep(1) # TODO: This is a dirty workaround for not having the login window pop up twice
await self._fetch_search_results(keyword, on_show, page_number, page_size, widget)

# What happens is that the LoginWindow evokes the renew-token action via Gtk framework.
# This happens asynchronously as well. This means _fetch_search_results called again
# within the retry() function would open another LoginWindow here as the token renewal does
# not happen "quick" enough. Hence there is the asybcio.sleep(1).
LoginWindow(application=self.application, follow_up_action=lambda: asyncio.create_task(retry())).show()

except Exception as e:
self.show_error(e)

Expand Down Expand Up @@ -480,10 +482,6 @@ def _select_base_uri_row_by_uri(self, uri):
index = self.base_uri_list_box.get_row_index_from_uri(uri)
self._select_base_uri_row_by_row_index(index)

# def _show_base_uri(self, dataset):
# asyncio.create_task(self._update_dataset_view(dataset))
# self.dataset_stack.set_visible_child(self.dataset_box)

# actions

# dataset selection actions
Expand Down
36 changes: 27 additions & 9 deletions dtool_lookup_gui/views/server_versions_dialog.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,52 @@
import asyncio
import logging
import os

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gio, GLib, Gtk

gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from dtool_lookup_api.asynchronous import versions
from ..utils.logging import _log_nested


# Set up logger for this module
logger = logging.getLogger(__name__)


@Gtk.Template(filename=f'{os.path.dirname(__file__)}/server_versions_dialog.ui')
class ServerVersionsDialog(Gtk.Window):
__gtype_name__ = 'ServerVersionsDialog'

server_versions_label = Gtk.Template.Child()

def __init__(self, server_versions, *args, **kwargs):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

# Apply margins to the server versions label for better aesthetics
self.server_versions_label.set_margin_start(10)
self.server_versions_label.set_margin_end(10)
self.server_versions_label.set_margin_top(10)
self.server_versions_label.set_margin_bottom(10)

async def _retrieve_versions(self):
"""Asynchronously fetch server versions and update the label with formatted information."""
server_versions = await versions()
version_info = self._format_server_versions(server_versions)
_log_nested(logger.info, version_info)
self.server_versions_label.set_markup(version_info)

def _format_server_versions(self, server_versions):
# Just return a placeholder string instead of formatting actual data
return "<b>Server Versions:</b>\nComponent1: 1.0\nComponent2: 2.0\n"
"""Format server versions, sorting components by name length."""
sorted_components = sorted(server_versions.keys(), key=len)

# Use list comprehension for concise formatting of server versions
formatted_versions = [f"{component}: <b>{server_versions[component]}</b>" for component in sorted_components]
return "\n".join(formatted_versions)

@Gtk.Template.Callback()
def on_show(self, widget):
"""Callback executed when the window is shown; fetches server versions."""
asyncio.create_task(self._retrieve_versions())

@Gtk.Template.Callback()
def on_delete(self, widget, event):
"""Don't delete, just hide."""
"""Callback executed when window close event is triggered; hides the window instead of deleting."""
return self.hide_on_delete()
1 change: 1 addition & 0 deletions dtool_lookup_gui/views/server_versions_dialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<property name="resizable">False</property>
<property name="modal">True</property>
<signal name="delete-event" handler="on_delete" swapped="no"/>
<signal name="show" handler="on_show" swapped="no"/>
<child>
<object class="GtkBox">
<property name="visible">True</property>
Expand Down
2 changes: 0 additions & 2 deletions dtool_lookup_gui/views/settings_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,6 @@ def on_delete(self, widget, event):

@Gtk.Template.Callback()
def on_renew_token_clicked(self, widget):

# show authentication dialogue and get username and password
def authenticate(username, password):
auth_url = self.authenticator_url_entry.get_text()
Expand All @@ -216,7 +215,6 @@ def authenticate(username, password):

AuthenticationDialog(authenticate, Config.username, Config.password).show()


@Gtk.Template.Callback()
def on_reset_config_clicked(self, widget):
"""Process clicked signal from reset-config button."""
Expand Down
Loading