2018-10-24 05:32:26 +00:00
#!/usr/bin/env python3
import tkinter as tk
2018-11-03 16:24:38 +00:00
import tkinter . simpledialog as dialog
2018-11-18 16:43:36 +00:00
from tkinter . filedialog import asksaveasfilename as savedialog
2018-10-24 05:32:26 +00:00
from connect import connect as conn
from parser import parser
import time
import sys
import json
import os . path
2018-10-26 03:30:07 +00:00
from io import BytesIO
from PIL import Image , ImageTk
2018-10-30 02:19:03 +00:00
import webbrowser as wb
2018-10-24 05:32:26 +00:00
class GUI :
def __init__ ( self ) :
self . history = [ ]
self . history_location = - 1
self . message_bar_content = ' '
self . read_config ( )
self . conn = conn ( )
self . parser = parser ( )
2018-11-03 03:48:40 +00:00
self . search = None
2018-10-24 05:32:26 +00:00
#colors
2018-10-27 22:33:01 +00:00
self . FG = ' #E0E2E4 '
self . BG = ' #2F393C '
self . LINK = ' #E8E2B7 '
2018-11-10 04:03:43 +00:00
self . FLINK = ' #93C763 '
2018-10-27 22:33:01 +00:00
self . ACTIVELINK = ' #678CB1 '
self . HLB = ' #804000 '
2018-11-10 23:48:08 +00:00
self . HLF = self . FG
2018-10-27 22:33:01 +00:00
self . STATUS_BG = ' #293134 '
self . STATUS_FG = ' #FFCD22 '
2018-11-10 04:03:43 +00:00
self . ERROR = ' #EC7600 '
2018-11-10 23:48:08 +00:00
self . BAR_BG = self . STATUS_BG
self . BAR_FG = self . BG
self . BAR_HLB = self . HLB
self . BAR_HLF = self . FG
self . BAR_SLOT = self . FG
2018-10-27 22:33:01 +00:00
self . SCROLL = ' #434A57 '
self . TYPES = ' #A082BD '
2018-11-10 23:48:08 +00:00
self . MENU_BG = self . BAR_BG
self . MENU_FG = self . FG
self . MENU_HLB = self . LINK
self . MENU_HLF = self . BAR_BG
2018-10-24 05:32:26 +00:00
2018-12-05 03:49:04 +00:00
#configure root window
2018-10-30 02:19:03 +00:00
self . root = tk . Tk ( className = ' Burrow ' )
self . root . title ( ' Burrow ' )
2018-11-08 07:04:34 +00:00
sh = self . root . winfo_screenheight ( )
sw = self . root . winfo_screenwidth ( )
w = int ( sw * 0.7 )
h = sh - 200
self . root . geometry ( " {} x {} + {} + {} " . format ( w , h , sw / / 2 - w / / 2 , 50 ) )
2018-10-24 05:32:26 +00:00
self . add_assets ( )
#main frame objects
2018-10-27 22:33:01 +00:00
self . top_bar = tk . Frame ( self . root , padx = 10 , height = 50 , relief = tk . FLAT , bd = 2 , bg = self . BAR_BG )
self . body = tk . Frame ( self . root , relief = tk . FLAT , bd = 0 , bg = self . BG )
self . status_bar = tk . Frame ( self . root , height = " 20 " , relief = tk . FLAT , bg = self . STATUS_BG , takefocus = 0 )
2018-10-24 05:32:26 +00:00
#top bar objects
2018-10-27 22:33:01 +00:00
self . btn_back = tk . Button ( self . top_bar , image = self . img_back , bd = 0 , highlightthickness = 0 , takefocus = 1 , bg = self . BAR_BG )
self . btn_forward = tk . Button ( self . top_bar , image = self . img_forward , bd = 0 , highlightthickness = 0 , bg = self . BAR_BG )
self . btn_favorite = tk . Button ( self . top_bar , image = self . img_favorite , bd = 0 , highlightthickness = 0 , bg = self . BAR_BG )
self . btn_home = tk . Button ( self . top_bar , image = self . img_home , bd = 0 , highlightthickness = 0 , bg = self . BAR_BG )
self . entry_url = tk . Entry ( self . top_bar , selectbackground = self . HLB , selectforeground = self . HLF , highlightcolor = self . FG , highlightbackground = self . BAR_BG , fg = self . BAR_FG , bg = self . BAR_SLOT )
self . btn_menu = tk . Button ( self . top_bar , image = self . img_menu , bd = 0 , highlightthickness = 0 , bg = self . BAR_BG )
2018-10-24 05:32:26 +00:00
#body objects
2018-10-27 22:33:01 +00:00
self . scroll_bar = tk . Scrollbar ( self . body , bg = self . BAR_BG , bd = 0 , highlightthickness = 0 , troughcolor = self . BG , activebackground = self . SCROLL , activerelief = tk . RAISED )
2018-12-08 00:14:44 +00:00
self . site_display = tk . Text ( self . body , bg = self . BG , foreground = self . FG , padx = 20 , pady = 20 , wrap = tk . WORD , state = tk . DISABLED , spacing2 = 2 , spacing1 = 2 , spacing3 = 2 , yscrollcommand = self . scroll_bar . set , highlightcolor = self . BG , highlightbackground = self . BAR_BG , relief = tk . FLAT , font = " TkFixedFont " )
2018-10-24 05:32:26 +00:00
self . scroll_bar . config ( command = self . site_display . yview , width = 20 , relief = tk . RIDGE )
2018-10-25 03:17:36 +00:00
self . site_display . tag_configure ( ' linkcolor ' , foreground = self . LINK , spacing1 = 5 , spacing2 = 5 , spacing3 = 5 )
2018-11-10 04:03:43 +00:00
self . site_display . tag_configure ( ' favoritecolor ' , foreground = self . FLINK , spacing1 = 5 , spacing2 = 5 , spacing3 = 5 )
2018-10-27 22:33:01 +00:00
self . site_display . tag_configure ( ' type_tag ' , background = self . BG , foreground = self . TYPES , spacing2 = 1 , spacing1 = 1 , spacing3 = 1 )
2018-10-24 05:32:26 +00:00
self . site_display . tag_configure ( ' error_text ' , foreground = self . ERROR , spacing1 = 5 , spacing2 = 5 , spacing3 = 5 )
#status bar objects
2018-10-27 22:33:01 +00:00
self . status_info = tk . Label ( self . status_bar , textvariable = self . message_bar_content , bg = self . STATUS_BG , takefocus = 0 , fg = self . ACTIVELINK )
2018-10-24 05:32:26 +00:00
2018-11-09 04:25:27 +00:00
#menu objects
2018-11-10 23:48:08 +00:00
self . context_menu = tk . Menu ( self . body , tearoff = 0 , bg = self . MENU_BG , fg = self . MENU_FG , activebackground = self . MENU_HLB , activeforeground = self . MENU_HLF , activeborderwidth = 0 )
2018-11-09 04:25:27 +00:00
2018-10-24 05:32:26 +00:00
self . pack_geometry ( )
self . add_status_titles ( )
self . add_event_listeners ( )
#load the home screen
2018-10-25 03:17:36 +00:00
self . load_home_screen ( 1 )
2018-10-24 05:32:26 +00:00
2018-11-18 16:43:36 +00:00
2018-10-24 05:32:26 +00:00
#-----------Start GUI configuration-----------------------
2018-11-18 16:43:36 +00:00
2018-10-24 05:32:26 +00:00
def add_event_listeners ( self ) :
buttons = [
self . btn_back ,
self . btn_forward ,
self . btn_favorite ,
self . btn_home ,
self . btn_menu
]
for x in buttons :
x . bind ( ' <Enter> ' , self . update_status )
x . bind ( ' <Leave> ' , self . clear_status )
2018-10-27 22:33:01 +00:00
x . config ( activebackground = self . BG )
2018-11-02 05:44:48 +00:00
self . entry_url . bind ( ' <Return> ' , self . handle_request )
2018-11-10 23:48:08 +00:00
self . btn_back . bind ( ' <ButtonRelease-1> ' , self . go_back )
self . btn_forward . bind ( ' <ButtonRelease-1> ' , self . go_forward )
self . btn_home . bind ( ' <ButtonRelease-1> ' , self . load_home_screen )
2018-10-24 05:32:26 +00:00
self . site_display . bind ( " <Up> " , lambda event : self . site_display . yview_scroll ( - 1 , ' units ' ) )
self . site_display . bind ( " <Down> " , lambda event : self . site_display . yview_scroll ( 1 , ' units ' ) )
self . site_display . bind ( " <Button-1> " , lambda event : self . site_display . focus_set ( ) )
2019-12-09 05:37:43 +00:00
self . site_display . bind ( " k " , lambda event : self . site_display . yview_scroll ( - 1 , ' units ' ) )
self . site_display . bind ( " j " , lambda event : self . site_display . yview_scroll ( 1 , ' units ' ) )
self . site_display . bind ( " h " , self . go_back )
self . site_display . bind ( " l " , self . go_forward )
2018-10-24 05:32:26 +00:00
self . entry_url . bind ( " <Button-1> " , lambda event : self . entry_url . focus_set ( ) )
self . root . protocol ( ' WM_DELETE_WINDOW ' , self . close_window )
2018-11-03 16:24:38 +00:00
self . btn_favorite . bind ( " <Button-1> " , self . add_to_favorites )
2018-11-10 23:48:08 +00:00
self . site_display . tag_bind ( ' generic_r_click ' , " <Button-3> " , ( lambda event , href = None : self . show_context_menu ( event , href ) ) )
2018-10-24 05:32:26 +00:00
def pack_geometry ( self ) :
self . top_bar . pack ( expand = False , fill = tk . BOTH , side = tk . TOP , anchor = tk . NW )
self . top_bar . pack_propagate ( False )
self . body . pack ( expand = True , fill = tk . BOTH , side = tk . TOP )
self . status_bar . pack ( expand = False , fill = tk . X , side = tk . TOP , anchor = tk . SW )
self . btn_back . pack ( side = tk . LEFT , padx = ( 0 , 20 ) )
self . btn_forward . pack ( side = tk . LEFT , padx = ( 0 , 20 ) )
self . btn_home . pack ( side = tk . LEFT , padx = ( 0 , 20 ) )
2018-10-27 22:33:01 +00:00
self . entry_url . pack ( side = tk . LEFT , fill = tk . X , expand = True , ipady = 5 , ipadx = 10 )
2018-10-24 05:32:26 +00:00
self . btn_favorite . pack ( side = tk . LEFT , padx = ( 10 , 10 ) )
self . btn_menu . pack ( side = tk . LEFT )
self . scroll_bar . pack ( side = tk . RIGHT , fill = tk . Y )
self . site_display . pack ( expand = True , side = tk . TOP , fill = tk . BOTH )
self . status_info . pack ( side = tk . LEFT )
def add_status_titles ( self ) :
self . btn_back . pop_title = ' Back '
self . btn_forward . pop_title = ' Forward '
self . btn_favorite . pop_title = ' Favorite '
self . btn_home . pop_title = ' Home '
self . btn_menu . pop_title = ' Menu '
def add_assets ( self ) :
2018-11-18 17:58:08 +00:00
back = Image . open ( ' ./images/back.png ' )
self . img_back = ImageTk . PhotoImage ( back )
forward = Image . open ( ' ./images/forward.png ' )
self . img_forward = ImageTk . PhotoImage ( forward )
favorite = Image . open ( ' ./images/favorite.png ' )
self . img_favorite = ImageTk . PhotoImage ( favorite )
home = Image . open ( ' ./images/home.png ' )
self . img_home = ImageTk . PhotoImage ( home )
settings = Image . open ( ' ./images/settings.png ' )
self . img_menu = ImageTk . PhotoImage ( settings )
2018-10-24 05:32:26 +00:00
self . message_bar_content = tk . StringVar ( )
self . message_bar_content . set ( ' Ready. ' )
2018-11-10 23:48:08 +00:00
def show_context_menu ( self , e , href = None ) :
2018-11-18 16:43:36 +00:00
current_page = self . entry_url . get ( )
2018-11-10 04:03:43 +00:00
self . context_menu . delete ( 0 , 20 )
2018-11-10 23:48:08 +00:00
#add navigation options
2018-11-18 16:43:36 +00:00
if len ( self . history ) > 1 and self . history_location > 0 :
2018-11-10 23:48:08 +00:00
back = ( lambda event = e : self . go_back ( event ) )
2018-11-18 16:43:36 +00:00
self . context_menu . add_command ( label = " Back " , command = back )
else :
self . context_menu . add_command ( label = " Back " , state = tk . DISABLED )
if len ( self . history ) > 1 and self . history_location < len ( self . history ) - 1 :
2018-11-10 23:48:08 +00:00
forward = ( lambda event = e : self . go_forward ( event ) )
2018-11-18 16:43:36 +00:00
self . context_menu . add_command ( label = " Forward " , command = forward )
else :
self . context_menu . add_command ( label = " Forward " , state = tk . DISABLED )
refresh = ( lambda event = e , link = current_page : self . handle_request ( event , link , False ) )
self . context_menu . add_command ( label = " Refresh " , command = refresh )
if current_page != ' home ' :
2018-11-10 23:48:08 +00:00
home = ( lambda event = e : self . load_home_screen ( event ) )
2018-11-18 16:43:36 +00:00
self . context_menu . add_command ( label = " Home " , command = home )
else :
self . context_menu . add_command ( label = " Home " , state = tk . DISABLED )
save_as_file = ( lambda data = self . site_display . get ( 1.0 , tk . END ) , url = current_page : self . write_to_file ( data , url ) )
self . context_menu . add_command ( label = " Save as... " , command = save_as_file )
2018-11-10 23:48:08 +00:00
if href :
2018-11-18 16:43:36 +00:00
self . context_menu . add_separator ( )
2018-11-10 23:48:08 +00:00
copy_link = ( lambda link = href : self . copy_to_clipboard ( link ) )
2018-11-18 16:43:36 +00:00
self . context_menu . add_command ( label = " Copy URL to clipboard " , command = copy_link )
2018-11-10 23:48:08 +00:00
if self . is_favorite ( href ) :
2018-11-18 16:43:36 +00:00
self . context_menu . add_separator ( )
2018-11-10 23:48:08 +00:00
delete_favorite = ( lambda event = e , link = href : self . remove_favorite ( event , link ) )
2018-11-18 16:43:36 +00:00
self . context_menu . add_command ( label = " Delete from favorites " , command = delete_favorite )
2018-11-10 23:48:08 +00:00
rename_favorite = ( lambda event = e , link = href : self . rename_favorite ( event , link ) )
2018-11-18 16:43:36 +00:00
self . context_menu . add_command ( label = " Rename this favorite " , command = rename_favorite )
2018-11-10 23:48:08 +00:00
elif href :
2018-11-18 16:43:36 +00:00
self . context_menu . add_separator ( )
2018-11-10 23:48:08 +00:00
add_favorite = ( lambda event = e , link = href : self . add_to_favorites ( event , link ) )
2018-11-18 16:43:36 +00:00
self . context_menu . add_command ( label = " Add to favorites " , command = add_favorite )
2018-11-10 04:03:43 +00:00
self . context_menu . tk_popup ( e . x_root , e . y_root )
2018-11-10 23:48:08 +00:00
def copy_to_clipboard ( self , text ) :
2018-11-10 04:03:43 +00:00
self . root . clipboard_clear ( )
self . root . clipboard_append ( text )
2018-11-09 04:25:27 +00:00
2018-12-05 03:49:04 +00:00
# ------------Start navigation methods---------------------------
2018-10-24 05:32:26 +00:00
2018-11-18 16:43:36 +00:00
2018-11-02 05:44:48 +00:00
def handle_request ( self , event = False , url = False , history = True ) :
2018-11-05 06:04:15 +00:00
self . loading_bar = tk . Label ( self . entry_url , text = ' Loading... ' , width = 12 , relief = tk . FLAT , height = 1 , fg = ' #FFFFFF ' , bg = self . TYPES )
self . loading_bar . pack ( side = tk . RIGHT , padx = ( 0 , 10 ) )
self . loading_bar . update_idletasks ( )
2018-11-05 01:20:51 +00:00
2018-11-03 04:00:48 +00:00
url = url if url else self . entry_url . get ( )
2018-11-02 05:44:48 +00:00
parsed_url = self . parse_url ( url )
2018-11-03 04:00:48 +00:00
2018-11-02 05:44:48 +00:00
if not parsed_url :
if url == ' home ' :
return self . load_home_screen ( history )
else :
2018-11-10 04:03:43 +00:00
data = { ' type ' : ' 3 ' , ' body ' : ' 3ERROR: Improperly formatted URL \t false \t null.host \t 1 \n ' }
2018-12-05 03:49:04 +00:00
# return False
elif parsed_url [ ' protocol ' ] == ' http:// ' :
wb . open ( url , 2 , True )
self . populate_url_bar ( self . history [ - 1 ] )
self . loading_bar . destroy ( )
return False
2018-10-24 05:32:26 +00:00
2018-11-03 03:48:40 +00:00
self . populate_url_bar ( url )
if history :
self . add_to_history ( url )
2018-12-05 03:49:04 +00:00
if parsed_url and parsed_url [ ' type ' ] == ' 7 ' :
2018-11-03 03:48:40 +00:00
self . show_search ( )
2018-11-02 05:44:48 +00:00
return False # display search
2018-11-10 04:03:43 +00:00
elif not parsed_url :
2018-12-05 03:49:04 +00:00
data = { ' type ' : ' 3 ' , ' body ' : ' 3ERROR: Improperly formatted URL \t false \t null.host \t 1 \n ' }
2018-11-02 05:44:48 +00:00
else :
data = self . execute_address ( parsed_url )
2018-11-05 06:04:15 +00:00
self . send_to_screen ( data [ ' body ' ] , data [ ' type ' ] )
2018-11-02 05:44:48 +00:00
2018-11-03 04:00:48 +00:00
def parse_url ( self , url = False ) :
2018-10-24 05:32:26 +00:00
parsed_url = self . parser . parse_url ( url )
if not parsed_url :
return False
2018-11-02 05:44:48 +00:00
return parsed_url
2018-10-30 02:19:03 +00:00
2018-10-27 22:33:01 +00:00
2018-11-02 05:44:48 +00:00
def execute_address ( self , url ) :
response = self . conn . request ( url [ ' resource ' ] , url [ ' host ' ] , url [ ' type ' ] , url [ ' port ' ] )
2018-10-24 05:32:26 +00:00
if not response :
2018-11-02 05:44:48 +00:00
# send error to screen
2019-02-06 02:43:16 +00:00
print ( ' ERROR in execute address... ' )
2018-10-24 05:32:26 +00:00
return False
# Get the data to the screen
self . site_display . focus_set ( )
self . config [ " last_viewed " ] = url
2018-11-05 06:04:15 +00:00
return response
2018-10-24 05:32:26 +00:00
2018-10-25 02:53:42 +00:00
def add_to_history ( self , url ) :
self . history = self . history [ : self . history_location + 1 ]
self . history . append ( url )
self . history_location = len ( self . history ) - 1
2018-10-24 05:32:26 +00:00
def gotolink ( self , event , href , tag_name ) :
2018-12-28 06:35:23 +00:00
if href . find ( ' URL: ' ) > = 0 :
href = href . split ( ' URL: ' ) [ 1 ]
2018-10-30 02:19:03 +00:00
wb . open ( href , 2 , True )
return True
2018-10-24 05:32:26 +00:00
element = event . widget
element . tag_config ( tag_name , background = self . ACTIVELINK )
element . update_idletasks ( ) # make sure change is visible
time . sleep ( .5 ) # optional delay to show changed text
element . tag_config ( tag_name , background = self . BG ) # restore tag text style
element . update_idletasks ( )
2018-11-02 05:44:48 +00:00
self . handle_request ( False , href )
2018-10-24 05:32:26 +00:00
2018-11-02 05:44:48 +00:00
def load_home_screen ( self , event = False ) :
2018-10-24 05:32:26 +00:00
with open ( ' ./home.gopher ' , ' r ' ) as f :
data = f . read ( )
self . entry_url . delete ( 0 , tk . END )
self . entry_url . insert ( tk . END , ' home ' )
2018-11-03 03:48:40 +00:00
if event :
2018-10-25 02:53:42 +00:00
self . add_to_history ( ' home ' )
2018-11-08 07:04:34 +00:00
data2 = self . load_favorites ( )
link_count = self . send_to_screen ( data , ' 1 ' , True )
2018-11-09 04:25:27 +00:00
self . send_to_screen ( data2 , ' 1 ' , False )
2018-10-24 05:32:26 +00:00
def go_back ( self , event ) :
2018-10-25 02:53:42 +00:00
if len ( self . history ) < = 1 or self . history_location < = 0 :
2018-10-24 05:32:26 +00:00
return False
self . history_location - = 1
href = self . history [ self . history_location ]
2018-11-02 05:44:48 +00:00
self . handle_request ( False , href , False )
2018-10-24 05:32:26 +00:00
def go_forward ( self , event ) :
2018-10-25 02:53:42 +00:00
if len ( self . history ) < = 1 or self . history_location > = len ( self . history ) - 1 :
2018-10-24 05:32:26 +00:00
return False
self . history_location + = 1
href = self . history [ self . history_location ]
2018-11-02 05:44:48 +00:00
self . handle_request ( False , href , False )
2018-10-24 05:32:26 +00:00
#-------------Start view methods----------------
def load_favorites ( self ) :
2018-11-03 16:24:38 +00:00
header = ' '
2018-10-24 05:32:26 +00:00
#soon add code to load in favorites here
2018-11-03 16:24:38 +00:00
for x in self . config [ " favorites " ] :
url = self . parser . parse_url ( x [ " url " ] )
if not url :
continue
entry = ' {} {} \t {} \t {} \t {} \n ' . format ( url [ ' type ' ] , x [ ' name ' ] , url [ ' resource ' ] , url [ ' host ' ] , url [ ' port ' ] )
header + = entry
return header
2018-11-05 01:20:51 +00:00
2018-10-24 05:32:26 +00:00
2018-11-03 03:48:40 +00:00
def show_search ( self ) :
text1 = ' __ ___ __ __ \n /__` |__ / \ |__) / ` |__| \n .__/ |___ /~~ \ | \ \ __, | | \n \n \n Please enter your search terms and press the enter key: \n \n '
self . search = tk . Entry ( width = ' 50 ' )
self . search . bind ( ' <Return> ' , self . query_search_engine )
self . site_display . config ( state = tk . NORMAL )
self . site_display . delete ( 1.0 , tk . END )
self . site_display . insert ( tk . END , text1 )
self . site_display . window_create ( tk . END , window = self . search )
self . site_display . config ( state = tk . DISABLED )
2018-11-05 01:20:51 +00:00
self . search . focus_set ( )
2018-11-03 03:48:40 +00:00
2018-11-05 06:04:15 +00:00
try :
self . loading_bar . destroy ( )
except :
pass
2018-11-03 03:48:40 +00:00
def query_search_engine ( self , event ) :
base_url = self . entry_url . get ( )
base_url = base_url . replace ( ' /7/ ' , ' /1/ ' , 1 )
query = self . search . get ( )
url = ' {} \t {} ' . format ( base_url , query )
self . populate_url_bar ( url )
self . handle_request ( False , url )
self . search = None
2018-11-09 04:25:27 +00:00
def show_menu ( self , data , clear = True ) :
2018-10-24 05:32:26 +00:00
if not data :
#error handling will go here
return False
types = {
2018-10-26 03:30:07 +00:00
' 0 ' : ' ( TXT ) ' ,
' 1 ' : ' ( MNU ) ' ,
' 3 ' : ' ( ERR ) ' ,
' 7 ' : ' ( INT ) ' ,
' 9 ' : ' ( BIN ) ' ,
' g ' : ' ( GIF ) ' ,
' I ' : ' ( IMG ) ' ,
' h ' : ' ( HTM ) ' ,
' i ' : ' ( INF ) ' ,
' s ' : ' ( SND ) ' ,
' p ' : ' ( PNG ) '
2018-10-24 05:32:26 +00:00
}
self . site_display . config ( state = tk . NORMAL )
if clear :
self . site_display . delete ( 1.0 , tk . END )
2018-10-24 15:10:18 +00:00
2018-11-09 04:25:27 +00:00
if clear :
self . link_count = 0
2018-10-24 15:10:18 +00:00
2018-11-05 06:04:15 +00:00
for x in data :
2018-10-24 05:32:26 +00:00
if x [ ' type ' ] == ' i ' :
2018-11-10 23:48:08 +00:00
self . site_display . insert ( tk . END , ' \t \t {} \n ' . format ( x [ ' description ' ] ) , ( ' generic_r_click ' ) )
2018-10-24 05:32:26 +00:00
elif x [ ' type ' ] == ' 3 ' :
2018-11-10 23:48:08 +00:00
self . site_display . insert ( tk . END , ' \t \t {} \n ' . format ( x [ ' description ' ] ) , ( ' generic_r_click ' ) )
2018-10-24 05:32:26 +00:00
elif x [ ' type ' ] in types :
# adapted from:
# https://stackoverflow.com/questions/27760561/tkinter-and-hyperlinks
if x [ ' port ' ] and x [ ' port ' ] [ 0 ] != ' : ' :
x [ ' port ' ] = ' : {} ' . format ( x [ ' port ' ] )
2019-02-06 02:43:16 +00:00
link = ' gopher:// {} {} / {} {} ' . format ( x [ ' host ' ] , x [ ' port ' ] , x [ ' type ' ] , x [ ' resource ' ] )
2018-10-30 02:19:03 +00:00
2018-11-09 04:25:27 +00:00
tag_name = ' link {} ' . format ( self . link_count )
2018-10-24 05:32:26 +00:00
callback = ( lambda event , href = link , tag_name = tag_name : self . gotolink ( event , href , tag_name ) )
2018-12-05 03:49:04 +00:00
# favorite = [x for x in self.config['favorites'] if x['url'] == link]
favorite = self . is_favorite ( link )
2018-10-24 05:32:26 +00:00
self . site_display . tag_bind ( tag_name , " <Button-1> " , callback )
self . site_display . insert ( tk . END , types [ x [ ' type ' ] ] , ( ' type_tag ' , ) )
self . site_display . insert ( tk . END , ' \t \t ' )
2018-11-10 04:03:43 +00:00
callback_menu = ( lambda event , href = link : self . show_context_menu ( event , href ) )
self . site_display . tag_bind ( tag_name , ' <Button-3> ' , callback_menu )
2018-11-08 07:04:34 +00:00
if favorite :
2018-11-10 04:03:43 +00:00
styletag = ' favoritecolor '
2018-11-08 07:04:34 +00:00
else :
2018-11-10 04:03:43 +00:00
styletag = ' linkcolor '
2018-11-18 16:43:36 +00:00
2018-11-10 04:03:43 +00:00
hover = ( lambda event , href = link , tag_name = tag_name : self . hoverlink ( event , href , tag_name ) )
clear = ( lambda event , tag_name = tag_name : self . clear_status ( event , tag_name ) )
self . site_display . tag_bind ( tag_name , " <Enter> " , hover )
self . site_display . tag_bind ( tag_name , ' <Leave> ' , clear )
self . site_display . insert ( tk . END , x [ ' description ' ] , ( tag_name , styletag ) )
2018-10-24 05:32:26 +00:00
self . site_display . insert ( tk . END , ' \n ' )
2018-11-09 04:25:27 +00:00
self . link_count + = 1
2018-10-24 05:32:26 +00:00
self . site_display . config ( state = tk . DISABLED )
2018-11-09 04:25:27 +00:00
return self . link_count
2018-10-24 05:32:26 +00:00
def show_text ( self , data ) :
2018-11-05 06:04:15 +00:00
if data [ - 2 : ] == ' . \n ' :
2018-11-03 16:24:38 +00:00
data = data [ : - 2 ]
2018-10-24 05:32:26 +00:00
self . site_display . config ( state = tk . NORMAL )
self . site_display . delete ( 1.0 , tk . END )
2018-11-18 16:43:36 +00:00
self . site_display . insert ( tk . END , data , ' generic_r_click ' )
2018-10-24 05:32:26 +00:00
self . site_display . config ( state = tk . DISABLED )
2018-10-26 03:30:07 +00:00
def show_image ( self , data ) :
self . current_image = self . build_image ( data )
2018-11-18 16:43:36 +00:00
callback = ( lambda event , image = data , write = ' wb ' : self . write_to_file ( contents = image , event = event , write = write ) )
hover = ( lambda event , href = ' Download this image... ' , tag_name = ' image_download ' : self . hoverlink ( event , href , tag_name ) )
clear = ( lambda event , tag_name = ' image_download ' : self . clear_status ( event , tag_name ) )
self . site_display . tag_bind ( ' image_download ' , " <Button-1> " , callback )
self . site_display . tag_bind ( ' image_download ' , " <Enter> " , hover )
self . site_display . tag_bind ( ' image_download ' , ' <Leave> ' , clear )
2018-10-26 03:30:07 +00:00
self . site_display . config ( state = tk . NORMAL )
self . site_display . delete ( 1.0 , tk . END )
2018-11-18 16:43:36 +00:00
self . site_display . insert ( tk . END , ' Download this image ' , ( ' linkcolor ' , ' image_download ' ) )
self . site_display . insert ( tk . END , ' \n \n ' )
2018-10-26 03:30:07 +00:00
self . site_display . image_create ( tk . END , image = self . current_image )
self . site_display . config ( state = tk . DISABLED )
2018-11-18 16:43:36 +00:00
def show_bin_download ( self , data ) :
url = self . entry_url . get ( )
filename = url . rpartition ( ' / ' )
if len ( filename ) > 1 :
filename = filename [ - 1 ]
else :
filename = ' '
callback = ( lambda event , bindata = data , write = ' wb ' : self . write_to_file ( contents = bindata , event = event , write = write ) )
hover = ( lambda event , href = ' Download {} ' . format ( filename ) , tag_name = ' bin_download ' : self . hoverlink ( event , href , tag_name ) )
clear = ( lambda event , tag_name = ' bin_download ' : self . clear_status ( event , tag_name ) )
self . site_display . tag_bind ( ' bin_download ' , " <Button-1> " , callback )
self . site_display . tag_bind ( ' bin_download ' , " <Enter> " , hover )
self . site_display . tag_bind ( ' bin_download ' , ' <Leave> ' , clear )
self . site_display . config ( state = tk . NORMAL )
self . site_display . delete ( 1.0 , tk . END )
self . site_display . insert ( tk . END , ' Download ' )
self . site_display . insert ( tk . END , filename , ( ' linkcolor ' , ' bin_download ' ) )
self . site_display . config ( state = tk . DISABLED )
2018-11-09 04:25:27 +00:00
def send_to_screen ( self , data , itemtype = ' 1 ' , clear = True ) :
2019-02-06 02:43:16 +00:00
if itemtype in [ ' 0 ' , ' h ' ] :
2018-10-24 05:32:26 +00:00
self . show_text ( data )
2018-11-01 05:13:00 +00:00
elif itemtype in [ ' 1 ' , ' 3 ' , ' 7 ' ] :
2018-10-24 05:32:26 +00:00
data = self . parser . parse_menu ( data )
2018-11-09 04:25:27 +00:00
self . show_menu ( data , clear )
2018-10-26 03:30:07 +00:00
elif itemtype in [ ' p ' , ' I ' , ' g ' ] :
self . show_image ( data )
2018-11-18 16:43:36 +00:00
elif itemtype in [ ' s ' , ' 9 ' , ' M ' , ' c ' , ' ; ' , ' d ' , ' 5 ' ] :
self . show_bin_download ( data )
2018-10-24 05:32:26 +00:00
2018-11-05 01:20:51 +00:00
try :
2018-11-05 06:04:15 +00:00
self . loading_bar . destroy ( )
2018-11-05 01:20:51 +00:00
except :
pass
2018-10-24 05:32:26 +00:00
2018-11-10 04:03:43 +00:00
2018-10-24 05:32:26 +00:00
def update_status ( self , event , href = False ) :
if href :
self . message_bar_content . set ( href )
else :
self . message_bar_content . set ( event . widget . pop_title )
def clear_status ( self , event , tag_name = False ) :
if tag_name :
e = event . widget
e . tag_config ( tag_name , underline = 0 )
self . site_display . config ( cursor = ' xterm ' )
e . update_idletasks ( )
self . message_bar_content . set ( ' ' )
def populate_url_bar ( self , url ) :
self . entry_url . delete ( 0 , tk . END )
self . entry_url . insert ( tk . END , url )
def hoverlink ( self , event , href , tag_name ) :
self . update_status ( event , href )
e = event . widget
2018-11-10 04:03:43 +00:00
e . tag_config ( tag_name , underline = 1 )
2018-10-24 05:32:26 +00:00
self . site_display . config ( cursor = " arrow " )
e . update_idletasks ( )
2018-11-10 04:03:43 +00:00
2018-10-26 03:30:07 +00:00
def build_image ( self , bytes_str ) :
stream = BytesIO ( bytes_str )
pilimage = Image . open ( stream )
tkimage = ImageTk . PhotoImage ( pilimage )
return tkimage
2018-10-24 05:32:26 +00:00
#--------Start file handling methods------------
def read_config ( self , url = ' ./go.config.json ' ) :
if not os . path . isfile ( url ) :
self . create_config ( )
with open ( ' ./go.config.json ' , ' r ' ) as f :
config = f . read ( )
config = json . loads ( config )
self . config = config
def write_config ( self , config , url = ' ./go.config.json ' ) :
with open ( url , ' w ' ) as f :
data = json . dumps ( config )
f . write ( data )
def create_config ( self ) :
config = { " favorites " : [ ] , " last_viewed " : None }
self . write_config ( config )
def close_window ( self ) :
self . write_config ( self . config )
self . root . destroy ( )
2018-11-10 04:03:43 +00:00
def is_favorite ( self , href ) :
for val in self . config [ ' favorites ' ] :
if val [ ' url ' ] == href :
return True
return False
2018-10-24 05:32:26 +00:00
2018-11-10 23:48:08 +00:00
def rename_favorite ( self , event , link ) :
index = None
for ind , val in enumerate ( self . config [ ' favorites ' ] ) :
if val [ ' url ' ] == link :
index = ind
break
if index is not None :
title = self . config [ ' favorites ' ] [ index ] [ ' name ' ]
new_name = dialog . askstring ( " Rename favorite " , " \n Change favorite name to: \n " . format ( title ) , initialvalue = title )
if new_name :
self . config [ ' favorites ' ] [ index ] [ ' name ' ] = new_name
self . write_config ( self . config )
if self . entry_url . get ( ) == ' home ' :
self . load_home_screen ( )
return True
return False
2018-11-08 07:04:34 +00:00
def remove_favorite ( self , event , href ) :
index = None
for ind , val in enumerate ( self . config [ ' favorites ' ] ) :
if val [ ' url ' ] == href :
index = ind
break
if index is not None :
self . config [ ' favorites ' ] . pop ( index )
2018-11-10 23:48:08 +00:00
self . write_config ( self . config )
2018-11-08 07:04:34 +00:00
self . load_home_screen ( )
2018-10-24 05:32:26 +00:00
2018-11-10 23:48:08 +00:00
def add_to_favorites ( self , event , url = None ) :
favorite_name = dialog . askstring ( " Add to favorites " , " What would you like to title this favorite? " )
if url is None :
url = self . entry_url . get ( )
if not favorite_name or not url :
return False
favorite = { " url " : url , " name " : favorite_name }
self . config [ " favorites " ] . append ( favorite )
self . write_config ( self . config )
if self . entry_url . get ( ) == ' home ' :
self . load_home_screen ( )
return True
2018-11-18 16:43:36 +00:00
def write_to_file ( self , contents = None , page_url = None , event = None , write = ' w ' ) :
url = self . entry_url . get ( )
filetype = url . rpartition ( ' . ' )
if len ( filetype ) > 1 :
filetype = filetype [ - 1 ]
else :
filetype = ' txt '
filename = savedialog ( initialdir = " ~/Desktop/ " , defaultextension = ' . {} ' . format ( filetype ) , title = " Save As File " , filetypes = ( ( filetype , ' *. {} ' . format ( filetype ) ) , ( ' all files ' , ' *.* ' ) ) )
if not filename or filename is None or contents is None :
return False
with open ( filename , write ) as f :
f . write ( contents )
return True
2018-10-24 05:32:26 +00:00
if __name__ == ' __main__ ' :
app = GUI ( )
app . root . mainloop ( )