예제 #1
0
 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')
예제 #2
0
    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
예제 #3
0
    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)
예제 #4
0
    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()
예제 #5
0
 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)
예제 #6
0
 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)
예제 #7
0
    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)))
예제 #8
0
    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()
예제 #9
0
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()
예제 #10
0
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)})
예제 #11
0
    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)
예제 #12
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))
예제 #13
0
 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')))
예제 #14
0
 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)
예제 #15
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()
예제 #16
0
    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))
예제 #17
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()