def btn_viewpassword_click(self, event): getattr(self, 'txt_in_password').entry.config( show='' if getattr(self, 'txt_in_password').entry.cget('show') == '*' else '*') self.btn_viewpwd.label['text'] = translate('View Password') if getattr( self, 'txt_in_password').entry.cget('show') == '*' else translate( 'Hide Password')
def get_btn_list(self, history): def ask_revert_changes(history): def revert_changes(msg, history): history.project.file = history.file history.project.lastEdited = history.editDate history.project.image = history.image Container.save(history.project) msg.destroy() for li in self.historyItems: if li.dataObject.editDate >= history.editDate: Container.deleteObject(li.dataObject) li.destroy() photo = getdisplayableimage(history.image, (self.frm_preview.winfo_width(), self.frm_preview.winfo_height())) self.lbl_image.configure(image=photo) self.lbl_image.image = photo MessageModal( self, title=f'Success', message= f'Changes reverted to the following date:\n{history.editDate.strftime("%x - %X")}!', messageType='info') getattr( self, 'lbl_' + CollaborationWindow.lblSettings[2]['prop'] )['text'] = history.editDate.strftime( "%d/%m/%Y" ) if datetime.datetime.now( ).strftime("%x") != history.editDate.strftime( "%x") else 'Today at - ' + history.editDate.strftime("%X") msg = MessageModal( self, title=f'Confirmation', message=f'Are you sure you want to revert to that change?', messageType='prompt', actions={'yes': lambda e: revert_changes(msg, history)}) btn_list = [{ 'icon': 'save.png', 'text': translate('Export to XML'), 'cmd': lambda e: self.export_project(history.project.title, history. editDate, history.file) }, { 'icon': 'revert_history.png', 'text': translate('Revert'), 'cmd': lambda e: ask_revert_changes(history) }] if CollaborationWindow.ACTIVE_USER != self.session.owner: btn_list.pop(1) return btn_list
def design(self): # lay out the components to project tab self.btn_container1 = Frame(self.tb_projects, bg=background, pady=10) self.btn_container1.pack (side=TOP, fill=X) # BOOKMARK: modal redirections # configure redirections to form modals createProjectModalCmnd = lambda e: (self.windowManager.get_module('CreateProjectModal'))( self, # BOOKMARK_DONE: create project button command lambda formModal: self.create(formModal) ) loadProjectModalCmnd = lambda e: (self.windowManager.get_module('LoadProjectModal'))( self, # BOOKMARK_DONE: create load project button command lambda formModal: self.create(formModal, HomeWindow.PROJECT_LI, True) ) createSessionModalCmnd = lambda e: (self.windowManager.get_module('CreateSessionModal'))( self, # BOOKMARK_DONE: create session button command lambda formModal: self.create(formModal, HomeWindow.SESSION_LI) ) joinSessionModalCmnd = lambda e: (self.windowManager.get_module('JoinModal'))( self, # BOOKMARK_DONE: join session command lambda formModal: self.join_session(formModal) ) joinProjectModalCmnd = lambda e: (self.windowManager.get_module('JoinModal'))( self, # BOOKMARK_DONE: join project command lambda formModal: self.join_project(formModal) ) self.btn_create_project = MainButton(self.btn_container1, translate('Create New Project'), 'new_project.png', createProjectModalCmnd) self.btn_create_project.pack(side=LEFT, padx=(0, 10)) self.btn_open = SecondaryButton(self.btn_container1, translate('Load From Device'), 'upload.png', loadProjectModalCmnd) self.btn_open.pack(side=LEFT, padx=(0, 10)) self.btn_open = SecondaryButton(self.btn_container1, translate('Access Project'), 'login.png', joinProjectModalCmnd) self.btn_open.pack(side=RIGHT) self.lv_project = Scrollable(self.tb_projects, bg=background, pady=15) self.lv_project.set_gridcols(4) self.lv_project.pack(fill=BOTH, expand=1) # lay out the components to session tab self.btn_container2 = Frame(self.tb_sessions, bg=background, pady=10, padx=1) self.btn_container2.pack (side=TOP, fill=X) self.btn_create_session = MainButton(self.btn_container2, translate('Create New Session'), 'new_session.png', createSessionModalCmnd) self.btn_create_session.pack(side=LEFT, padx=(0, 10)) self.btn_join_session = SecondaryButton(self.btn_container2, translate('Join Session'), 'login.png', joinSessionModalCmnd) self.btn_join_session.pack(side=RIGHT) self.lv_session = Scrollable(self.tb_sessions, bg=background, pady=15) self.lv_session.set_gridcols(4) self.lv_session.pack(fill=BOTH, expand=1)
def __init__(self, root, project=None, **args): TabbedWindow.__init__(self, root, ProjectWindow.tabSettings, project.title, **args) self.project = project self.historyItems = [] # Button settings self.btnSettings = [ { 'icon': 'edit.png', 'text': translate('Open Editor'), 'dock': LEFT, 'cmnd': lambda e: self.windowManager.run( EditorWindow(self.master, self.project)) }, { 'icon': 'share.png', 'text': translate('Share Project'), 'type': SecondaryButton, 'cmnd': lambda e: (self.windowManager.get_module('ShareModal'))( self, # BOOKMARK_DONE: Share Project Command lambda modal: self.generate_share_link( self.project, modal)) }, { 'icon': 'save.png', 'text': translate('Export as XML'), 'cmnd': lambda e: self. export_project('current_' + self.project.title, self.project. lastEdited, self.project.file) } ] # Design elements self.design() self.configure_settings()
def options_menu(e): # convert screen mouse position win_coords = self.to_window_coords(e.x_root, e.y_root) menu_buttons = [ { 'text': translate('Open'), 'icon': 'open.png', 'cmnd': lambda e: self.windowManager.run(ProjectWindow(self, item.dataObject)) if liType == HomeWindow.PROJECT_LI else self.windowManager.run(CollaborationWindow(self, item.dataObject)) }, { 'text': translate('Edit'), 'icon': 'edit.png', 'cmnd': lambda e: self.windowManager.run_tag('editor', item.dataObject) }, { 'text': translate('Share'), 'icon': 'share.png', 'cmnd': lambda e: (self.windowManager.get_module('ShareModal'))(self, lambda modal: self.generate_share_link(item.dataObject, modal)) }, { 'text': translate('Delete'), 'icon': 'delete.png', 'fg': danger, 'cmnd': lambda e: self.delete_project(item.dataObject) if liType == self.PROJECT_LI else self.delete_session(item.dataObject) }, { 'text': translate('Leave'), 'icon': 'logout.png', 'fg': danger, 'cmnd': lambda e: self.quit_session(item.dataObject) } ] # pop unwanted buttons if liType == self.SESSION_LI: # remove share button menu_buttons.pop(2) # remove delete or leave menu_buttons.pop(2 if item.dataObject.owner != HomeWindow.ACTIVE_USER else 3) else: # remove leave menu_buttons.pop() # show menu self.show_menu(x=win_coords[0], y=win_coords[1], width=150, height=200, options=menu_buttons)
def fill_members(self): # Remove all items self.lv_members.empty() # Append items for i in Container.filter( User, Collaboration.sessionId == self.session.id, or_(User.id == Collaboration.userId, User.id == self.session.ownerId)).all(): li = ListItem(self.lv_members.interior, i, { 'username': i.userName, 'image': i.image }, [{ 'icon': 'cancel.png', 'text': translate('Kick'), 'cmd': lambda e, user=i: self.kick_user(user), }] if i != self.session.owner else None) li.pack(anchor=N + W, pady=(0, 10), padx=(10, 10), fill=X) self.collaboratorItems.append(li)
def create_list_item(self, item: ListItem, liType: int = PROJECT_LI): item.configure (highlightthickness=1, highlightbackground=border, bg=white) comps = [] img_size = 205 img_thumb = Frame(item, height=img_size, bg=white) img_thumb.pack_propagate(0) # adding image label item.lbl_image = Label(img_thumb,bg='white') item.lbl_image.pack(fill=BOTH,expand=1) comps.append(item.lbl_image) border_bottom = Frame(item, bg=border) frm_info = Frame(item, bg=silver, padx=10, pady=10) frm_details = Frame(frm_info, bg=silver) lbl_title = Label(frm_info, text=item.bindings.get('title', '{title}'), bg=silver, fg=black, font='-size 18') lbl_title.pack(side=TOP, fill=X, pady=(0, 10)) comps.append(lbl_title) panel_settings = [ { 'label': translate('Created In:'), 'text': item.bindings.get('creationDate').strftime('%a, %d %b') if 'creationDate' in item.bindings else '{creationDate}' }, { 'label': translate('Edited In:'), 'text': item.bindings.get('lastEdited').strftime('%a, %d %b') if 'lastEdited' in item.bindings else '{lastEdited}' } ] if liType == HomeWindow.SESSION_LI: panel_settings.append({ 'label': translate('Members:'), 'text': item.bindings.get('memberCount', '{memberCount}') }) for i in panel_settings: frm = Frame(frm_details, bg=silver) frm.pack(side=LEFT, fill=X, expand=1) comps.append(frm) lbl_label = Label(frm, text=i.get('label'), fg=teal, bg=silver, font='-size 8') lbl_label.pack(fill=X) comps.append(lbl_label) lbl_text = Label(frm, text=i.get('text'), fg=gray, bg=silver, font='-size 9') lbl_text.pack(fill=X) comps.append(lbl_text) img_thumb.pack(fill=X, side=TOP) comps.append(img_thumb) border_bottom.pack(fill=X, side=TOP) frm_info.pack(fill=X, side=TOP) comps.append(frm_info) frm_details.pack(fill=X, side=TOP) comps.append(frm_details) # BOOKMARK_DONE: project item's menu def options_menu(e): # convert screen mouse position win_coords = self.to_window_coords(e.x_root, e.y_root) menu_buttons = [ { 'text': translate('Open'), 'icon': 'open.png', 'cmnd': lambda e: self.windowManager.run(ProjectWindow(self, item.dataObject)) if liType == HomeWindow.PROJECT_LI else self.windowManager.run(CollaborationWindow(self, item.dataObject)) }, { 'text': translate('Edit'), 'icon': 'edit.png', 'cmnd': lambda e: self.windowManager.run_tag('editor', item.dataObject) }, { 'text': translate('Share'), 'icon': 'share.png', 'cmnd': lambda e: (self.windowManager.get_module('ShareModal'))(self, lambda modal: self.generate_share_link(item.dataObject, modal)) }, { 'text': translate('Delete'), 'icon': 'delete.png', 'fg': danger, 'cmnd': lambda e: self.delete_project(item.dataObject) if liType == self.PROJECT_LI else self.delete_session(item.dataObject) }, { 'text': translate('Leave'), 'icon': 'logout.png', 'fg': danger, 'cmnd': lambda e: self.quit_session(item.dataObject) } ] # pop unwanted buttons if liType == self.SESSION_LI: # remove share button menu_buttons.pop(2) # remove delete or leave menu_buttons.pop(2 if item.dataObject.owner != HomeWindow.ACTIVE_USER else 3) else: # remove leave menu_buttons.pop() # show menu self.show_menu(x=win_coords[0], y=win_coords[1], width=150, height=200, options=menu_buttons) # options icon IconFrame(item, 'resources/icons/ui/menu.png', 10, teal, 32, options_menu, bg=white).place(relx=1-0.03, rely=0.02, anchor=N+E) for c in comps: c.bind('<Double-Button-1>', lambda e: self.windowManager.run(ProjectWindow(self, item.dataObject)) if liType == HomeWindow.PROJECT_LI else self.windowManager.run(CollaborationWindow(self, item.dataObject)))
def __init__(self, root, session=None, **args): TabbedWindow.__init__(self, root, CollaborationWindow.tabSettings, session.title, **args) self.session = session self.collaboratorItems = [] self.historyItems = [] # configure button settings self.btnSettings = [ { 'icon': 'edit.png', 'text': translate('Open Editor'), 'dock': LEFT, 'cmnd': lambda e: self.windowManager.run( EditorWindow(self.master, self.session)) }, { 'icon': 'delete.png', 'text': translate('End Session'), 'type': DangerButton, # BOOKARK: Ending Session Command 'cmnd': lambda e: self.show_prompt( 'Are you sure you want to terminate the session?', lambda e: self.delete_session(), 'Terminating the session') }, { 'icon': 'invite.png', 'text': translate('Invite'), 'type': SecondaryButton, 'cmnd': lambda e: (self.windowManager.get_module('InviteModal'))( self, # BOOKMARK_DONE: Activate Link Command lambda modal: self.generate_inviationlink( modal), # modal.get_form_data()['txt_link'] # BOOKMARK_DONE: Invite User Command lambda modal: self.invite_user(modal.get_form_data()[ 'txt_username'])) }, { 'icon': 'save.png', 'text': translate('Export to XML'), 'dock': LEFT, 'cmnd': lambda e: self.export_project( f'current_{self.session.project.title}', self.session. project.lastEdited, self.session.project.file) } ] if CollaborationWindow.ACTIVE_USER != self.session.owner: self.btnSettings.pop(1) # Design elements self.design() # Fill session members self.fill_members()
class CollaborationWindow(TabbedWindow): tabSettings = [{ 'icon': 'info.png', 'text': translate('General Info'), 'tag': 'tb_info' }, { 'icon': 'history.png', 'text': translate('History'), 'tag': 'tb_hist' }, { 'icon': 'session.png', 'text': translate('Members'), 'tag': 'tb_member' }] lblSettings = [{ 'label': translate('Session\'s Title:'), 'prop': 'title' }, { 'label': translate('Creation Date:'), 'prop': 'creationDate' }, { 'label': translate('Last Edit:'), 'prop': 'lastEdit' }, { 'label': translate('Members:'), 'prop': 'memberCount' }] def __init__(self, root, session=None, **args): TabbedWindow.__init__(self, root, CollaborationWindow.tabSettings, session.title, **args) self.session = session self.collaboratorItems = [] self.historyItems = [] # configure button settings self.btnSettings = [ { 'icon': 'edit.png', 'text': translate('Open Editor'), 'dock': LEFT, 'cmnd': lambda e: self.windowManager.run( EditorWindow(self.master, self.session)) }, { 'icon': 'delete.png', 'text': translate('End Session'), 'type': DangerButton, # BOOKARK: Ending Session Command 'cmnd': lambda e: self.show_prompt( 'Are you sure you want to terminate the session?', lambda e: self.delete_session(), 'Terminating the session') }, { 'icon': 'invite.png', 'text': translate('Invite'), 'type': SecondaryButton, 'cmnd': lambda e: (self.windowManager.get_module('InviteModal'))( self, # BOOKMARK_DONE: Activate Link Command lambda modal: self.generate_inviationlink( modal), # modal.get_form_data()['txt_link'] # BOOKMARK_DONE: Invite User Command lambda modal: self.invite_user(modal.get_form_data()[ 'txt_username'])) }, { 'icon': 'save.png', 'text': translate('Export to XML'), 'dock': LEFT, 'cmnd': lambda e: self.export_project( f'current_{self.session.project.title}', self.session. project.lastEdited, self.session.project.file) } ] if CollaborationWindow.ACTIVE_USER != self.session.owner: self.btnSettings.pop(1) # Design elements self.design() # Fill session members self.fill_members() def generate_inviationlink(self, modal): # modal.form[0]['input'].entry.get() def set_link(link): modal.form[0]['input'].entry.delete(0, END) modal.form[0]['input'].entry.insert(0, link) def check_privilege(msg, modal, inv): def generate_link(msg2, modal, inv, privilege): msg2.destroy() if inv != None: Container.deleteObject(inv) link = f'bpmntool//{self.session.title}/{datetime.datetime.now()}/' Container.save( InvitationLink(link=link, expirationDate=datetime.datetime.now() + datetime.timedelta(days=1), privilege=privilege, sender=CollaborationWindow.ACTIVE_USER, session=self.session)) self.clean_notifications() set_link(link) if msg != None: msg.destroy() msg2 = MessageModal( self, title=f'Confirmation', message=f'Do you want to grant this link the "edit" privilege?', messageType='prompt', actions={ 'yes': lambda e: generate_link(msg2, modal, inv, 'edit'), 'no': lambda e: generate_link(msg2, modal, inv, 'read') }) def set_old_link(msg, modal): set_link(inv.link) msg.destroy() inv = Container.filter( InvitationLink, InvitationLink.senderId == CollaborationWindow.ACTIVE_USER.id, InvitationLink.sessionId == self.session.id).first() if inv != None: msg = check_privilege( None, modal, inv ) if inv.expirationDate < datetime.datetime.now( ) else MessageModal( self, title='link found', message=f'A link already exists, Do you want to override it?', messageType='prompt', actions={ 'yes': lambda e: check_privilege(msg, modal, inv), 'no': lambda e: set_old_link(msg, modal) }) else: check_privilege(None, modal, None) def invite_user(self, username): def send_invite(msg, user, privilege): inv = Invitation(privilege=privilege, invitationTime=datetime.datetime.now(), sender=CollaborationWindow.ACTIVE_USER, recipient=user, session=self.session) Container.save(inv) notif = Notification(type=NotificationType.INVITED.value, notificationTime=datetime.datetime.now(), nature=NotificationNature.INV.value, invitationId=inv.id, actor=inv.sender, recipient=inv.recipient) Container.save(notif) msg.destroy() MessageModal( self, title=f'Success', message=f'Invitation sent to {user.userName} successfully!', messageType='info') user = Container.filter(User, User.userName == username).first() collabs = Container.filter( User, Collaboration.sessionId == self.session.id, or_(User.id == Collaboration.userId, User.id == self.session.ownerId)).all() if user == None: MessageModal( self, title='User error 404', message=f'{username} doesn\'t exist!' if username != '' and not str.isspace(username) else 'Please enter a username!', messageType='error') elif user in collabs: MessageModal(self, title='User already in', message=f'{username} is already in the session!', messageType='error') elif Container.filter(Invitation, Invitation.recipientId == user.id, Invitation.sessionId == self.session.id, Invitation.status == Status.PENDING.value).first() != None: MessageModal(self, title='User already invited', message=f'An invite is already sent to {username}!', messageType='info') else: msg = MessageModal( self, title=f'Confirmation', message= f'An invitation will be sent to [{username}], but do you want to give him the right to make changes?', messageType='prompt', actions={ 'yes': lambda e: send_invite(msg, user, 'edit'), 'no': lambda e: send_invite(msg, user, 'read') }) def delete_session(self): Container.deleteObject(self.session.project) self.clean_notifications() self.windowManager.run_tag('home') self.destroy() def configure_settings(self): # get_label = lambda prop: getattr(self, f'lbl_{prop}') # change label get_label(CollaborationWindow.lblSettings[0] ['prop'])['text'] = self.session.title get_label( CollaborationWindow.lblSettings[1]['prop'] )['text'] = self.session.creationDate.strftime( "%d/%m/%Y" ) if datetime.datetime.now( ).strftime("%x") != self.session.creationDate.strftime( "%x") else 'Today at - ' + self.session.creationDate.strftime("%X") get_label( CollaborationWindow.lblSettings[2]['prop'] )['text'] = self.session.project.lastEdited.strftime( "%d/%m/%Y" ) if datetime.datetime.now( ).strftime("%x") != self.session.project.lastEdited.strftime( "%x" ) else 'Today at - ' + self.session.project.lastEdited.strftime("%X") get_label(CollaborationWindow.lblSettings[3]['prop'])['text'] = str( Container.filter(Collaboration, Collaboration.sessionId == self.session.id).count() + 1) # change image if self.session.project.image != None: photo = getdisplayableimage(self.session.project.image, (self.frm_preview.winfo_width(), self.frm_preview.winfo_height())) self.lbl_image.configure(image=photo) self.lbl_image.image = photo # fill self.fill_collaboration() self.fill_members() def design(self): # Putting the control buttons btn_container = Frame(self.frm_body, bg=background) btn_container.pack(fill=X, side=TOP) for i in self.btnSettings: childCount = len(btn_container.pack_slaves()) method = i.get('type', MainButton) btn = method(btn_container, i.get('text', 'Button'), i.get('icon', 'error.png'), i.get('cmnd', None)) btn.pack(side=i.get('dock', RIGHT), padx=(0 if childCount == 0 else 10, 0)) # Filling the information tab frm_label_container = Frame(self.tb_info, bg=black) frm_label_container.pack(side=TOP, fill=X) for i in CollaborationWindow.lblSettings: frm_lbl_group = Frame(frm_label_container, bg=background) frm_lbl_group.pack(side=LEFT, fill=X, expand=1) lbl_label = Label(frm_lbl_group, bg=background, fg=teal, font='-size 16', text=i.get('label'), anchor='nw') lbl_label.pack(side=TOP, fill=X) lbl_prop = Label(frm_lbl_group, bg=background, fg=black, font='-size 13', text=i.get('prop'), anchor='nw') lbl_prop.pack(side=TOP, fill=X) setattr(self, 'lbl_' + i.get('prop'), lbl_prop) frm_group = Frame(self.tb_info, bg=background) frm_group.pack(expand=1, fill=BOTH, pady=15) self.frm_preview = Frame(frm_group, bg=white, highlightthickness=1, highlightbackground=border) self.frm_preview.pack(side=LEFT, fill=BOTH, expand=1) self.frm_preview.update() def resize_image(event, label): if self.session.project.image != None: photo = getdisplayableimage(self.session.project.image, (self.frm_preview.winfo_width(), self.frm_preview.winfo_height())) label.configure(image=photo) label.image = photo self.lbl_image = Label(self.frm_preview, bg='white') self.lbl_image.pack(fill=BOTH, expand=1) self.lbl_image.bind('<Configure>', lambda e, l=self.lbl_image: resize_image(e, l)) # Filling the history tab self.frm_list_view = Scrollable(self.tb_hist, bg=background) self.frm_list_view.pack(expand=1, fill=BOTH, pady=(0, 15)) # filling member tab self.lv_members = Scrollable(self.tb_member, bg=background) self.lv_members.pack(fill=BOTH, expand=1, pady=(0, 15)) self.fill_collaboration() def fill_collaboration(self): self.frm_list_view.empty() # BOOKMARK_DONE: Fill Collaboration Session Change History for i in Container.filter( History, History.projectId == self.session.projectId ).order_by(History.editDate.desc()).all( ): #, or_(History.editorId == Collaboration.userId, History.editorId == self.session.ownerId) since the project is gonna be unique if i.project.owner == CollaborationWindow.ACTIVE_USER or Container.filter( Collaboration, Collaboration.sessionId == self.session.id, Collaboration.userId == CollaborationWindow.ACTIVE_USER.id).first() != None: li = ListItem( self.frm_list_view.interior, i, { 'username': f'{i.editor.userName} edited on {i.editDate.strftime("%d/%m/%Y at %X")}', 'image': i.editor.image }, self.get_btn_list(i)) li.pack(anchor=N + W, fill=X, pady=(0, 10), padx=5) self.historyItems.append(li) def export_project(self, title, date, fileBytes): if fileBytes == None: MessageModal( self, title='Error', message= 'No changes has been made yet on this session\'s project yet!', messageType='error') else: folderName = filedialog.askdirectory( initialdir="/", title='Please select a directory') if folderName != '': bytestofile(f'{folderName}', f'{title}_{date.strftime("%d-%m-%Y_%H-%M-%S")}', 'xml', fileBytes) MessageModal(self, title=f'Success', message=f'File saved in {folderName}!', messageType='info') def get_btn_list(self, history): def ask_revert_changes(history): def revert_changes(msg, history): history.project.file = history.file history.project.lastEdited = history.editDate history.project.image = history.image Container.save(history.project) msg.destroy() for li in self.historyItems: if li.dataObject.editDate >= history.editDate: Container.deleteObject(li.dataObject) li.destroy() photo = getdisplayableimage(history.image, (self.frm_preview.winfo_width(), self.frm_preview.winfo_height())) self.lbl_image.configure(image=photo) self.lbl_image.image = photo MessageModal( self, title=f'Success', message= f'Changes reverted to the following date:\n{history.editDate.strftime("%x - %X")}!', messageType='info') getattr( self, 'lbl_' + CollaborationWindow.lblSettings[2]['prop'] )['text'] = history.editDate.strftime( "%d/%m/%Y" ) if datetime.datetime.now( ).strftime("%x") != history.editDate.strftime( "%x") else 'Today at - ' + history.editDate.strftime("%X") msg = MessageModal( self, title=f'Confirmation', message=f'Are you sure you want to revert to that change?', messageType='prompt', actions={'yes': lambda e: revert_changes(msg, history)}) btn_list = [{ 'icon': 'save.png', 'text': translate('Export to XML'), 'cmd': lambda e: self.export_project(history.project.title, history. editDate, history.file) }, { 'icon': 'revert_history.png', 'text': translate('Revert'), 'cmd': lambda e: ask_revert_changes(history) }] if CollaborationWindow.ACTIVE_USER != self.session.owner: btn_list.pop(1) return btn_list # BOOKMARK_DONE: Fill Collaboration Session Members def fill_members(self): # Remove all items self.lv_members.empty() # Append items for i in Container.filter( User, Collaboration.sessionId == self.session.id, or_(User.id == Collaboration.userId, User.id == self.session.ownerId)).all(): li = ListItem(self.lv_members.interior, i, { 'username': i.userName, 'image': i.image }, [{ 'icon': 'cancel.png', 'text': translate('Kick'), 'cmd': lambda e, user=i: self.kick_user(user), }] if i != self.session.owner else None) li.pack(anchor=N + W, pady=(0, 10), padx=(10, 10), fill=X) self.collaboratorItems.append(li) def kick_user(self, user): def delete_collaboration(user): Container.deleteObject( Container.filter( Collaboration, Collaboration.userId == user.id, Collaboration.sessionId == self.session.id).first()) msg.destroy() for li in self.collaboratorItems: if li.dataObject == user: li.destroy() getattr( self, 'lbl_' + CollaborationWindow.lblSettings[3]['prop'] )['text'] = str( Container.filter( Collaboration, Collaboration.sessionId == self.session.id).count() + 1) MessageModal( self, title=f'Success', message=f'{user.userName} has been kicked out of the session!', messageType='info') msg = MessageModal( self, title=f'Confirmation', message=f'Are you sure you want to kick {user.userName}?', messageType='prompt', actions={'yes': lambda e: delete_collaboration(user)}) def refresh(self): super().refresh() self.configure_settings()
class ProfileWindow(TabbedWindow): tabSettings = [{ 'tag': translate('tb_info'), 'text': 'Profile', 'icon': 'account.png' }, { 'tag': translate('tb_collabs'), 'text': translate('Saved Collaborators'), 'icon': 'session.png' }] formSettings = [[{ 'label': translate('First Name:'), 'icon': 'account.png', 'tag': 'firstName' }, { 'label': translate('Last Name:'), 'icon': 'account.png', 'tag': 'lastName' }, { 'label': translate('Username:'******'icon': 'account.png', 'tag': 'userName' }, { 'label': translate('Email:'), 'icon': 'mail.png', 'tag': 'email' }], [{ 'label': translate('Company:'), 'icon': 'business.png', 'tag': 'company' }, { 'label': translate('Gender:'), 'icon': 'wc.png', 'tag': 'gender' }, { 'label': translate('Password:'******'icon': 'key.png', 'tag': 'password' }, { 'label': translate('Confirm Password:'******'icon': 'key.png', 'tag': 'confirmPwd' }]] def __init__(self, root, **args): TabbedWindow.__init__(self, root, ProfileWindow.tabSettings, 'Profile', **args) self.textBoxes = {} self.collaboratorsItems = [] self.design() self.fill_collaborators() self.fill_profile() def design(self): # Setup the tab of profile frm_form = Frame(self.tb_info, bg=background) frm_form.pack(fill=BOTH, expand=1) frm_form.rowconfigure(0, weight=1) frm_form.columnconfigure([0, 1, 2], weight=1) frm_image_column = Frame(frm_form, bg=background) frm_image_column.grid(row=0, column=0, padx=(0, 20)) Label(frm_image_column, pady=10, bg=background, font='-size 10 -weight bold', fg=black, text=translate('Profile Photo:'), anchor=N + W).pack(side=TOP, fill=X) frm_image = Frame(frm_image_column, bg=black, height=150) frm_image.pack(side=TOP, fill=X, pady=(0, 10)) self.lbl_image = Label(frm_image) SecondaryButton(frm_image_column, translate('Upload Image'), 'upload.png', btnCmd=lambda event: self.open_image(event)).pack( side=TOP, fill=X) for column in ProfileWindow.formSettings: # Prepare a form column frm_column = Frame(frm_form, bg=background) frm_column.grid(row=0, column=(1 + ProfileWindow.formSettings.index(column))) # Loop through groups for group in column: # Prepare group frm_group = Frame(frm_column, bg=background) frm_group.pack(side=TOP, pady=10, padx=(0, 20)) # Label and textbox Label(frm_group, bg=background, font='-size 10 -weight bold', fg=black, text=group.get('label'), anchor=N + W).pack(side=TOP, fill=X, pady=(0, 5)) txt = TextBox(frm_group, 'resources/icons/ui/' + group.get('icon')) if group['tag'] in ['password', 'confirmPwd']: txt.entry.config(show='*') txt.pack(side=TOP) # Save the textbox in a list in order to get its value self.textBoxes[group.get('tag')] = txt frm_footer = Frame(self.tb_info, bg=background) frm_footer.pack(side=BOTTOM, fill=X) MainButton( frm_footer, translate('Save Changes'), 'save.png', btnCmd=lambda event: self.save_changes(event)).pack(side=LEFT) # Setup the tab of saved collabs frm_tip = IconButton( self.tb_collabs, 'Saved Collaborators are all the users who have participated in a collaboration session with you.', '-size 12 -weight bold', white, 'resources/icons/ui/info.png', 10, None, black, bg=black, pady=10, padx=5) frm_tip.pack(side=TOP, fill=X) self.lv_collabs = Scrollable(self.tb_collabs, bg=background, pady=5) self.lv_collabs.set_gridcols(2) self.lv_collabs.pack(expand=1, fill=BOTH, pady=(15, 0)) # select a ne image def open_image(self, event): self.set_image( filetobytes( filedialog.askopenfilename(initialdir="/", title="Select file", filetypes=(("jpeg/jpg files", "*.jpg"), ("png files", "*.png"), ("all files", "*.*"))))) # display current image def set_image(self, img): setattr(self, 'image', img) if img != None: photo = getdisplayableimage(img, (160, 150)) self.lbl_image.configure(image=photo) self.lbl_image.image = photo self.lbl_image.pack() # fill current user's profile def fill_profile(self): self.set_image(ProfileWindow.ACTIVE_USER.image) for key, value in self.textBoxes.items(): if hasattr( ProfileWindow.ACTIVE_USER, key) and getattr(ProfileWindow.ACTIVE_USER, key) != None: value.entry.insert(0, getattr(ProfileWindow.ACTIVE_USER, key)) # BOOKMARK_DONE: this one is responsible for filling the scrollable container def fill_collaborators(self): self.lv_collabs.empty() for i in Container.filter( Relation, Relation.userOneId == ProfileWindow.ACTIVE_USER.id): self.collaboratorsItems.append( self.lv_collabs.grid_item(i, { 'username': i.userTwo.userName, 'image': i.userTwo.image }, [{ 'text': 'Remove', 'icon': 'cancel.png', 'cmd': lambda e, relation=i: self.remove_collaborator(relation) }], None, 15)) # BOOKMARK_DONE: this method takes care of getting the data from the form in a form of dictionary def get_form_data(self): dic = {} # get data from textboxes for key, value in self.textBoxes.items(): dic[key] = value.entry.get() if value.entry.get() != '' else None # get images dic['image'] = getattr(self, 'image') return dic # validate form data def validate_form_data(self, data): try: for key, value in data.items(): if value == None and key not in ['confirmPwd', 'image']: raise Exception(camel_case(key), f'{key} Cannot be null!') elif key in ['firstName', 'lastName'] and not re.fullmatch( '[A-Za-z]{2,15}( [A-Za-z]{2,15})?', value): raise Exception( camel_case(key), f'\n1. Can contain 2 words with 1 space in between\n2.Must be between 2 - 15 alphabets each' ) elif key in [ 'userName', 'password' ] and not re.fullmatch('^[a-zA-Z0-9_.-]+$', value): raise Exception( camel_case(key), f'can only be alphanumeric and contain (. _ -)') elif key == 'email' and not re.fullmatch( '[^@]+@[^@]+\.[^@]+', value): raise Exception( camel_case(key), f'Please enter a valid email!\nExample: [email protected]' ) elif key == 'company' and value != None and not re.fullmatch( '^[a-zA-Z0-9_]+( [a-zA-Z0-9_]+)*$', value): raise Exception( camel_case(key), f'\n1. Must be between 4 - 20 characters\n2. Should not contain any special characters' ) elif key == 'gender' and value != None and value.lower( ) not in ['female', 'male']: raise Exception(camel_case(key), f'Gender must be either male or female!') elif key == 'confirmPwd' and value != data['password']: raise Exception( 'password confirmation', f'Passwords don\'t match, please confirm your password!' ) return True except Exception as ex: MessageModal(self, title=f'{ex.args[0]} Error', message=ex.args[1], messageType='error') return False def refresh_window(self, message=None): window = ProfileWindow(self.master) self.windowManager.run(window) if message != None: MessageModal(window, title=f'Success', message=message, messageType='info') self.destroy() def save_changes(self, event): data = self.get_form_data() # check if data is validated if self.validate_form_data(data) == True: # make changes on current user for key, value in data.items(): if hasattr(ProfileWindow.ACTIVE_USER, key): setattr(ProfileWindow.ACTIVE_USER, key, value) # save changes Container.save(ProfileWindow.ACTIVE_USER) # reload the window self.refresh_window('Changes saved succefully!') def remove_collaborator(self, relation): def delete_relation(relation): # delete relation Container.deleteObject(relation) # destroy message msg.destroy() # remove deleted collaborator's listItem for li in self.collaboratorsItems: if li.dataObject == relation: li.destroy() # self.collaboratorItems.remove(li) self.refresh_window( f'{relation.userTwo.userName} has been removed succefully!') # confirm with the user msg = MessageModal( self, title=f'Confirmation', message= f'Are you sure you want to remove {relation.userTwo.userName} from your collaboration list?', messageType='prompt', actions={'yes': lambda e: delete_relation(relation)})
def design(self): # Session items section self.frm_body.config(padx=0, pady=0) frm_sessions = Frame(self.frm_body, bg=background, width=300) frm_border = Frame(self.frm_body, highlightthickness=1, highlightbackground=border) frm_discussion = Frame(self.frm_body, bg=background) frm_sessions.pack_propagate(0) self.lv_sessions = Scrollable(frm_sessions, bg=silver) self.lv_sessions.pack(fill=BOTH, expand=1) frm_sessions.pack(side=LEFT, fill=Y) frm_border.pack(side=LEFT, fill=Y) frm_discussion.pack(side=LEFT, fill=BOTH, expand=1) # Discussion Section frm_head = Frame(frm_discussion, bg=white, pady=20, padx=20) frm_head.pack(side=TOP, fill=X) frm_border_bottom = Frame(frm_discussion, highlightthickness=1, highlightbackground=border) frm_border_bottom.pack(fill=X, side=TOP) frm_group = Frame(frm_head, bg=white) frm_group.pack(side=LEFT, fill=X) self.lbl_sessionName = Label(frm_group, bg=white, fg=teal, text=translate('Session\'s Title'), font='-size 18 -weight bold') self.lbl_sessionName.pack(anchor=N + W) self.lbl_memberCount = Label(frm_group, bg=white, fg=black, text='X members') self.lbl_memberCount.pack(anchor=N + W) self.btn_open_session = MainButton( frm_head, translate('Open Session'), 'open.png', btnCmd=lambda event: self.open_session(event)) self.btn_open_session.config(pady=5) self.btn_open_session.pack(side=RIGHT) frm_scrollable_container = Frame(frm_discussion, bg=black) frm_scrollable_container.pack_propagate(0) frm_scrollable_container.pack(side=TOP, fill=BOTH, expand=1) self.lv_messages = Scrollable(frm_scrollable_container, bg=background, padx=15, pady=15) self.lv_messages.pack(expand=1, fill=BOTH) frm_footer = Frame(frm_discussion, bg=white, pady=20, padx=20) frm_footer.pack(side=BOTTOM, fill=X) self.is_hint_deleted = False self.txt_message = Entry(frm_footer, highlightthickness=0, relief=FLAT, font='-size 12', fg=black) self.txt_message.insert(0, translate('Type your message here...')) self.txt_message.pack(side=LEFT, fill=BOTH, expand=1) def txt_message_focus(e): self.is_hint_deleted = True self.txt_message.delete(0, len(self.txt_message.get())) self.txt_message.bind('<FocusIn>', txt_message_focus) IconFrame(frm_footer, 'resources/icons/ui/send.png', 25, teal, command=lambda event: self.send_message( event, self.currentItem)).pack(side=RIGHT) frm_border_top = Frame(frm_discussion, highlightthickness=1, highlightbackground=border) frm_border_top.pack(side=BOTTOM, fill=X) self.frm_veil = Frame(frm_discussion, bg=background) self.frm_veil.place(relwidth=1, relheight=1, x=0, y=0)
def Configure_session(self, event, listItem): self.frm_veil.place_forget() self.fill_discussion(listItem.dataObject.session) self.lbl_sessionName['text'] = listItem.dataObject.session.title self.lbl_memberCount[ 'text'] = f'{Container.filter(Collaboration,Collaboration.sessionId == listItem.dataObject.session.id).count()+1} ' + translate( 'Members') self.txt_message.bind('<Return>', lambda event, listItem=listItem: self. send_message(event, listItem)) if self.currentItem != None: self.change_session_item_style(self.currentItem, self.CHAT_NORMAL) self.currentItem = listItem self.change_session_item_style(self.currentItem, self.CHAT_ACTIVE) currentSession = self.currentItem.dataObject.session # mark previous messages as seen prevmsgs = Container.filter( Message, Message.sessionId == currentSession.id, Message.userId != DiscussionWindow.ACTIVE_USER.id) # mark them as seen for m in prevmsgs: # check if already marked if len( Container.filter( SeenMessage, SeenMessage.messageId == m.id, SeenMessage.seerId == DiscussionWindow.ACTIVE_USER.id).all()) > 0: continue # mark as read Container.save( SeenMessage(date=datetime.datetime.now(), seer=DiscussionWindow.ACTIVE_USER, message=m))
def btn_next_step_config(self): self.btn_next.label.config( text=(translate('Sign Up') if self.current == len(self.forms) - 1 else translate('Next Step')))
def design(self): # lay out the container frames self.frm_in = Frame(self, bg=background, width=self.DEFAULT_WIDTH / 2, padx=100) self.frm_in.pack(side=RIGHT, expand=1, fill=BOTH) self.frm_up = Frame(self, bg=background, width=self.DEFAULT_WIDTH / 2, padx=100) self.frm_up.pack(side=LEFT, expand=1, fill=BOTH) self.frm_in.pack_propagate(0) self.frm_up.pack_propagate(0) # design the sign in side self.lbl_title_signin = Label(self.frm_in, text=translate('Sign in'), fg=teal, bg=background, font='-size 32 -weight bold') self.lbl_title_signin.pack(side=TOP, pady=(150, 50)) signin_config = [{ 'name': 'txt_in_username', 'label': translate('Username:'******'icon': 'account.png' }, { 'name': 'txt_in_password', 'label': translate('Password:'******'icon': 'key.png' }] # put the form in place for config in signin_config: Label(self.frm_in, text=config.get('label'), font='-size 11 -weight bold', fg=black, bg=background).pack(side=TOP, anchor=N + W, pady=(0, 5)) tb = TextBox(self.frm_in, 'resources/icons/ui/' + config.get('icon')) tb.pack(side=TOP, fill=X, anchor=N + W, pady=(0, 10)) if config.get('name') == 'txt_in_password': tb.entry.config(show='*') setattr(self, config.get('name'), tb) # buttons frm_in_btns = Frame(self.frm_in, bg=background) frm_in_btns.pack(side=TOP, fill=X, pady=(5, 0)) self.btn_signin = MainButton(frm_in_btns, translate('Sign In'), 'login.png', self.btn_signin_click, 8) self.btn_signin.pack(side=LEFT) self.btn_viewpwd = SecondaryButton(frm_in_btns, translate('View Password'), 'eye.png', self.btn_viewpassword_click, 8) self.btn_viewpwd.pack(side=RIGHT) # divider frm_in_divider = Frame(self.frm_in, bg=border) frm_in_divider.pack(side=TOP, fill=X, pady=(100, 5)) # extra options frame frm_in_xtra = Frame(self.frm_in, bg=background) frm_in_xtra.pack(side=TOP, fill=X) self.lbl_signup = Label(frm_in_xtra, fg=teal, font='-size 9', text=translate('Sign up'), bg=background) self.lbl_signup.pack(side=RIGHT) self.lbl_signup.bind('<Button-1>', self.lbl_signup_click) self.lbl_forgotpwd = Label(frm_in_xtra, fg=black, font='-size 9 -underline 1', text=translate('Forgot your password?'), bg=background) self.lbl_forgotpwd.pack(side=LEFT) self.lbl_forgotpwd.bind('<Button-1>', self.lbl_forgotpwd_click) # designing the sign up side self.up_congig = { translate('Step 1: Authentication Settings'): [{ 'name': 'txt_email', 'label': translate('Email:'), 'icon': 'mail.png' }, { 'name': 'txt_up_pwd', 'label': translate('Password:'******'icon': 'key.png' }, { 'name': 'txt_confirm', 'label': translate('Confirm Password:'******'icon': 'key.png' }], translate('Step 2: Identity Information'): [{ 'name': 'txt_up_username', 'label': translate('Username:'******'icon': 'account.png' }, { 'name': 'txt_firstname', 'label': translate('First Name:'), 'icon': 'account.png' }, { 'name': 'txt_lastname', 'label': translate('Last Name:'), 'icon': 'account.png' }], translate('Step 3: Personal Information'): [{ 'name': 'txt_gender', 'label': translate('Gender:'), 'icon': 'wc.png' }, { 'name': 'txt_company', 'label': translate('Company:'), 'icon': 'business.png' }] } # preparations self.current = 0 self.steptitles = [] self.checkpoints = [] self.forms = [] # sign up header self.lbl_title_signup = Label(self.frm_up, text=translate('Sign Up'), fg=teal, bg=background, font='-size 32 -weight bold') self.lbl_title_signup.pack(side=TOP, pady=(100, 30)) # step label self.lbl_step = Label(self.frm_up, text='Step X: Description', fg=black, bg=background, font='-size 12') self.lbl_step.pack(side=TOP) # map frame self.frm_map = Frame(self.frm_up, bg=background) self.frm_map.pack(side=TOP, fill=X, pady=(5, 0)) for s in self.up_congig.keys(): frm_cp = Frame(self.frm_map, highlightthickness=1, highlightbackground=teal, height=15, bg=white) frm_cp.pack(side=LEFT, fill=X, expand=1, padx=(0, 4 if list(self.up_congig.keys()).index(s) != len(self.up_congig.keys()) else 0)) self.checkpoints.append(frm_cp) # forms container self.frm_frmcontainer = Frame(self.frm_up, bg=background) self.frm_frmcontainer.pack(side=TOP, fill=X, pady=(30, 0)) for s in self.up_congig.keys(): tb_config = self.up_congig.get(s) frm_form = Frame(self.frm_frmcontainer, bg=background) for i in tb_config: Label(frm_form, text=i.get('label'), font='-size 11 -weight bold', fg=black, bg=background).pack(side=TOP, anchor=N + W, pady=(0, 5)) tb = TextBox(frm_form, 'resources/icons/ui/' + i.get('icon')) tb.pack(side=TOP, fill=X, anchor=N + W, pady=(0, 10)) if i.get('name') in ['txt_up_pwd', 'txt_confirm']: tb.entry.config(show='*') setattr(self, i.get('name'), tb) # save those entities self.steptitles.append(s) self.forms.append(frm_form) # extra sign up options frm_in_xtra = Frame(self.frm_up, bg=background) frm_in_xtra.pack(side=BOTTOM, fill=X, pady=(5, 75)) self.lbl_signin = Label(frm_in_xtra, fg=teal, font='-size 9', text=translate('Sign in'), bg=background) self.lbl_signin.pack(side=RIGHT) self.lbl_signin.bind('<Button-1>', self.lbl_signin_click) # divider frm_in_divider = Frame(self.frm_up, bg=border) frm_in_divider.pack(side=BOTTOM, fill=X) # buttons frm_up_btns = Frame(self.frm_up, bg=background) frm_up_btns.pack(side=BOTTOM, fill=X, pady=(0, 60)) self.btn_prev = DangerButton(frm_up_btns, translate('Go Back'), 'revert_history.png', self.btn_prev_click, 8) self.btn_prev.pack(side=LEFT) self.btn_next = SecondaryButton(frm_up_btns, translate('Next Step'), 'yes.png', self.btn_next_click, 8) self.btn_next.pack(side=RIGHT) # display the first step self.move_to(self.current) # creating the veil self.frm_veil = Frame(self, bg=teal) self.frm_veil.place(x=0, y=0, relwidth=0.5, relheight=1) # make it a non-resizable window self.resizable(0, 0)
class HomeWindow(TabbedWindow): PROJECT_LI = 0 SESSION_LI = 1 tabSettings = [ { 'icon': 'folder.png', 'text': translate('My Projects'), 'tag': 'tb_projects' }, { 'icon': 'session.png', 'text': translate('My Sessions'), 'tag': 'tb_sessions' } ] def __init__(self, root, **args): TabbedWindow.__init__(self, root, HomeWindow.tabSettings, 'Welcome', **args) # Design elements self.design() # Fill methods self.fill_projects() self.fill_sessions() def design(self): # lay out the components to project tab self.btn_container1 = Frame(self.tb_projects, bg=background, pady=10) self.btn_container1.pack (side=TOP, fill=X) # BOOKMARK: modal redirections # configure redirections to form modals createProjectModalCmnd = lambda e: (self.windowManager.get_module('CreateProjectModal'))( self, # BOOKMARK_DONE: create project button command lambda formModal: self.create(formModal) ) loadProjectModalCmnd = lambda e: (self.windowManager.get_module('LoadProjectModal'))( self, # BOOKMARK_DONE: create load project button command lambda formModal: self.create(formModal, HomeWindow.PROJECT_LI, True) ) createSessionModalCmnd = lambda e: (self.windowManager.get_module('CreateSessionModal'))( self, # BOOKMARK_DONE: create session button command lambda formModal: self.create(formModal, HomeWindow.SESSION_LI) ) joinSessionModalCmnd = lambda e: (self.windowManager.get_module('JoinModal'))( self, # BOOKMARK_DONE: join session command lambda formModal: self.join_session(formModal) ) joinProjectModalCmnd = lambda e: (self.windowManager.get_module('JoinModal'))( self, # BOOKMARK_DONE: join project command lambda formModal: self.join_project(formModal) ) self.btn_create_project = MainButton(self.btn_container1, translate('Create New Project'), 'new_project.png', createProjectModalCmnd) self.btn_create_project.pack(side=LEFT, padx=(0, 10)) self.btn_open = SecondaryButton(self.btn_container1, translate('Load From Device'), 'upload.png', loadProjectModalCmnd) self.btn_open.pack(side=LEFT, padx=(0, 10)) self.btn_open = SecondaryButton(self.btn_container1, translate('Access Project'), 'login.png', joinProjectModalCmnd) self.btn_open.pack(side=RIGHT) self.lv_project = Scrollable(self.tb_projects, bg=background, pady=15) self.lv_project.set_gridcols(4) self.lv_project.pack(fill=BOTH, expand=1) # lay out the components to session tab self.btn_container2 = Frame(self.tb_sessions, bg=background, pady=10, padx=1) self.btn_container2.pack (side=TOP, fill=X) self.btn_create_session = MainButton(self.btn_container2, translate('Create New Session'), 'new_session.png', createSessionModalCmnd) self.btn_create_session.pack(side=LEFT, padx=(0, 10)) self.btn_join_session = SecondaryButton(self.btn_container2, translate('Join Session'), 'login.png', joinSessionModalCmnd) self.btn_join_session.pack(side=RIGHT) self.lv_session = Scrollable(self.tb_sessions, bg=background, pady=15) self.lv_session.set_gridcols(4) self.lv_session.pack(fill=BOTH, expand=1) def set_image(self, li, image): if image != None: photo = getdisplayableimage(image,(li.winfo_width(),205)) li.lbl_image.configure(image=photo) li.lbl_image.image = photo def resize_image(self, event, li, image): self.set_image(li,image) # BOOKMARK_DONE: fill project items def fill_projects(self): # cleaning up old items self.lv_project.empty() # refilling for item in Container.filter(Project, Project.ownerId == HomeWindow.ACTIVE_USER.id): if Container.filter(Session, Session.projectId == item.id).first() == None: li = self.lv_project.grid_item(item, {'title': item.title, 'creationDate': item.creationDate, 'lastEdited': item.lastEdited, 'image': item.image}, None, lambda i: self.create_list_item(i), 15) self.set_image(li, item.image) li.lbl_image.bind('<Configure>', lambda e, l=li, image= item.image: self.resize_image(e, l, image)) # BOOKMARK_DONE: fill session items def fill_sessions(self): # cleaning up old items self.lv_session.empty() # refilling for item in Container.filter(Session): if item.owner == HomeWindow.ACTIVE_USER or Container.filter(Collaboration, Collaboration.userId == HomeWindow.ACTIVE_USER.id, Collaboration.sessionId == item.id).first() != None: li = self.lv_session.grid_item(item, {'title': item.title, 'creationDate': item.creationDate, 'lastEdited': item.project.lastEdited, 'memberCount': str(Container.filter(Collaboration,Collaboration.sessionId == item.id).count()+1), 'image': item.project.image}, None, lambda i: self.create_list_item(i, HomeWindow.SESSION_LI), 15) self.set_image(li, item.project.image) li.lbl_image.bind('<Configure>', lambda e, l=li, image= item.project.image: self.resize_image(e, l, image)) # BOOKMARK: Project List Item & Session List Item Creation Method def create_list_item(self, item: ListItem, liType: int = PROJECT_LI): item.configure (highlightthickness=1, highlightbackground=border, bg=white) comps = [] img_size = 205 img_thumb = Frame(item, height=img_size, bg=white) img_thumb.pack_propagate(0) # adding image label item.lbl_image = Label(img_thumb,bg='white') item.lbl_image.pack(fill=BOTH,expand=1) comps.append(item.lbl_image) border_bottom = Frame(item, bg=border) frm_info = Frame(item, bg=silver, padx=10, pady=10) frm_details = Frame(frm_info, bg=silver) lbl_title = Label(frm_info, text=item.bindings.get('title', '{title}'), bg=silver, fg=black, font='-size 18') lbl_title.pack(side=TOP, fill=X, pady=(0, 10)) comps.append(lbl_title) panel_settings = [ { 'label': translate('Created In:'), 'text': item.bindings.get('creationDate').strftime('%a, %d %b') if 'creationDate' in item.bindings else '{creationDate}' }, { 'label': translate('Edited In:'), 'text': item.bindings.get('lastEdited').strftime('%a, %d %b') if 'lastEdited' in item.bindings else '{lastEdited}' } ] if liType == HomeWindow.SESSION_LI: panel_settings.append({ 'label': translate('Members:'), 'text': item.bindings.get('memberCount', '{memberCount}') }) for i in panel_settings: frm = Frame(frm_details, bg=silver) frm.pack(side=LEFT, fill=X, expand=1) comps.append(frm) lbl_label = Label(frm, text=i.get('label'), fg=teal, bg=silver, font='-size 8') lbl_label.pack(fill=X) comps.append(lbl_label) lbl_text = Label(frm, text=i.get('text'), fg=gray, bg=silver, font='-size 9') lbl_text.pack(fill=X) comps.append(lbl_text) img_thumb.pack(fill=X, side=TOP) comps.append(img_thumb) border_bottom.pack(fill=X, side=TOP) frm_info.pack(fill=X, side=TOP) comps.append(frm_info) frm_details.pack(fill=X, side=TOP) comps.append(frm_details) # BOOKMARK_DONE: project item's menu def options_menu(e): # convert screen mouse position win_coords = self.to_window_coords(e.x_root, e.y_root) menu_buttons = [ { 'text': translate('Open'), 'icon': 'open.png', 'cmnd': lambda e: self.windowManager.run(ProjectWindow(self, item.dataObject)) if liType == HomeWindow.PROJECT_LI else self.windowManager.run(CollaborationWindow(self, item.dataObject)) }, { 'text': translate('Edit'), 'icon': 'edit.png', 'cmnd': lambda e: self.windowManager.run_tag('editor', item.dataObject) }, { 'text': translate('Share'), 'icon': 'share.png', 'cmnd': lambda e: (self.windowManager.get_module('ShareModal'))(self, lambda modal: self.generate_share_link(item.dataObject, modal)) }, { 'text': translate('Delete'), 'icon': 'delete.png', 'fg': danger, 'cmnd': lambda e: self.delete_project(item.dataObject) if liType == self.PROJECT_LI else self.delete_session(item.dataObject) }, { 'text': translate('Leave'), 'icon': 'logout.png', 'fg': danger, 'cmnd': lambda e: self.quit_session(item.dataObject) } ] # pop unwanted buttons if liType == self.SESSION_LI: # remove share button menu_buttons.pop(2) # remove delete or leave menu_buttons.pop(2 if item.dataObject.owner != HomeWindow.ACTIVE_USER else 3) else: # remove leave menu_buttons.pop() # show menu self.show_menu(x=win_coords[0], y=win_coords[1], width=150, height=200, options=menu_buttons) # options icon IconFrame(item, 'resources/icons/ui/menu.png', 10, teal, 32, options_menu, bg=white).place(relx=1-0.03, rely=0.02, anchor=N+E) for c in comps: c.bind('<Double-Button-1>', lambda e: self.windowManager.run(ProjectWindow(self, item.dataObject)) if liType == HomeWindow.PROJECT_LI else self.windowManager.run(CollaborationWindow(self, item.dataObject))) # BOOKMARK: this is how a COMMAND should be def create(self, modal, nature= PROJECT_LI, load= False): title = modal.get_form_data()['txt_title'] date = datetime.now() def create_project(bytesFile= None): project = Project(title= title, creationDate= datetime.now(), lastEdited= datetime.now(), owner= HomeWindow.ACTIVE_USER, file= bytesFile) Container.save(project) self.lv_project.grid_item(project, {'title': project.title, 'creationDate': project.creationDate, 'lastEdited': project.lastEdited}, None, lambda i: self.create_list_item(i, HomeWindow.PROJECT_LI), 15) def create_session(): project = Project(title= title+'Project', creationDate= date, lastEdited= date, owner= HomeWindow.ACTIVE_USER) session = Session(title= title, creationDate= date, owner= HomeWindow.ACTIVE_USER, project= project) message = Message(content=f'welcome to the chat',user=HomeWindow.ACTIVE_USER, session=session, sentDate=session.creationDate) Container.save(project, session, message) seenmessage = SeenMessage(date=session.creationDate, seer=HomeWindow.ACTIVE_USER, messageId=message.id) Container.save(seenmessage) self.lv_session.grid_item(session, {'title': session.title, 'creationDate': project.creationDate, 'lastEdited': project.lastEdited, 'memberCount': str(Container.filter(Collaboration,Collaboration.sessionId == session.id).count()+1)}, None, lambda i: self.create_list_item(i, HomeWindow.SESSION_LI), 15) def load_project(): title = modal.get_form_data()['txt_title'] filename: str= modal.lbl_filename['text'] if filename.endswith('...') != True and filename != '': create_project(filetobytes(filename)) if not re.fullmatch('^[a-zA-Z0-9_]+( [a-zA-Z0-9_]+)*$', title): MessageModal(self,title=f'Title error',message=f'\n1. Must be between 4 - 20 characters \n2. It should not contain any special character',messageType='error') else: create_session() if nature == HomeWindow.SESSION_LI else ( create_project() if load == False else load_project()) modal.destroy() def delete(self, dataObject): Container.deleteObject(dataObject) self.clean_notifications() self.refresh_window() def delete_project(self, dataObject): MessageModal(self,title=f'Confirmation',message=f'Do you want to delete [{dataObject.title}] project?',messageType='prompt',actions={'yes' : lambda e: self.delete(dataObject)}) def delete_session(self, dataObject): MessageModal(self,title=f'Confirmation',message=f'Do you want to delete [{dataObject.title}] session?',messageType='prompt',actions={'yes' : lambda e: self.delete(dataObject.project)}) def quit_session(self, dataObject): MessageModal(self,title=f'Confirmation',message=f'Do you want to quit [{dataObject.title}] session?',messageType='prompt',actions={'yes' : lambda e: self.delete(Container.filter(Collaboration, Collaboration.userId == HomeWindow.ACTIVE_USER.id, Collaboration.sessionId == dataObject.id).first())}) # BOOKMARK: this should redirect to the editor window def join_project(self, modal): link = modal.get_form_data()['txt_link'] slink = Container.filter(ShareLink, ShareLink.link == link).first() if slink == None: MessageModal(self, title= f'Link error' ,message= 'This link doesn\'t exist!', messageType= 'error') elif slink.expirationDate < datetime.now(): MessageModal(self, title= f'Link error' ,message= 'This link has expired!', messageType= 'error') else: if slink.project.owner != HomeWindow.ACTIVE_USER :noti = Notification(notificationTime= datetime.now(), type= NotificationType.JOINED.value, nature= NotificationNature.SHARELINK.value, invitationId= slink.id, actor= HomeWindow.ACTIVE_USER, recipient= slink.project.owner) modal.destroy() self.windowManager.run(EditorWindow(self.master, slink.project)) def join_session(self, modal): link = modal.get_form_data()['txt_link'] date = datetime.now() invlink = Container.filter(InvitationLink, InvitationLink.link == link).first() if invlink == None: MessageModal(self, title= f'Link error' ,message= 'This link doesn\'t exist!', messageType= 'error') elif invlink.expirationDate < datetime.now(): MessageModal(self, title= f'Link error' ,message= 'This link has expired!', messageType= 'error') elif Container.filter(Collaboration, Collaboration.userId == HomeWindow.ACTIVE_USER.id, Collaboration.sessionId == invlink.sessionId).first() != None or invlink.session.owner == HomeWindow.ACTIVE_USER: MessageModal(self, title= f'Error' ,message= f'You are already in {invlink.session.title} session!', messageType= 'error') else: # create relations if they don't exist if Container.filter(Relation,Relation.userOne == HomeWindow.ACTIVE_USER, Relation.userTwo == invlink.sender ).first() == None: Container.save(Relation(userOne= HomeWindow.ACTIVE_USER, userTwo= invlink.sender)) if Container.filter(Relation,Relation.userTwo == HomeWindow.ACTIVE_USER, Relation.userOne == invlink.sender ).first() == None: Container.save(Relation(userTwo= HomeWindow.ACTIVE_USER, userOne= invlink.sender)) # create collaboration Container.save(Collaboration(joiningDate= date, privilege= invlink.privilege, user= HomeWindow.ACTIVE_USER, session= invlink.session)) # add an acceptedInv type notification noti = Notification(notificationTime= date, type= NotificationType.JOINED.value, nature= NotificationNature.INVLINK.value, invitationId= invlink.id, actor= HomeWindow.ACTIVE_USER, recipient= invlink.sender) modal.destroy() self.windowManager.run(CollaborationWindow(self.master, invlink.session)) def generate_share_link(self, dataObject, modal): def set_link(link): modal.form[0]['input'].entry.delete(0,END) modal.form[0]['input'].entry.insert(0,link) def check_privilege(msg, modal, slink): def generate_link(msg2, modal, slink, privilege): msg2.destroy() if slink != None: Container.deleteObject(slink) link= f'bpmntool//{dataObject.title}/{datetime.now()}/' Container.save(ShareLink(link=link, expirationDate=datetime.now()+timedelta(days=1), privilege= privilege, project=dataObject)) self.clean_notifications() set_link(link) if msg != None: msg.destroy() msg2 = MessageModal(self,title=f'Confirmation',message=f'Do you want to grant this link the "edit" privilege?',messageType='prompt',actions={'yes' : lambda e: generate_link(msg2, modal, slink, 'edit'), 'no' : lambda e: generate_link(msg2, modal, slink, 'read')}) def set_old_link(msg,modal): set_link(slink.link) msg.destroy() slink = Container.filter(ShareLink, ShareLink.projectId == dataObject.id).first() if slink != None: msg = check_privilege(None, modal, slink) if slink.expirationDate < datetime.now() else MessageModal(self,title='Link found',message=f'An active link already exists, Do you want to override it?',messageType='prompt',actions={'yes': lambda e: check_privilege(msg, modal, slink) , 'no': lambda e: set_old_link(msg,modal)}) else: check_privilege(None, modal, None) def refresh_window(self, message=None): window = HomeWindow(self.master) self.windowManager.run(window) if message != None: MessageModal(window,title=f'Success',message=message,messageType='info') self.destroy()
def design(self): # Setup the tab of profile frm_form = Frame(self.tb_info, bg=background) frm_form.pack(fill=BOTH, expand=1) frm_form.rowconfigure(0, weight=1) frm_form.columnconfigure([0, 1, 2], weight=1) frm_image_column = Frame(frm_form, bg=background) frm_image_column.grid(row=0, column=0, padx=(0, 20)) Label(frm_image_column, pady=10, bg=background, font='-size 10 -weight bold', fg=black, text=translate('Profile Photo:'), anchor=N + W).pack(side=TOP, fill=X) frm_image = Frame(frm_image_column, bg=black, height=150) frm_image.pack(side=TOP, fill=X, pady=(0, 10)) self.lbl_image = Label(frm_image) SecondaryButton(frm_image_column, translate('Upload Image'), 'upload.png', btnCmd=lambda event: self.open_image(event)).pack( side=TOP, fill=X) for column in ProfileWindow.formSettings: # Prepare a form column frm_column = Frame(frm_form, bg=background) frm_column.grid(row=0, column=(1 + ProfileWindow.formSettings.index(column))) # Loop through groups for group in column: # Prepare group frm_group = Frame(frm_column, bg=background) frm_group.pack(side=TOP, pady=10, padx=(0, 20)) # Label and textbox Label(frm_group, bg=background, font='-size 10 -weight bold', fg=black, text=group.get('label'), anchor=N + W).pack(side=TOP, fill=X, pady=(0, 5)) txt = TextBox(frm_group, 'resources/icons/ui/' + group.get('icon')) if group['tag'] in ['password', 'confirmPwd']: txt.entry.config(show='*') txt.pack(side=TOP) # Save the textbox in a list in order to get its value self.textBoxes[group.get('tag')] = txt frm_footer = Frame(self.tb_info, bg=background) frm_footer.pack(side=BOTTOM, fill=X) MainButton( frm_footer, translate('Save Changes'), 'save.png', btnCmd=lambda event: self.save_changes(event)).pack(side=LEFT) # Setup the tab of saved collabs frm_tip = IconButton( self.tb_collabs, 'Saved Collaborators are all the users who have participated in a collaboration session with you.', '-size 12 -weight bold', white, 'resources/icons/ui/info.png', 10, None, black, bg=black, pady=10, padx=5) frm_tip.pack(side=TOP, fill=X) self.lv_collabs = Scrollable(self.tb_collabs, bg=background, pady=5) self.lv_collabs.set_gridcols(2) self.lv_collabs.pack(expand=1, fill=BOTH, pady=(15, 0))
class ProjectWindow(TabbedWindow): tabSettings = [{ 'icon': 'info.png', 'text': translate('General Info'), 'tag': 'tb_info' }, { 'icon': 'history.png', 'text': translate('History'), 'tag': 'tb_hist' }] lblSettings = [{ 'label': translate('Project\'s Title:'), 'prop': 'title' }, { 'label': translate('Creation Date:'), 'prop': 'creationDate' }, { 'label': translate('Last Edit:'), 'prop': 'lastEdit' }] def __init__(self, root, project=None, **args): TabbedWindow.__init__(self, root, ProjectWindow.tabSettings, project.title, **args) self.project = project self.historyItems = [] # Button settings self.btnSettings = [ { 'icon': 'edit.png', 'text': translate('Open Editor'), 'dock': LEFT, 'cmnd': lambda e: self.windowManager.run( EditorWindow(self.master, self.project)) }, { 'icon': 'share.png', 'text': translate('Share Project'), 'type': SecondaryButton, 'cmnd': lambda e: (self.windowManager.get_module('ShareModal'))( self, # BOOKMARK_DONE: Share Project Command lambda modal: self.generate_share_link( self.project, modal)) }, { 'icon': 'save.png', 'text': translate('Export as XML'), 'cmnd': lambda e: self. export_project('current_' + self.project.title, self.project. lastEdited, self.project.file) } ] # Design elements self.design() self.configure_settings() def get_btn_list(self, history): def ask_revert_changes(history): def revert_changes(msg, history): history.project.file = history.file history.project.lastEdited = history.editDate history.project.image = history.image Container.save(history.project) msg.destroy() for li in self.historyItems: if li.dataObject.editDate >= history.editDate: Container.deleteObject(li.dataObject) li.destroy() photo = getdisplayableimage(history.image, (self.frm_preview.winfo_width(), self.frm_preview.winfo_height())) self.lbl_image.configure(image=photo) self.lbl_image.image = photo MessageModal( self, title=f'Success', message= f'Changes reverted to the following date:\n{history.editDate.strftime("%x - %X")}!', messageType='info') getattr( self, 'lbl_' + ProjectWindow.lblSettings[2]['prop'] )['text'] = history.editDate.strftime( "%d/%m/%Y" ) if datetime.datetime.now( ).strftime("%x") != history.editDate.strftime( "%x") else 'Today at - ' + history.editDate.strftime("%X") msg = MessageModal( self, title=f'Confirmation', message=f'Are you sure you want to revert to that change?', messageType='prompt', actions={'yes': lambda e: revert_changes(msg, history)}) btns = [{ 'icon': 'save.png', 'text': translate('Export as XML'), 'cmd': lambda e: self.export_project(history.project.title, history. editDate, history.file) }, { 'icon': 'revert_history.png', 'text': translate('Revert'), 'cmd': lambda e: ask_revert_changes(history) }] return btns def design(self): # Putting the control buttons btn_container = Frame(self.frm_body, bg=background) btn_container.pack(fill=X, side=TOP) for i in self.btnSettings: childCount = len(btn_container.pack_slaves()) method = i.get('type', MainButton) btn = method(btn_container, i.get('text', 'Button'), i.get('icon', 'error.png'), i.get('cmnd', None)) btn.pack(side=i.get('dock', RIGHT), padx=(0 if childCount == 0 else 10, 0)) # Filling the information tab frm_label_container = Frame(self.tb_info, bg=black) frm_label_container.pack(side=TOP, fill=X) for i in ProjectWindow.lblSettings: frm_lbl_group = Frame(frm_label_container, bg=background) frm_lbl_group.pack(side=LEFT, fill=X, expand=1) lbl_label = Label(frm_lbl_group, bg=background, fg=teal, font='-size 16', text=i.get('label'), anchor='nw') lbl_label.pack(side=TOP, fill=X) lbl_prop = Label(frm_lbl_group, bg=background, fg=black, font='-size 13', text=i.get('prop'), anchor='nw') lbl_prop.pack(side=TOP, fill=X) setattr(self, 'lbl_' + i.get('prop'), lbl_prop) self.frm_preview = Frame(self.tb_info, bg=white, highlightthickness=1, highlightbackground=border) self.frm_preview.pack(expand=1, fill=BOTH, pady=15) self.frm_preview.update() def resize_image(event, label): if self.project.image != None: photo = getdisplayableimage(self.project.image, (self.frm_preview.winfo_width(), self.frm_preview.winfo_height())) label.configure(image=photo) label.image = photo self.lbl_image = Label(self.frm_preview, bg='white') self.lbl_image.pack(fill=BOTH, expand=1) self.lbl_image.bind('<Configure>', lambda e, l=self.lbl_image: resize_image(e, l)) # Filling the history tab self.frm_list_view = Scrollable(self.tb_hist, bg=background) self.frm_list_view.pack(expand=1, fill=BOTH, pady=(0, 15)) self.fill_history() def fill_history(self): # BOOKMARK: fill history items self.frm_list_view.empty() for i in Container.filter( History, History.projectId == self.project.id).order_by( History.editDate.desc()): li = ListItem( self.frm_list_view.interior, i, { 'username': f'{i.editor.userName} edited on {i.editDate.strftime("%d/%m/%Y at %X")}', 'image': i.editor.image }, self.get_btn_list(i)) li.pack(anchor=N + W, pady=(0, 10), fill=X, padx=5) self.historyItems.append(li) def configure_settings(self): def get_label(prop): return getattr(self, f'lbl_{prop}') # changing texts get_label( ProjectWindow.lblSettings[0]['prop'])['text'] = self.project.title get_label( ProjectWindow.lblSettings[1]['prop'] )['text'] = self.project.creationDate.strftime( "%d/%m/%Y" ) if datetime.datetime.now( ).strftime("%x") != self.project.creationDate.strftime( "%x") else 'Today at - ' + self.project.creationDate.strftime("%X") get_label( ProjectWindow.lblSettings[2]['prop'] )['text'] = self.project.lastEdited.strftime( "%d/%m/%Y" ) if datetime.datetime.now( ).strftime("%x") != self.project.lastEdited.strftime( "%x") else 'Today at - ' + self.project.lastEdited.strftime("%X") # update image if self.project.image == None: return # proceed photo = getdisplayableimage( self.project.image, (self.frm_preview.winfo_width(), self.frm_preview.winfo_height())) self.lbl_image.configure(image=photo) self.lbl_image.image = photo def export_project(self, title, date, fileBytes): if fileBytes == None: MessageModal(self, title='Error', message='No changes has been made on this project!', messageType='error') else: folderName = filedialog.askdirectory( initialdir="/", title='Please select a directory') if folderName != '': bytestofile(f'{folderName}', f'{title}_{date.strftime("%d-%m-%Y_%H-%M-%S")}', 'xml', fileBytes) MessageModal(self, title=f'Success', message=f'File saved in {folderName}!', messageType='info') def generate_share_link(self, dataObject, modal): def set_link(link): modal.form[0]['input'].entry.delete(0, END) modal.form[0]['input'].entry.insert(0, link) def check_privilege(msg, modal, slink): def generate_link(msg2, modal, slink, privilege): msg2.destroy() if slink != None: Container.deleteObject(slink) link = f'bpmntool//{dataObject.title}/{datetime.datetime.now()}/' Container.save( ShareLink(link=link, expirationDate=datetime.datetime.now() + datetime.timedelta(days=1), privilege=privilege, project=dataObject)) self.clean_notifications() set_link(link) if msg != None: msg.destroy() msg2 = MessageModal( self, title=f'Confirmation', message=f'Do you want to grant this link the "edit" privilege?', messageType='prompt', actions={ 'yes': lambda e: generate_link(msg2, modal, slink, 'edit'), 'no': lambda e: generate_link(msg2, modal, slink, 'read') }) def set_old_link(msg, modal): set_link(slink.link) msg.destroy() slink = Container.filter(ShareLink, ShareLink.projectId == dataObject.id).first() if slink != None: msg = check_privilege( None, modal, slink ) if slink.expirationDate < datetime.datetime.now( ) else MessageModal( self, title='Link found', message=f'A link already exists, Do you want to override it?', messageType='prompt', actions={ 'yes': lambda e: check_privilege(msg, modal, slink), 'no': lambda e: set_old_link(msg, modal) }) else: check_privilege(None, modal, None) def refresh(self): super().refresh() self.configure_settings() self.fill_history()