Exemple #1
0
    def _create_layout(self):
        ''' 创建画面。 '''
        Gtk.Window.__init__(self, title=self.PROGRAM_NAME)

        # 设定窗口的大小。
        # TODO:应该记住上一次的大小
        self.set_default_size(800, 900)

        # 窗口的布局器
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)

        # 创建内部的控件。
        # - 菜单和工具栏
        self.ide_menu = ViewMenu(self, self.on_process_func)
        vbox.pack_start(self.ide_menu.menubar, False, False, 0)
        vbox.pack_start(self.ide_menu.toolbar, False, False, 0)

        # 产生棋盘
        self.create_game_panel()
        self.grid_game.set_size_request(600, 600)

        vbox.pack_start(self.grid_game, True, True, 5)
        vbox.show()

        # - 加入布局器。
        self.add(vbox)
    def _create_layout(self):
        '''
        创建画面。
        '''
        Gtk.Window.__init__(self, title=self.PROGRAM_NAME)

        # 总的布局器
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)

        # 菜单和工具栏
        self.ide_menu = ViewMenu(self, self.on_menu_func)
        vbox.pack_start(self.ide_menu.menubar, False, False, 0)
        vbox.pack_start(self.ide_menu.toolbar, False, False, 0)

        # 左右布局器:命令组列表和命令编辑器
        # - resize:子控件是否跟着paned的大小而变化。
        # - shrink:子控件是否能够比它需要的大小更小。

        # 左右布局器:命令组列表、命令组
        panedListAndCmdGp = Gtk.Paned.new(Gtk.Orientation.HORIZONTAL)

        # 命令组列表
        container, self.cmdgroupList = self._create_cmdgrp_list()
        panedListAndCmdGp.pack1(container, resize=False, shrink=True)

        # 打开的命令组内命令列表(多个列表的切换Tab)
        self.mutilePages = ViewMultiPages(self.on_menu_func)
        self.tab_page = self.mutilePages.get_notebook()

        panedListAndCmdGp.pack2(self.tab_page, resize=True, shrink=True)

        # 设定divider的位置.
        panedListAndCmdGp.set_position(400)

        vbox.pack_start(panedListAndCmdGp, True, True, 5)

        # - 加入布局器。
        self.add(vbox)
    def _create_layout(self):
        ''' 创建画面。 '''
        Gtk.Window.__init__(self, title=self.PROGRAM_NAME)

        # 设定窗口的大小。
        # TODO:应该记住上一次的大小
        self.set_default_size(800, 600)
        
        # 窗口的布局器
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        
        # 创建内部的控件。
        # - 菜单和工具栏
        self.ide_menu = ViewMenu(self, self.on_process_func)
        vbox.pack_start(self.ide_menu.menubar, False, False, 0)
        vbox.pack_start(self.ide_menu.toolbar, False, False, 0)
        
        # - resize:子控件是否跟着paned的大小而变化。
        # - shrink:子控件是否能够比它需要的大小更小。
        
        # 包含列表和文本命令
        panedListAndTextCmd = Gtk.Paned.new(Gtk.Orientation.HORIZONTAL)
        
        # 左边的处理列表。
        fstreeScroll, self.history_list = self.create_history_list()
        panedListAndTextCmd.pack1(fstreeScroll, resize=False, shrink=True)
        
        # 文本和命令控件
        panedTextAndCmd = Gtk.Paned.new(Gtk.Orientation.VERTICAL)
        
        # 输入处理文本的地方
        self.txt_source = GtkSource.View()
        #self.txt_source.set_wrap_mode(Gtk.WrapMode.WORD_CHAR)
        self.txt_source.set_show_line_numbers(True)
        self.txt_source.set_highlight_current_line(True)
        self.txt_source.set_tab_width(4)
        src_buffer = GtkSource.Buffer()
        self.txt_source.set_buffer(src_buffer)
        
        scrolledSource = Gtk.ScrolledWindow()
        scrolledSource.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
        scrolledSource.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        scrolledSource.add(self.txt_source)
        
        panedTextAndCmd.pack1(scrolledSource, resize=True, shrink=True)
        
        # 输入命令的文本框
        self.txt_command = GtkSource.View()
        self.txt_command.set_size_request(0, 200)
        
        src_buffer = GtkSource.Buffer()
        manager = GtkSource.LanguageManager()
        language = manager.get_language("sh")        # 设定语法的类型
        src_buffer.set_language(language)
        src_buffer.set_highlight_syntax(True)        # 语法高亮
        self.txt_command.set_buffer(src_buffer)
        
        buf = self.txt_command.get_buffer()
        self.tag_cmd_err = buf.create_tag("cmd_err", foreground = 'Red')
        self.tag_cmd_ok = buf.create_tag("cmd_ok", foreground = 'Black')
        
        scrolledCommand = Gtk.ScrolledWindow()
        scrolledCommand.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
        scrolledCommand.add(self.txt_command)
        
        panedTextAndCmd.pack2(scrolledCommand, resize=False, shrink=False)
        
        panedListAndTextCmd.pack2(panedTextAndCmd, resize=True, shrink=False)

        vbox.pack_start(panedListAndTextCmd, True, True, 5)
                
        # - 加入布局器。
        self.add(vbox)
class ViewWindow(Gtk.Window):
    
    '''
    ideWorkshop:ModelWorkshop:当前的workshop。
    cur_prj:ModelProject:当前打开的项目。
    '''
    
    ###################################
    ## 返回值的定义
    
    RLT_OK=0
    RLT_CANCEL=1    # 取消
    RLT_ERROR=2     # 错误
    
    PROGRAM_NAME='Visual Editor '
    
    '''
    总窗口。
    '''
    def __init__(self):
        # 创建画面
        self._create_layout()
        self._init_data()
        
        self.txt_command.grab_focus()

    def _create_layout(self):
        ''' 创建画面。 '''
        Gtk.Window.__init__(self, title=self.PROGRAM_NAME)

        # 设定窗口的大小。
        # TODO:应该记住上一次的大小
        self.set_default_size(800, 600)
        
        # 窗口的布局器
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        
        # 创建内部的控件。
        # - 菜单和工具栏
        self.ide_menu = ViewMenu(self, self.on_process_func)
        vbox.pack_start(self.ide_menu.menubar, False, False, 0)
        vbox.pack_start(self.ide_menu.toolbar, False, False, 0)
        
        # - resize:子控件是否跟着paned的大小而变化。
        # - shrink:子控件是否能够比它需要的大小更小。
        
        # 包含列表和文本命令
        panedListAndTextCmd = Gtk.Paned.new(Gtk.Orientation.HORIZONTAL)
        
        # 左边的处理列表。
        fstreeScroll, self.history_list = self.create_history_list()
        panedListAndTextCmd.pack1(fstreeScroll, resize=False, shrink=True)
        
        # 文本和命令控件
        panedTextAndCmd = Gtk.Paned.new(Gtk.Orientation.VERTICAL)
        
        # 输入处理文本的地方
        self.txt_source = GtkSource.View()
        #self.txt_source.set_wrap_mode(Gtk.WrapMode.WORD_CHAR)
        self.txt_source.set_show_line_numbers(True)
        self.txt_source.set_highlight_current_line(True)
        self.txt_source.set_tab_width(4)
        src_buffer = GtkSource.Buffer()
        self.txt_source.set_buffer(src_buffer)
        
        scrolledSource = Gtk.ScrolledWindow()
        scrolledSource.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
        scrolledSource.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        scrolledSource.add(self.txt_source)
        
        panedTextAndCmd.pack1(scrolledSource, resize=True, shrink=True)
        
        # 输入命令的文本框
        self.txt_command = GtkSource.View()
        self.txt_command.set_size_request(0, 200)
        
        src_buffer = GtkSource.Buffer()
        manager = GtkSource.LanguageManager()
        language = manager.get_language("sh")        # 设定语法的类型
        src_buffer.set_language(language)
        src_buffer.set_highlight_syntax(True)        # 语法高亮
        self.txt_command.set_buffer(src_buffer)
        
        buf = self.txt_command.get_buffer()
        self.tag_cmd_err = buf.create_tag("cmd_err", foreground = 'Red')
        self.tag_cmd_ok = buf.create_tag("cmd_ok", foreground = 'Black')
        
        scrolledCommand = Gtk.ScrolledWindow()
        scrolledCommand.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
        scrolledCommand.add(self.txt_command)
        
        panedTextAndCmd.pack2(scrolledCommand, resize=False, shrink=False)
        
        panedListAndTextCmd.pack2(panedTextAndCmd, resize=True, shrink=False)

        vbox.pack_start(panedListAndTextCmd, True, True, 5)
                
        # - 加入布局器。
        self.add(vbox)
        
    def create_history_list(self):
        ''' 创建文件系统树控件。 '''
        tree_source_cmd = ViewHistoryTextCmd(self.on_process_func)
        
        # 加入事件。
        select = tree_source_cmd.treeview.get_selection()
        #select.connect("changed", self.on_tree_source_cmd_selection_changed)
        #tree_source_cmd.treeview.connect("row-activated", self.on_tree_source_cmd_row_activated)
        
        return tree_source_cmd.scrolledwindow, tree_source_cmd
    
    ###################################
    ## 创建画面

    def _init_data(self):
        # 取得剪贴板
        atom = Gdk.atom_intern('CLIPBOARD', True)
        clipboard = self.get_clipboard(atom)
        
        clipboard.request_text(self.on_get_text_from_clipboard)
        
    def on_get_text_from_clipboard(self, clipboard, text):
        source_cmd = VxSourceCmd(text, None)
        clipboard.clear()
        
        VxSourceCmdMng.add(source_cmd)
        self.show_source_cmd(source_cmd)
        
    def show_source_cmd(self, source_cmd):
        self.history_list.refresh_model()
        
        self.set_source(source_cmd.source)
        self.set_command(source_cmd.command)
        
    def set_command_alert(self, alert):
        ''' 改变控件的颜色。'''
        
        buf = self.txt_command.get_buffer()
        if alert:
            tag = self.tag_cmd_err
        else:
            tag = self.tag_cmd_ok
            
        buf.apply_tag(tag, buf.get_start_iter(), buf.get_end_iter())
        
    def set_source(self, text):
        if text is None:
            self.txt_source.get_buffer().set_text("")
        else:
            self.txt_source.get_buffer().set_text(text)
        
    def set_command(self, text):
        if text is None:
            self.txt_command.get_buffer().set_text("")
        else:
            self.txt_command.get_buffer().set_text(text)
        
    def _copy_result_2_clipboard(self):
        atom = Gdk.atom_intern('CLIPBOARD', True)
        clipboard = self.get_clipboard(atom)
        
        buf = self.txt_source.get_buffer()
        text = buf.get_text(buf.get_start_iter(), buf.get_end_iter(), False)
        clipboard.set_text(text, len(text))
    
    ###################################
    ## 回调方法
    def on_process_func(self, widget, action, param=None):
        if action == ViewMenu.ACTION_DISCARD:
            # 退出程序,结果也不需要保存。
            self.vx_quit()
            
        elif action == ViewMenu.ACTION_APPLY:
            # 退出程序,但是当前结果放入到剪贴板中。
            self.vx_save_and_quit()
            
        elif action == ViewMenu.ACTION_EXECUTE:
            # 执行命令。
            self.ide_execute_cmd()
        elif action == ViewMenu.ACTION_KEEP:
            # 将当前结果放入到命令历史记录中。
            self.ide_close_command_group()
        elif action == ViewMenu.ACTION_UNDO:
            # 回退到上一个命令运行情况。
            self.ide_undo_execute()
        elif action == ViewMenu.ACTION_RESTORE:
            # 回退到最开始的状况。
            self.ide_restore_execute()
            
        elif action == ViewMenu.ACTION_BACK_TO:
            self.ide_back_to_source_cmd(param)
                        
        elif action == ViewMenu.ACTION_HELP_INFO:
            # 显示帮助信息。
            self.ide_help_info()
        
        else:
            print 'Unknown action %s' % (action)
            
    def on_src_bufer_changed(self, widget):
        ''' 当文件发了变化后。'''
        self._set_status(ViewMenu.STATUS_FILE_OPEN_CHANGED)
        
    def on_tree_source_cmd_selection_changed(self, selection):
        ''' 文件列表选择时,不是双击,只是选择变化时 '''
        #model, treeiter = selection.get_selected()
        #if treeiter != None:
        #    print "You selected", model[treeiter][1]
        pass
    
    def on_tree_source_cmd_row_activated(self, treeview, tree_path, column):
        ''' 双击了文件列表中的项目。
        如果是文件夹,就将当前文件夹变成这个文件夹。
        如果是文件,就打开。
        '''
        model = treeview.get_model()
        pathname = model._get_fp_from_tp(tree_path)
        abs_path = model.get_abs_filepath(pathname)
        
        if not os.access(abs_path, os.R_OK):
            print '没有权限进入此目录。'
            return
        
        if model.is_folder(tree_path):
            #new_model = FsTreeModel(abs_path)
            #treeview.set_model(new_model)
            
            #self.window.set_title(new_model.dirname)
            
            treeview.expand_row(tree_path, False)
        else:
            # 根据绝对路径显示名字。
            self.ide_open_file(None, abs_path)
    
    ###################################
    ## 基本功能
    
    def vx_quit(self):        
        Gtk.main_quit()
        
    def vx_save_and_quit(self):
        self._copy_result_2_clipboard()
        Gtk.main_quit()
        
    def ide_execute_cmd(self):
        
        buf = self.txt_command.get_buffer()
        str_cmd = buf.get_text(buf.get_start_iter(), buf.get_end_iter(), False)
        if is_empty(str_cmd):
            return
        
        buf = self.txt_source.get_buffer()
        str_source = buf.get_text(buf.get_start_iter(), buf.get_end_iter(), False)
        
        vx_source_cmd = VxSourceCmdMng.last()
        vx_source_cmd.command = str_cmd
        vx_source_cmd.source = str_source
        rlt_code, return_source_cmd = VxExecute.execute_cmd(vx_source_cmd)
        
        if rlt_code == 0:
            VxSourceCmdMng.add(return_source_cmd)
            self.show_source_cmd(return_source_cmd)
            self.set_command_alert(False)
        else:
            self.set_command_alert(True)
            # 显示错误信息
            dialog = Gtk.MessageDialog( modal=True,
                                   destroy_with_parent=True,
                                   message_type=Gtk.MessageType.ERROR,
                                   buttons=Gtk.ButtonsType.OK,
                                   text= ('错误号是 %d:' % rlt_code))
            dialog.format_secondary_text(return_source_cmd)
            dialog.run()
    
            dialog.destroy()
            
    def ide_undo_execute(self):
        if VxSourceCmdMng.len() == 1:
            return
        
        VxSourceCmdMng.pop()
        vx_source_cmd = VxSourceCmdMng.last()
        
        self.show_source_cmd(vx_source_cmd)
    
    def ide_restore_execute(self):
        if VxSourceCmdMng.len() == 1:
            return
        
        VxSourceCmdMng.pop()
        vx_source_cmd = VxSourceCmdMng.last()
        
        self.show_source_cmd(vx_source_cmd)
        
    def ide_back_to_source_cmd(self, vx_source_cmd):
        if VxSourceCmdMng.len() == 1:
            return
        
        VxSourceCmdMng.pop_to(vx_source_cmd)
        vx_source_cmd = VxSourceCmdMng.last()
        
        self.show_source_cmd(vx_source_cmd)
            
    def ide_open_command(self, widget, path=None):
        '''
        如果已经打开文件,关闭当前文件
        显示“挑选”文件。
        然后显示打开的文件。
        path:string:绝对路径。
        '''
        result = self.RLT_CANCEL
        
        if(path is None):
            dialog = Gtk.FileChooserDialog("请选择一个文件", self,
                    Gtk.FileChooserAction.OPEN,
                    (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                     Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
    
            self._add_filters(dialog)
    
            response = dialog.run()
            
            file_path = dialog.get_filename()
            dialog.reset_state()
        else:
            response = Gtk.ResponseType.OK
            file_path = path
        
        if response == Gtk.ResponseType.OK:
            print("File selected: " + file_path)
            
#             self.multiEditors.show_editor(file_path)
#             
#             view_editor = self.multiEditors.get_editor_by_path(file_path)
#             self._ide_search_init(view_editor.editor.get_buffer())
#             
#             # 分析标记
#             if self.cur_prj is not None:
#                 tags = self.cur_prj.query_tags_by_file(file_path)
#                 self.ide_refresh_file_tag_list(tags)
            self.ide_switch_page(file_path)

            result = self.RLT_OK

        elif response == Gtk.ResponseType.CANCEL:
            print("Cancel to open one file.")
            result = self.RLT_CANCEL
        
        self._set_status(ViewMenu.STATUS_FILE_OPEN)
        
        return result

    def ide_close_file(self, widget):
        '''
        如果打开了文件,
            如果文件已经修改过,保存当前的文件。
            关闭当前的文件。
            清除当前的Buffer。
        \return RLT_XXX
        '''
        print("ide close file.")
        
        ide_editor = self.multiEditors.get_current_ide_editor()
        if ide_editor is None or ide_editor.ide_file is None:
            print('No file is being opened')
            return self.RLT_OK
        
        needSave = False
        
        # 根据是否被修改了,询问是否需要保存。
        if ide_editor.editor.get_buffer().get_modified():
            dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.QUESTION, \
                                       Gtk.ButtonsType.YES_NO, "文件已经被改变,是否保存?")
            response = dialog.run()
            dialog.reset_state()
            if response == Gtk.ResponseType.YES:
                needSave = True

        # 需要保存,就保存,如果不需要,就直接关闭。
        if needSave:
            result = self.ide_save_file(widget)
            if result != self.RLT_OK:
                return result
        
        # 关闭文件
        self.multiEditors.close_editor(self.multiEditors.get_current_abs_file_path())
        
        self._set_status(ViewMenu.STATUS_FILE_NONE)
        
        return self.RLT_OK
        
    def ide_save_file(self, widget):
        '''
        如果当前文件已经打开,并且已经修改了,就保存文件。
        '''
        
        print('ide save file')
        
        ide_editor = self.multiEditors.get_current_ide_editor()
        if ide_editor is None:
            print('No file is being opened.')
            return self.RLT_OK
        
        src_buffer = ide_editor.editor.get_buffer()
        if src_buffer.get_modified():
            if ide_editor.ide_file.file_path is None:
                dialog = Gtk.FileChooserDialog("请选择一个文件", self,
                           Gtk.FileChooserAction.SAVE ,
                           (    Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                                Gtk.STOCK_OK, Gtk.ResponseType.OK))

                response = dialog.run()
                file_path = dialog.get_filename()
                dialog.reset_state()
                
                if response == Gtk.ResponseType.OK:
                    print("File selected: " + file_path)
                    
                    # 打开一个空的文件,或者里面已经有内容了。
                    ide_editor.ide_file.open_file(file_path)
                    self._set_src_language(src_buffer, file_path)

                elif response == Gtk.ResponseType.CANCEL:
                    print("Cancel to save one file.")
                    return self.RLT_CANCEL

            # 将内容保存到文件中。
            ide_editor.ide_file.save_file(self._ide_get_editor_buffer())
            src_buffer.set_modified(False)
            print('ide save file to disk file.')
        
        self._set_status(ViewMenu.STATUS_FILE_OPEN)
        
        return self.RLT_OK
        
    def ide_save_as_file(self, widget):
        '''
        显示对话框,选择另存为的文件名字。
        然后关闭当前文件,
        创建新的Ide文件,打开这个文件,并保存。
        '''
        print("ide save as other file.")
        
        ide_editor = self.multiEditors.get_current_ide_editor()
        old_file_path = self.multiEditors.get_current_abs_file_path()
        
        if ide_editor.ide_file == None:
            print('No file is being opened')
            return self.RLT_OK
        
        # 如果是新文件,则按照Save的逻辑进行
        src_buffer = self._ide_get_editor_buffer()
        if src_buffer.get_modified():
            if ide_editor.ide_file.file_path is None:
                return self.ide_save_file(widget)

        # 如果是已经打开的文件,就将当前文件保存成新文件后,关闭旧的,打开新的。
        # 设定新的文件路径   
        dialog = Gtk.FileChooserDialog("请选择一个文件", self, \
                                               Gtk.FileChooserAction.SAVE , \
                                               (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, \
                                                Gtk.STOCK_OK, Gtk.ResponseType.OK))

        response = dialog.run()
        file_path = dialog.get_filename()
        dialog.reset_state()

        if response == Gtk.ResponseType.CANCEL:
            print("Cancel to save as one file.")
            return self.RLT_CANCEL
        
        print("File selected: " + file_path)
        
        # 将当前文件保存成新文件
        shutil.copy(old_file_path, file_path)
        
        # 关闭原来的文件。
        # ide_editor.ide_file.close_file()
        self.multiEditors.close_editor(old_file_path)
        
        # 打开指定的文件,并保存       
        #self.current_idefile = ModelFile()
#         ide_editor.ide_file.open_file(file_path)
#         
#         ide_editor = self.multiEditors.get_current_ide_editor()
#         src_buffer = self._ide_get_editor_buffer()
#         self.current_idefile.save_file(src_buffer)
#         self._set_src_language(src_buffer, file_path)
#         src_buffer.set_modified(False)

        self.multiEditors.show_editor(file_path)
        
        # 切换当前的状态
        self._set_status(ViewMenu.STATUS_FILE_OPEN)
        
    def ide_help_info(self):
        dialog = ViewDialogInfo(self)
        dialog.run()
         
        dialog.reset_state()
        
    def ide_edit_redo(self, widget):
        ve_editor = self.multiEditors.get_current_ide_editor()
        if ve_editor is None:
            return
        
        src_buffer = ve_editor.editor.get_buffer()
        src_buffer.redo()
    
    def ide_edit_undo(self, widget):
        ve_editor = self.multiEditors.get_current_ide_editor()
        if ve_editor is None:
            return
        
        src_buffer = ve_editor.editor.get_buffer()
        src_buffer.undo()
        
    def ide_edit_cut(self, widget):
        ve_editor = self.multiEditors.get_current_ide_editor()
        if ve_editor is None:
            return
        
        atom = Gdk.atom_intern('CLIPBOARD', True)
        clipboard = ve_editor.editor.get_clipboard(atom)
        ve_editor.editor.get_buffer().cut_clipboard(clipboard, True)
        
    def ide_edit_copy(self, widget):
        ve_editor = self.multiEditors.get_current_ide_editor()
        if ve_editor is None:
            return
        
        atom = Gdk.atom_intern('CLIPBOARD', True)
        clipboard = ve_editor.editor.get_clipboard(atom)
        ve_editor.editor.get_buffer().copy_clipboard(clipboard)
        
    def ide_edit_paste(self, widget):
        ve_editor = self.multiEditors.get_current_ide_editor()
        if ve_editor is None:
            return
        
        atom = Gdk.atom_intern('CLIPBOARD', True)
        clipboard = ve_editor.editor.get_clipboard(atom)
        ve_editor.editor.get_buffer().paste_clipboard(clipboard, None, True)
    
    def ide_edit_select_all(self, widget):
        ve_editor = self.multiEditors.get_current_ide_editor()
        if ve_editor is None:
            return
        
        src_buffer = ve_editor.editor.get_buffer()
        src_buffer.select_range(src_buffer.get_start_iter(), src_buffer.get_end_iter())
        
    def ide_switch_page(self, abs_file_path):
        '''
        abs_file_path string 切换到的文件名字
        '''
        
        self.multiEditors.show_editor(abs_file_path)
        
        view_editor = self.multiEditors.get_editor_by_path(abs_file_path)
        self._ide_search_init(view_editor.editor.get_buffer())
            
        # 分析标记
        if self.cur_prj is not None:
            tags = self.cur_prj.query_tags_by_file(abs_file_path)
            self.ide_refresh_file_tag_list(tags)
            
        # 显示文件的路径。
        self.ide_set_title(abs_file_path)
        
        # 在文件树那里同步
        self.history_list.show_file(abs_file_path)
    
    ###################################
    ## 更加底层的功能
    def _add_filters(self, dialog):
        ''' 给对话框加入过滤器 '''
        # TODO:以后应该可以打开任意文件,然后根据后缀进行判断。
        filter_text = Gtk.FileFilter()
        filter_text.set_name("Text files")
        filter_text.add_mime_type("text/plain")
        dialog.add_filter(filter_text)

        filter_c = Gtk.FileFilter()
        filter_c.set_name("C/Cpp/hpp files")
        filter_c.add_mime_type("text/x-c")
        dialog.add_filter(filter_c)

        filter_py = Gtk.FileFilter()
        filter_py.set_name("Python files")
        filter_py.add_mime_type("text/x-python")
        dialog.add_filter(filter_py)

#         filter_any = Gtk.FileFilter()
#         filter_any.set_name("Any files")
#         filter_any.add_pattern("*")
#         dialog.add_filter(filter_any)

    def _set_src_language(self, src_buffer, file_path):
        manager = GtkSource.LanguageManager()
        
        if file_path is not None:
            language = manager.guess_language(file_path, None)        # 设定语法的类型
            src_buffer.set_language(language)
        else:
            src_buffer.set_language(None)
        
        return src_buffer
    
    def _set_status(self, status):
#         if self.current_idefile is None:
#             self.set_title(self.PROGRAM_NAME)
#         else:
#             if self.current_idefile.file_path is None:
#                 self.set_title(self.PROGRAM_NAME + ' New')
#             else:
#                 self.set_title(self.PROGRAM_NAME + ' ' + self.current_idefile.file_path)
        self.ide_set_title()

    def ide_set_title(self, title = ''):
        self.set_title(self.PROGRAM_NAME + ' ' + title)

        #TODO:不让状态变化。
        #self.ide_menu.set_status(status)
        self.ide_menu.set_status(ViewMenu.STATUS_FILE_OPEN_CHANGED)
        
    def ide_refresh_file_tag_list(self, tags):
        ''' 根据Tag的列表,更新文件对应的Tag列表
        tags:[IdeOneTag]:Tag列表。
        '''
        self.ideTagList.set_model(tags)
        
    def ide_goto_line(self, line_number):
        ''' 跳转到当前文件的行。
        line_number:int:行号(从1开始)
        '''
        #print 'goto line number:', line_number
        text_buf = self._ide_get_editor_buffer()
        it = text_buf.get_iter_at_line(line_number-1)
        
        text_buf.place_cursor(it)
        
        # 设定光标的位置,和什么都没有选中
        text_buf.select_range(it, it)
        # 屏幕滚动到这个地方。
        editor = self.multiEditors.get_current_editor()
        editor.scroll_to_iter(it, 0.25, False, 0.0, 0.5)
        
        # TODO:这里不是错误,而是给threads_add_idle返回不再继续调用的设定。
        return False
    
    def ide_editor_set_focus(self):
        ''' 获取焦点(延迟调用) '''
        Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE, self._ide_editor_set_focus)
    
    def _ide_editor_set_focus(self):
        ''' 获取焦点 '''
        editor = self.multiEditors.get_current_editor()
        editor.grab_focus()
    
    def ide_goto_file_line(self, file_path, line_number):
        ''' 跳转到指定文件的行。 '''
        # 先找到对应的文件
        # 然后再滚动到指定的位置
        #print 'jump to path:' + file_path + ', line:' + str(line_number)
        if self.ide_open_file(None, file_path) == self.RLT_OK:
            # 注意:这里采用延迟调用的方法,来调用goto_line方法,可能是buffer被设定后,
            # 还有其他的控件会通过事件来调用滚动,所以才造成马上调用滚动不成功。
            Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE, self.ide_goto_line, line_number)
    
    def ide_search_defination(self):
        ''' 查找定义
        '''
        tag_name = self._ide_get_selected_text_or_word()
        tags = self.cur_prj.query_defination_tags(tag_name)
        
        if len(tags) == 0:
            dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.INFO, \
                                       Gtk.ButtonsType.OK, "没有找到对应的定义。")
            dialog.run()
            dialog.reset_state()
            
        elif len(tags) == 1:
            ''' 直接跳转。 '''
            tag = tags[0]
            self.ide_goto_file_line(tag.tag_file_path, tag.tag_line_no)
        else:
            ''' 显示列表,让使用者挑选一个 '''
            tag = ViewDialogTagsOpen.show(self, tags)
            if tag:
                self.ide_goto_file_line(tag.tag_file_path, tag.tag_line_no)
    
    def ide_search_reference(self):
        ''' 查找引用
        '''
        tag_name = self._ide_get_selected_text_or_word()
        tags = self.cur_prj.query_reference_tags(tag_name)
        
        if len(tags) == 0:
            dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.INFO, \
                                       Gtk.ButtonsType.OK, "没有找到对应的引用。")
            dialog.run()
            dialog.reset_state()
            
        elif len(tags) == 1:
            ''' 直接跳转。 '''
            tag = tags[0]
            self.ide_goto_file_line(tag.tag_file_path, tag.tag_line_no)
        else:
            ''' 显示列表,让使用者挑选一个 '''
            tag = ViewDialogTagsOpen.show(self, tags)
            if tag:
                self.ide_goto_file_line(tag.tag_file_path, tag.tag_line_no)
    
    def ide_jump_to(self, line_number):
        self.ide_goto_line(line_number)
    
    def ide_find(self, search_entry):
        '''
        如果当前编辑器中有选中的文字,就将此文字放入检索本中。
        search_text string 需要检索的文字
        '''
        view_editor = self.multiEditors.get_current_ide_editor()
        if view_editor is None:
            return
        
        buf = view_editor.editor.get_buffer()
         
        if not buf.get_has_selection():
            return
         
        (start, end) = buf.get_selection_bounds()
         
        text = buf.get_text(start, end, False)

        search_entry.set_text(text)
    
    def _ide_search_init(self, text_buffer):
        self.search_text = None
        
        self.search_setting = GtkSource.SearchSettings.new()
        self.search_setting.set_regex_enabled(True)
        self.search_setting.set_case_sensitive(False)
        self.search_setting.set_wrap_around(True)
        
        self.search_context = GtkSource.SearchContext.new(text_buffer, self.search_setting)
        self.search_context.set_highlight(True)
        
    def _ide_search_text(self, text_buffer, search_text):
        
        self.search_context.get_settings().set_search_text(search_text)
        
        # -从当前的位置查找
        mark = text_buffer.get_insert()
        ite = text_buffer.get_iter_at_mark(mark)
        
        found, start_iter, end_iter = self.search_context.forward(ite)
        
        # 如果找到,就跳转到下面最近位置
        if found:
            line_num = start_iter.get_line()
            self.ide_jump_to(line_num)
    
    def _ide_search_text_next(self, text_buffer, search_text):
        # -从新位置查找
        mark = text_buffer.get_insert()
        ite = text_buffer.get_iter_at_mark(mark)
        
        found, start_iter, end_iter = self.search_context.forward(ite)
        
        # 如果找到,就跳转到下面最近位置
        if found:
            line_num = start_iter.get_line()
            self.ide_jump_to(line_num)
            
            text_buffer.move_mark_by_name("selection_bound", start_iter)
            text_buffer.move_mark_by_name("insert", end_iter)
            
    def ide_find_text(self, search_text):
        view_editor = self.multiEditors.get_current_ide_editor()
        if view_editor is None:
            return
        
        self._ide_search_text(view_editor.editor.get_buffer(), search_text)
        
    def ide_find_next(self, search_text):
        '''
        如果当前编辑器中有选中的文字,则直接显示对话框。
        对话框中的文字,缺省被选中,可以被全文粘贴。
        然后查找定义。 
        search_text string 需要检索的文字
        '''
        view_editor = self.multiEditors.get_current_ide_editor()
        if view_editor is None:
            return

        self._ide_search_text_next(view_editor.editor.get_buffer(), search_text)
        
    def ide_find_in_files(self):
        '''
        在多个文件中检索,比如文件夹内检索,打开的文件中检索,或者项目中检索等。
        '''
    
    def _ide_get_selected_text_or_word(self):
        ''' 从编辑器中得到当前被选中的文字,
        如果没有就返回光标所在的单词,
        如果都无法达到,就返回None 
        '''
        text_buf = self._ide_get_editor_buffer()
        selection = text_buf.get_selection_bounds()
        
        text = None
        if len(selection) > 0:
            # 已经有选中的文字。
            start, end = selection
            text = text_buf.get_text(start, end, False)
        else:
            
            # 没有选中任何的文字
            mark = text_buf.get_insert()
            word_start = text_buf.get_iter_at_mark(mark)
            word_end = text_buf.get_iter_at_mark(mark)

            # 得到以空格为区分的单词开头。
            while True:
                if word_start.starts_word():
                    n = word_start.copy()
                    # 获得前一个字符。
                    if not n.backward_char():
                        break
                    # 这里的算法应该有问题,如果判断为 空格,则不无法通过,不明白为什么?
                    if text_buf.get_text(n, word_start, False) != "_":
                        break
                    
                word_start.backward_word_start()
            
            # 得到以空格为区分的单词结尾。
            while True:
                if word_end.ends_word():
                    n = word_end.copy()
                    if not n.forward_char():
                        break
                    if text_buf.get_text(word_end, n, False) != "_":
                        break
                    
                word_end.forward_word_end()
                
            text = text_buf.get_text(word_start, word_end, False)
            
        print 'selected text or word is "', text, '"'

        return text
    
    def _ide_set_completion(self, ideProject):
        ''' 设定当前的编辑器的单词补足,当切换不同的Project时,才有必要 '''
        
        # 单词补齐,使用CompletionWords

        #配置单词自动补齐,使用自定义的CompletionProvider
        editor = self.multiEditors.get_current_editor()
        completion = editor.props.completion
        
        # 清除之前的所有provider
        providers = completion.get_providers()
        for p in providers:
            completion.remove_provider(p)

        # 加入新的Provider
        completion.add_provider(ideProject.get_completion_provider())

    def _ide_get_editor_buffer(self):
        editor = self.multiEditors.get_current_editor()
        if editor is None:
            return None
        
        return editor.get_buffer()
Exemple #5
0
    def __init__(self, NewWindow=False):
        self.get_font = Include.GetFontDetails()

        if NewWindow:  # When user wants to make a new window
            self.master = Toplevel()

            if 'Number of Windows' not in self.get_font:  # Tracking the number of Toplevel Windows
                self.get_font['Number of Windows'] = 1

            else:
                self.get_font['Number of Windows'] += 1

            Include.SaveFontDetails(self.get_font)

        else:  # When programs starts for the first time
            self.master = Tk()

        self.font = Font(family=self.get_font['Font Family'],
                         size=self.get_font['Font Size'])
        Include.ConfigFontStyle(self.get_font['Font Style'], self.font)

        self.menu = Menu(self.master)
        self.file_menu = Menu(self.menu, tearoff=0)
        self.edit_menu = Menu(self.menu, tearoff=0)
        self.format_menu = Menu(self.menu, tearoff=0)
        self.view_menu = Menu(self.menu, tearoff=0)
        self.help_menu = Menu(self.menu, tearoff=0)

        for label, menu in {
                'File': self.file_menu,
                'Edit': self.edit_menu,
                'Format': self.format_menu,
                'View': self.view_menu,
                'Help': self.help_menu
        }.items():
            self.menu.add_cascade(label=label, menu=menu)

        self.master.config(menu=self.menu)

        self.CanvasFrame = Frame(self.master)
        self.LineCanvas = Canvas(self.CanvasFrame, width=50)
        self.CanvasHSB = Scrollbar(self.CanvasFrame,
                                   orient='horizontal',
                                   command=self.LineCanvas.xview)
        self.LineCanvas.configure(xscrollcommand=self.CanvasHSB.set)
        self.CanvasHSB.pack(side='bottom', fill='x')
        self.LineCanvas.pack(side='left', fill='y')

        self.TextWidgetFrame = Frame(self.master, width=659, height=424)
        self.TextWidgetFrame.grid_propagate(False)
        self.TextWidget = Text(master=self.TextWidgetFrame,
                               bd=0,
                               undo=True,
                               font=self.font,
                               maxundo=-1,
                               autoseparators=True)
        self.VSB = Scrollbar(self.TextWidgetFrame,
                             orient='vertical',
                             command=self.TextWidget.yview)
        self.HSB = Scrollbar(self.TextWidgetFrame,
                             orient='horizontal',
                             command=self.TextWidget.xview)
        self.TextWidget.configure(yscrollcommand=self.VSB.set,
                                  xscrollcommand=self.HSB.set)

        self.TextWidget.grid(row=0, column=0, sticky='nsew')
        self.VSB.grid(row=0, column=1, sticky='ns')
        self.HSB.grid(row=1, column=0, sticky='ew')

        self.TextWidgetFrame.grid_rowconfigure(0, weight=1)
        self.TextWidgetFrame.grid_columnconfigure(0, weight=1)
        self.TextWidget.focus_set()
        self.TextWidgetFrame.pack(side='top', fill='both', expand=True)

        self.LineColumnVar = StringVar()
        self.status_label_var = StringVar()
        self.LineColumnVar.set('Ln 1, Col 1')

        self.StatusBarFrame = Frame(self.TextWidgetFrame)
        self.StatusBarFrame.grid(row=2, column=0, sticky='e')

        self.StatusLabel = Label(self.StatusBarFrame,
                                 textvariable=self.status_label_var)
        self.StatusLabel.grid(row=0, column=0, sticky='w')
        self.LineColumn = Label(self.StatusBarFrame,
                                textvariable=self.LineColumnVar)
        self.LineColumn.grid(row=0, column=1, ipadx=20)
        self.ZoomLabel = Label(self.StatusBarFrame, text='100%')
        self.ZoomLabel.grid(row=0, column=2, ipadx=10)
        self.TextFormatter = Label(self.StatusBarFrame, text='Windows (CRLF)')
        self.TextFormatter.grid(row=0, column=3, ipadx=14)
        self.encoding = Label(self.StatusBarFrame, text='UTF-8')
        self.encoding.grid(row=0, column=4, ipadx=10)

        self.fmc = FileMenu.File_Menu(self.master, self.TextWidget,
                                      self.status_label_var)
        self.FileMenuOptions = [
            'New', 'New Window ', 'Open... ', 'Save', 'SaveAs...', 'Exit'
        ]
        self.FileMenuCommands = [
            self.fmc.New, self.fmc.NewWindow, self.fmc.Open, self.fmc.Save,
            self.fmc.SaveAs, self.exit
        ]
        self.FileMenuAccelerator = [
            'Ctrl+N', 'Ctrl+Shift+N', 'Ctrl+O', 'Ctrl+S', 'Ctrl+Shift+S',
            'Ctrl+Q'
        ]

        self.emc = EditMenu.Edit_Menu(self.master, self.TextWidget,
                                      self.status_label_var)
        self.EditMenuOptions = [
            'Undo', 'Cut', 'Copy', 'Paste', 'Delete', 'Search with Google',
            'Find...', 'Replace...', 'Go To...', 'Select All', 'Time / Date',
            'Strip Trailing Whitespace'
        ]
        self.EditMenuCommands = [
            self.emc.undo, self.emc.cut, self.emc.copy, self.emc.paste,
            self.emc.delete, self.emc.SearchWithGoogle, self.emc.FindWidget,
            self.emc.ReplaceWidget, self.emc.GoToWidget, self.emc.SelectAll,
            self.emc.GetDateTime, self.emc.StripWhitespaces
        ]
        self.EditMenuAccelerator = [
            'Ctrl+Z', 'Ctrl+X', 'Ctrl+C', 'Ctrl+V', 'DEL', 'Ctrl+E', 'Ctrl+F',
            'Ctrl+H', 'Ctr+G', 'Ctrl+A', 'F5', 'Alt+Enter'
        ]

        self.Fmc = FormatMenu.Format(self.master, self.TextWidget, self.font)
        self.FormatMenuOptions = ['Word Wrap', 'Font...']
        self.FormatMenuAccelerator = ['Ctrl+W', 'Ctrl+Shift+F']

        self.vmc = ViewMenu.View(self.master, self.TextWidget,
                                 self.TextWidgetFrame, self.CanvasFrame,
                                 self.LineCanvas, self.StatusBarFrame,
                                 self.ZoomLabel, self.font)
        self.ViewMenuOptions = [
            'Zoom', 'Status Bar', 'FullScreen', 'Show Line Numbers'
        ]
        self.ZoomCommands = [
            self.vmc.ZoomIn, self.vmc.ZoomOut, self.vmc.DefaultZoom
        ]
        self.ViewMenuZoomAccelerator = {
            'Zoom In': '            Ctrl+Plus',
            'Zoom Out': '        Ctrl+Minus',
            'Restore Default Zoom': '                 Ctrl+0'
        }

        self.HelpMenuOptions = ['About']
        self.HelpMenuAccelerator = ['F12']
        self.HelpMenuCommands = [self.about]

        for index, value in enumerate(self.FileMenuOptions):
            if index in [5, 7]:
                self.file_menu.add_separator()

            self.file_menu.add_command(
                label=value.ljust(23),
                accelerator=self.FileMenuAccelerator[index],
                command=self.FileMenuCommands[index])

        for index, value in enumerate(self.EditMenuOptions):
            if index in [1, 5, 11]:
                self.edit_menu.add_separator()

            self.edit_menu.add_command(
                label=value.ljust(40),
                accelerator=self.EditMenuAccelerator[index],
                command=self.EditMenuCommands[index])

        for index, value in enumerate(self.FormatMenuOptions):
            if index == 1:
                self.format_menu.add_command(
                    label=value.ljust(30),
                    accelerator=self.FormatMenuAccelerator[index],
                    command=self.Fmc.FontSelection)

            else:
                self.format_menu.add_checkbutton(
                    label=value,
                    onvalue=True,
                    offvalue=False,
                    variable=self.Fmc.WrapAroundVar,
                    accelerator=self.FormatMenuAccelerator[index],
                    command=self.Fmc.WrapAround)

        for index, value in enumerate(self.ViewMenuOptions):
            if index == 0:
                self.sub_view_menu = Menu(self.view_menu, tearoff=0)
                self.view_menu.add_cascade(label=value,
                                           menu=self.sub_view_menu)

                for index, values in enumerate(
                        self.ViewMenuZoomAccelerator.items()):
                    self.sub_view_menu.add_command(
                        label=values[0],
                        accelerator=values[1],
                        command=self.ZoomCommands[index])

            elif index == 1:
                self.view_menu.add_checkbutton(
                    label=value,
                    onvalue=1,
                    offvalue=False,
                    variable=self.vmc.ShowStatusBar,
                    accelerator='Alt+S'.rjust(30),
                    command=self.vmc.toggle_statusbar)

            elif index == 2:
                self.view_menu.add_checkbutton(
                    label=value,
                    onvalue=1,
                    offvalue=False,
                    variable=self.vmc.FullScreenVar,
                    accelerator='F11'.rjust(28),
                    command=self.vmc.set_full_screen)

            elif index == 3:
                self.view_menu.add_checkbutton(
                    label=value,
                    onvalue=1,
                    offvalue=False,
                    variable=self.vmc.LineNumberVar,
                    accelerator='Alt+L'.rjust(30),
                    command=self.vmc.ToggleLineNumber)

        for index, value in enumerate(self.HelpMenuOptions):
            self.help_menu.add_command(
                label=value.ljust(20),
                accelerator=self.HelpMenuAccelerator[index],
                command=self.HelpMenuCommands[index])

        self.Fmc.WrapAround()
        self.vmc.ToggleLineNumber()
        self.UpdateLineColumn()
        self.EnableDisableMenu()
        self.UpdateLabelText()

        self.TextWidget.bind('<Control-q>', self.exit)
        self.TextWidget.bind('<Button-3>', self.button_3)
        self.TextWidget.bind('<Delete>', self.emc.delete)
        self.TextWidget.bind('<Control-n>', self.fmc.New)
        self.TextWidget.bind('<Control-x>', self.emc.cut)
        self.TextWidget.bind('<Control-o>', self.fmc.Open)
        self.TextWidget.bind('<Control-s>', self.fmc.Save)
        self.TextWidget.bind('<Control-z>', self.emc.undo)
        self.TextWidget.bind('<Control-c>', self.emc.copy)
        self.TextWidget.bind('<BackSpace>', self.backspace)
        self.TextWidget.bind('<Control-v>', self.emc.paste)
        self.TextWidget.bind('<Key>', self.RemoveSelection)
        self.TextWidget.bind('<F5>', self.emc.GetDateTime)
        self.master.bind('<F12>', self.HelpMenuCommands[0])
        self.master.protocol('WM_DELETE_WINDOW', self.exit)
        self.TextWidget.bind('<Control-S>', self.fmc.SaveAs)
        self.TextWidget.bind('<Control-N>', self.fmc.NewWindow)
        self.TextWidget.bind('<Control-a>', self.emc.SelectAll)
        self.TextWidget.bind('<Control-N>', self.fmc.NewWindow)
        self.TextWidget.bind('<Control-plus>', self.vmc.ZoomIn)
        self.TextWidget.bind('<Control-g>', self.emc.GoToWidget)
        self.TextWidget.bind('<MouseWheel>', self.vmc.WheelZoom)
        self.TextWidget.bind('<Button-1>', self.SingleLeftClick)
        self.TextWidget.bind('<Control-f>', self.ShowFindWidget)
        self.TextWidget.bind('<Control-minus>', self.vmc.ZoomOut)
        self.TextWidget.bind('<Control-0>', self.vmc.DefaultZoom)
        self.TextWidget.bind('<Triple-Button-1>', self.TripleClick)
        self.TextWidget.bind('<Control-h>', self.ShowReplaceWidget)
        self.master.bind('<F11>', lambda e: self.view_menu.invoke(2))
        self.master.bind('<Alt-s>', lambda e: self.view_menu.invoke(1))
        self.TextWidget.bind('<Control-e>', self.emc.SearchWithGoogle)
        self.TextWidget.bind('<Double-Button-1>', self.DoubleLeftClick)
        self.TextWidget.bind('<Alt-Return>', self.ActivateStripWhiteSpace)
        self.master.after(0, lambda: Include.initial_position(self.master))
        self.TextWidget.bind('<Alt-l>', lambda e: self.view_menu.invoke(3))
        self.TextWidget.bind('<Control-F>', lambda e: self.Fmc.FontSelection())
        self.TextWidget.bind('<Control-w>',
                             lambda e: self.format_menu.invoke(0))
        self.TextWidget.bind(
            '<Configure>', lambda e: self.TextWidget.configure(
                scrollregion=self.TextWidget.bbox('end')))
        self.master.mainloop()
 def initUi(self):
     self.setWindowTitle("Canteen")
     self.listWidget.currentRowChanged.connect(
         self.stackedWidget.setCurrentIndex
     )  #core feature, connect row change with the stack widget and display
     self.listWidget.setFrameShape(QListWidget.NoFrame)
     self.listWidget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
     self.listWidget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
     #add left side list widgets
     item = QListWidgetItem(QIcon(''), str('Main Page'), self.listWidget)
     item.setSizeHint(QSize(16777215, 80))
     item.setTextAlignment(Qt.AlignCenter)
     item = QListWidgetItem(QIcon('./Logo/McDonald.ico'), str('McDonalds'),
                            self.listWidget)
     item.setSizeHint(QSize(16777215, 80))
     item.setTextAlignment(Qt.AlignCenter)
     item = QListWidgetItem(QIcon('./Logo/Subway.ico'), str('Subway'),
                            self.listWidget)
     item.setSizeHint(QSize(16777215, 80))
     item.setTextAlignment(Qt.AlignCenter)
     item = QListWidgetItem(QIcon('./Logo/Malay_food.ico'), str('Malay'),
                            self.listWidget)
     item.setSizeHint(QSize(16777215, 80))
     item.setTextAlignment(Qt.AlignCenter)
     item = QListWidgetItem(QIcon('./Logo/kFC.ico'), str('KFC'),
                            self.listWidget)
     item.setSizeHint(QSize(16777215, 80))
     item.setTextAlignment(Qt.AlignCenter)
     item = QListWidgetItem(str('View menu'), self.listWidget)
     item.setSizeHint(QSize(16777215, 80))
     item.setTextAlignment(Qt.AlignCenter)
     item = QListWidgetItem(str('Cart and pay'), self.listWidget)
     item.setSizeHint(QSize(16777215, 80))
     item.setTextAlignment(Qt.AlignCenter)
     #------------------------------------------------------------------------------------------------------------
     #------------------------------------------------------------------------------------------------------------
     #------------------------------------------------------------------------------------------------------------
     #add right side stack widget
     # Main page
     main_window = Main_Page1.SlippedImgWidget('Pictures/bg.jpg',
                                               'Pictures/fg.PNG')
     self.stackedWidget.addWidget(main_window)
     #Mcdonalds Page
     time_zone = pytz.timezone('Asia/Singapore')
     current_time = datetime.now(time_zone)
     if current_time.hour <= 12:
         McDonalds_window = McDonalds.Breakfast_Mcdonald()
     elif current_time.hour > 12:
         McDonalds_window = McDonalds.Lunch_Mcdonald()
     self.stackedWidget.addWidget(McDonalds_window)
     #Subway Page
     label = QLabel('Dummy Page ', self)
     label.setAlignment(Qt.AlignCenter)
     label.setStyleSheet(
         'background: rgb(%d, %d, %d);margin: 50px;' %
         (randint(0, 255), randint(0, 255), randint(0, 255)))
     self.stackedWidget.addWidget(label)
     #Malay Page
     label = QLabel('Dummy Page ', self)
     label.setAlignment(Qt.AlignCenter)
     label.setStyleSheet(
         'background: rgb(%d, %d, %d);margin: 50px;' %
         (randint(0, 255), randint(0, 255), randint(0, 255)))
     self.stackedWidget.addWidget(label)
     #KFC Page
     label = QLabel('Dummy Page ', self)
     label.setAlignment(Qt.AlignCenter)
     label.setStyleSheet(
         'background: rgb(%d, %d, %d);margin: 50px;' %
         (randint(0, 255), randint(0, 255), randint(0, 255)))
     self.stackedWidget.addWidget(label)
     #view menu page
     view_menu_window = ViewMenu.View_Menu()
     self.stackedWidget.addWidget(view_menu_window)
     #pay and cart page
     pay_and_cart_window = CartPay.Cart_Pay()
     self.stackedWidget.addWidget(pay_and_cart_window)
class ViewWindow(Gtk.Window):
    '''
    ideWorkshop:ModelWorkshop:当前的workshop。
    cur_prj:ModelProject:当前打开的项目。
    '''

    ###################################
    ## 返回值的定义
    RLT_OK = 0  # 正常
    RLT_CANCEL = 1  # 取消
    RLT_ERROR = 2  # 错误

    PROGRAM_NAME = 'Visual Command 版本 0.1 '
    '''
    总窗口。
    '''
    def __init__(self, workshop_dir):

        self.workshop_dir = workshop_dir

        # 创建画面
        self._create_layout()

    ###########################################################################
    ## 创建画面

    def _create_layout(self):
        '''
        创建画面。
        '''
        Gtk.Window.__init__(self, title=self.PROGRAM_NAME)

        # 总的布局器
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)

        # 菜单和工具栏
        self.ide_menu = ViewMenu(self, self.on_menu_func)
        vbox.pack_start(self.ide_menu.menubar, False, False, 0)
        vbox.pack_start(self.ide_menu.toolbar, False, False, 0)

        # 左右布局器:命令组列表和命令编辑器
        # - resize:子控件是否跟着paned的大小而变化。
        # - shrink:子控件是否能够比它需要的大小更小。

        # 左右布局器:命令组列表、命令组
        panedListAndCmdGp = Gtk.Paned.new(Gtk.Orientation.HORIZONTAL)

        # 命令组列表
        container, self.cmdgroupList = self._create_cmdgrp_list()
        panedListAndCmdGp.pack1(container, resize=False, shrink=True)

        # 打开的命令组内命令列表(多个列表的切换Tab)
        self.mutilePages = ViewMultiPages(self.on_menu_func)
        self.tab_page = self.mutilePages.get_notebook()

        panedListAndCmdGp.pack2(self.tab_page, resize=True, shrink=True)

        # 设定divider的位置.
        panedListAndCmdGp.set_position(400)

        vbox.pack_start(panedListAndCmdGp, True, True, 5)

        # - 加入布局器。
        self.add(vbox)

    def _create_cmdgrp_list(self):
        ''' 创建包含命令组的列表(实际上是Tree来实现的)。 '''

        vc_cmd_groups = VcCmdGroupMng.instance().cmd_groups
        cmdgroupTree = ViewCmdGroupTree(self.on_menu_func, vc_cmd_groups)

        return cmdgroupTree.scrolledWindow, cmdgroupTree

    ###########################################################################
    ## 回调方法

    def on_menu_func(self, widget, action, param=None):
        ''' 从菜单等过来的命令,在这里执行。'''

        if action == ViewMenu.ACTION_APP_QUIT:
            self.ide_quit(widget)

        elif action == ViewMenu.ACTION_COMMAND_GROUP_NEW:  # 添加一个命令组
            self.ide_new_command_group()
        elif action == ViewMenu.ACTION_COMMAND_GROUP_OPEN:  # 显示一个命令组
            self.ide_open_command_group(param.get_key())
        elif action == ViewMenu.ACTION_COMMAND_GROUP_CLOSE:  # 不显示一个命令组
            if param is None:
                name = None
            else:
                name = param.get_key()
            self.ide_close_command_group(name)
        elif action == ViewMenu.ACTION_COMMAND_GROUP_SAVE:  # 保存一个命令组
            self.ide_save_command_group()
        elif action == ViewMenu.ACTION_COMMAND_GROUP_DELETE:  # 删除一个命令组
            self.ide_delete_command_group()

        elif action == ViewMenu.ACTION_COMMAND_ADD:  # 向命令组中添加一个命令
            self.ide_add_cmd()
        elif action == ViewMenu.ACTION_COMMAND_DELETE:  # 删除一个命令
            self.ide_del_cmd()
        elif action == ViewMenu.ACTION_COMMAND_MODIFY:  # 想修改一个命令        -- 不需要
            pass
        elif action == ViewMenu.ACTION_COMMAND_UP:  # 将命令在命令组中的位置提高一个
            self.ide_move_up_cmd()
        elif action == ViewMenu.ACTION_COMMAND_DOWN:  # 将命令在命令组中的位置降低一个
            self.ide_move_down_cmd()

        elif action == ViewMenu.ACTION_HELP_INFO:
            self.ide_help_info()

        else:
            print 'Unknown action %d' % action

    def on_src_buffer_changed(self, widget):
        ''' 当文件发了变化后。'''
        self._set_status(ViewMenu.STATUS_FILE_OPEN_CHANGED)

    ###################################
    ## 基础功能实现

    def ide_quit(self, widget):
        '''
        如果打开了当前文件,且修改过了,需要保存。
        关闭当前文件。
        退出程序。
        '''

        result = self.ide_close_command_group(widget)
        if result != self.RLT_OK:
            return result

        Gtk.main_quit()

    def ide_new_command_group(self):
        ''' 生成一个新的命令组 '''
        dlg_response, cmd_grg_name = ViewDialogNewCommandGroup.show(self)
        if dlg_response != Gtk.ResponseType.OK:
            return False

        # 显示在左边的列表中。
        self.cmdgroupList.add_new_cmd_grp(cmd_grg_name)

    def ide_open_command_group(self, cmdgroup_name):
        # 打开指定的命令组编辑器
        self.mutilePages.show_command_group(cmdgroup_name)

    def ide_close_command_group(self, name):
        # 关闭目前正在打开的命令组编辑器
        self.mutilePages.close_command_group(name)

    def ide_save_file(self, widget):
        '''
        如果当前文件已经打开,并且已经修改了,就保存文件。
        '''

        print('ide save file')

        ide_editor = self.multiEditors.get_current_ide_editor()
        if ide_editor is None:
            print('No file is being opened.')
            return self.RLT_OK

        src_buffer = ide_editor.cmdList.get_buffer()
        if src_buffer.get_modified():
            if ide_editor.ide_file.file_path is None:
                dialog = Gtk.FileChooserDialog(
                    "请选择一个文件", self, Gtk.FileChooserAction.SAVE,
                    (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OK,
                     Gtk.ResponseType.OK))

                response = dialog.run()
                file_path = dialog.get_filename()
                dialog.reset_state()

                if response == Gtk.ResponseType.OK:
                    print("File selected: " + file_path)

                    # 打开一个空的文件,或者里面已经有内容了。
                    ide_editor.ide_file.open_file(file_path)
                    self._set_src_language(src_buffer, file_path)

                elif response == Gtk.ResponseType.CANCEL:
                    print("Cancel to save one file.")
                    return self.RLT_CANCEL

            # 将内容保存到文件中。
            ide_editor.ide_file.save_file(self._ide_get_editor_buffer())
            src_buffer.set_modified(False)
            print('ide save file to disk file.')

        self._set_status(ViewMenu.STATUS_FILE_OPEN)

        return self.RLT_OK

    def ide_save_as_file(self, widget):
        '''
        显示对话框,选择另存为的文件名字。
        然后关闭当前文件,
        创建新的Ide文件,打开这个文件,并保存。
        '''
        print("ide save as other file.")

        ide_editor = self.multiEditors.get_current_ide_editor()
        old_file_path = self.multiEditors.get_current_abs_file_path()

        if ide_editor.ide_file == None:
            print('No file is being opened')
            return self.RLT_OK

        # 如果是新文件,则按照Save的逻辑进行
        src_buffer = self._ide_get_editor_buffer()
        if src_buffer.get_modified():
            if ide_editor.ide_file.file_path is None:
                return self.ide_save_file(widget)

        # 如果是已经打开的文件,就将当前文件保存成新文件后,关闭旧的,打开新的。
        # 设定新的文件路径
        dialog = Gtk.FileChooserDialog("请选择一个文件", self, \
                                               Gtk.FileChooserAction.SAVE , \
                                               (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, \
                                                Gtk.STOCK_OK, Gtk.ResponseType.OK))

        response = dialog.run()
        file_path = dialog.get_filename()
        dialog.reset_state()

        if response == Gtk.ResponseType.CANCEL:
            print("Cancel to save as one file.")
            return self.RLT_CANCEL

        print("File selected: " + file_path)

        # 将当前文件保存成新文件
        shutil.copy(old_file_path, file_path)

        # 关闭原来的文件。
        # ide_editor.ide_file.close_file()
        self.multiEditors.close_editor(old_file_path)

        # 打开指定的文件,并保存
        #self.current_idefile = ModelFile()
        #         ide_editor.ide_file.open_file(file_path)
        #
        #         ide_editor = self.multiEditors.get_current_ide_editor()
        #         src_buffer = self._ide_get_editor_buffer()
        #         self.current_idefile.save_file(src_buffer)
        #         self._set_src_language(src_buffer, file_path)
        #         src_buffer.set_modified(False)

        self.multiEditors.show_editor(file_path)

        # 切换当前的状态
        self._set_status(ViewMenu.STATUS_FILE_OPEN)

    def ide_help_info(self):
        dialog = ViewDialogInfo(self)
        dialog.run()

        dialog.destroy()

    def ide_edit_redo(self, widget):
        ve_editor = self.multiEditors.get_current_ide_editor()
        if ve_editor is None:
            return

        src_buffer = ve_editor.cmdList.get_buffer()
        src_buffer.redo()

    def ide_edit_undo(self, widget):
        ve_editor = self.multiEditors.get_current_ide_editor()
        if ve_editor is None:
            return

        src_buffer = ve_editor.cmdList.get_buffer()
        src_buffer.undo()

    def ide_edit_cut(self, widget):
        ve_editor = self.multiEditors.get_current_ide_editor()
        if ve_editor is None:
            return

        atom = Gdk.atom_intern('CLIPBOARD', True)
        clipboard = ve_editor.cmdList.get_clipboard(atom)
        ve_editor.cmdList.get_buffer().cut_clipboard(clipboard, True)

    def ide_edit_copy(self, widget):
        ve_editor = self.multiEditors.get_current_ide_editor()
        if ve_editor is None:
            return

        atom = Gdk.atom_intern('CLIPBOARD', True)
        clipboard = ve_editor.cmdList.get_clipboard(atom)
        ve_editor.cmdList.get_buffer().copy_clipboard(clipboard)

    def ide_edit_paste(self, widget):
        ve_editor = self.multiEditors.get_current_ide_editor()
        if ve_editor is None:
            return

        atom = Gdk.atom_intern('CLIPBOARD', True)
        clipboard = ve_editor.cmdList.get_clipboard(atom)
        ve_editor.cmdList.get_buffer().paste_clipboard(clipboard, None, True)

    def ide_edit_select_all(self, widget):
        ve_editor = self.multiEditors.get_current_ide_editor()
        if ve_editor is None:
            return

        src_buffer = ve_editor.cmdList.get_buffer()
        src_buffer.select_range(src_buffer.get_start_iter(),
                                src_buffer.get_end_iter())

    def ide_switch_page(self, abs_file_path):
        '''
        abs_file_path string 切换到的文件名字
        '''

        self.multiEditors.show_editor(abs_file_path)

        view_editor = self.multiEditors.get_editor_by_path(abs_file_path)
        self._ide_search_init(view_editor.cmdList.get_buffer())

        # 分析标记
        if self.cur_prj is not None:
            tags = self.cur_prj.query_tags_by_file(abs_file_path)
            self.ide_refresh_file_tag_list(tags)

        # 显示文件的路径。
        self.ide_set_title(abs_file_path)

        # 在文件树那里同步
        self.cmdgroupList.show_file(abs_file_path)

    ###########################################################################
    ## 最底层的功能

    def _add_filters(self, dialog):
        ''' 给对话框加入过滤器 '''
        # TODO:以后应该可以打开任意文件,然后根据后缀进行判断。
        filter_text = Gtk.FileFilter()
        filter_text.set_name("Text files")
        filter_text.add_mime_type("text/plain")
        dialog.add_filter(filter_text)

        filter_c = Gtk.FileFilter()
        filter_c.set_name("C/Cpp/hpp files")
        filter_c.add_mime_type("text/x-c")
        dialog.add_filter(filter_c)

        filter_py = Gtk.FileFilter()
        filter_py.set_name("Python files")
        filter_py.add_mime_type("text/x-python")
        dialog.add_filter(filter_py)

#         filter_any = Gtk.FileFilter()
#         filter_any.set_name("Any files")
#         filter_any.add_pattern("*")
#         dialog.add_filter(filter_any)

    def _set_src_language(self, src_buffer, file_path):
        manager = GtkSource.LanguageManager()

        if file_path is not None:
            language = manager.guess_language(file_path, None)  # 设定语法的类型
            src_buffer.set_language(language)
        else:
            src_buffer.set_language(None)

        return src_buffer

    def _set_status(self, status):
        #         if self.current_idefile is None:
        #             self.set_title(self.PROGRAM_NAME)
        #         else:
        #             if self.current_idefile.file_path is None:
        #                 self.set_title(self.PROGRAM_NAME + ' New')
        #             else:
        #                 self.set_title(self.PROGRAM_NAME + ' ' + self.current_idefile.file_path)
        self.ide_set_title()

    def ide_set_title(self, title=''):
        self.set_title(self.PROGRAM_NAME + ' ' + title)

        #TODO:不让状态变化。
        #self.ide_menu.set_status(status)
        self.ide_menu.set_status(ViewMenu.STATUS_FILE_OPEN_CHANGED)

    def ide_refresh_file_tag_list(self, tags):
        ''' 根据Tag的列表,更新文件对应的Tag列表
        tags:[IdeOneTag]:Tag列表。
        '''
        self.ideTagList.set_model(tags)

    def ide_goto_line(self, line_number):
        ''' 跳转到当前文件的行。
        line_number:int:行号(从1开始)
        '''
        #print 'goto line number:', line_number
        text_buf = self._ide_get_editor_buffer()
        it = text_buf.get_iter_at_line(line_number - 1)

        text_buf.place_cursor(it)

        # 设定光标的位置,和什么都没有选中
        text_buf.select_range(it, it)
        # 屏幕滚动到这个地方。
        editor = self.multiEditors.get_current_editor()
        editor.scroll_to_iter(it, 0.25, False, 0.0, 0.5)

        # TODO:这里不是错误,而是给threads_add_idle返回不再继续调用的设定。
        return False

    def ide_editor_set_focus(self):
        ''' 获取焦点(延迟调用) '''
        Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE,
                             self._ide_editor_set_focus)

    def _ide_editor_set_focus(self):
        ''' 获取焦点 '''
        editor = self.multiEditors.get_current_editor()
        editor.grab_focus()

    def ide_goto_file_line(self, file_path, line_number):
        ''' 跳转到指定文件的行。 '''
        # 先找到对应的文件
        # 然后再滚动到指定的位置
        #print 'jump to path:' + file_path + ', line:' + str(line_number)
        if self.ide_open_file(None, file_path) == self.RLT_OK:
            # 注意:这里采用延迟调用的方法,来调用goto_line方法,可能是buffer被设定后,
            # 还有其他的控件会通过事件来调用滚动,所以才造成马上调用滚动不成功。
            Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE,
                                 self.ide_goto_line, line_number)

    def ide_search_defination(self):
        ''' 查找定义
        '''
        tag_name = self._ide_get_selected_text_or_word()
        tags = self.cur_prj.query_defination_tags(tag_name)

        if len(tags) == 0:
            dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.INFO, \
                                       Gtk.ButtonsType.OK, "没有找到对应的定义。")
            dialog.run()
            dialog.reset_state()

        elif len(tags) == 1:
            ''' 直接跳转。 '''
            tag = tags[0]
            self.ide_goto_file_line(tag.tag_file_path, tag.tag_line_no)
        else:
            ''' 显示列表,让使用者挑选一个 '''
            tag = ViewDialogTagsOpen.show(self, tags)
            if tag:
                self.ide_goto_file_line(tag.tag_file_path, tag.tag_line_no)

    def ide_search_reference(self):
        ''' 查找引用
        '''
        tag_name = self._ide_get_selected_text_or_word()
        tags = self.cur_prj.query_reference_tags(tag_name)

        if len(tags) == 0:
            dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.INFO, \
                                       Gtk.ButtonsType.OK, "没有找到对应的引用。")
            dialog.run()
            dialog.reset_state()

        elif len(tags) == 1:
            ''' 直接跳转。 '''
            tag = tags[0]
            self.ide_goto_file_line(tag.tag_file_path, tag.tag_line_no)
        else:
            ''' 显示列表,让使用者挑选一个 '''
            tag = ViewDialogTagsOpen.show(self, tags)
            if tag:
                self.ide_goto_file_line(tag.tag_file_path, tag.tag_line_no)

    def ide_jump_to(self, line_number):
        self.ide_goto_line(line_number)

    def ide_find(self, search_entry):
        '''
        如果当前编辑器中有选中的文字,就将此文字放入检索本中。
        search_text string 需要检索的文字
        '''
        view_editor = self.multiEditors.get_current_ide_editor()
        if view_editor is None:
            return

        buf = view_editor.cmdList.get_buffer()

        if not buf.get_has_selection():
            return

        (start, end) = buf.get_selection_bounds()

        text = buf.get_text(start, end, False)

        search_entry.set_text(text)

    def _ide_search_init(self, text_buffer):
        self.search_text = None

        self.search_setting = GtkSource.SearchSettings.new()
        self.search_setting.set_regex_enabled(True)
        self.search_setting.set_case_sensitive(False)
        self.search_setting.set_wrap_around(True)

        self.search_context = GtkSource.SearchContext.new(
            text_buffer, self.search_setting)
        self.search_context.set_highlight(True)

    def _ide_search_text(self, text_buffer, search_text):

        self.search_context.get_settings().set_search_text(search_text)

        # -从当前的位置查找
        mark = text_buffer.get_insert()
        ite = text_buffer.get_iter_at_mark(mark)

        found, start_iter, end_iter = self.search_context.forward(ite)

        # 如果找到,就跳转到下面最近位置
        if found:
            line_num = start_iter.get_line()
            self.ide_jump_to(line_num)

    def _ide_search_text_next(self, text_buffer, search_text):
        # -从新位置查找
        mark = text_buffer.get_insert()
        ite = text_buffer.get_iter_at_mark(mark)

        found, start_iter, end_iter = self.search_context.forward(ite)

        # 如果找到,就跳转到下面最近位置
        if found:
            line_num = start_iter.get_line()
            self.ide_jump_to(line_num)

            text_buffer.move_mark_by_name("selection_bound", start_iter)
            text_buffer.move_mark_by_name("insert", end_iter)

    def ide_find_text(self, search_text):
        view_editor = self.multiEditors.get_current_ide_editor()
        if view_editor is None:
            return

        self._ide_search_text(view_editor.cmdList.get_buffer(), search_text)

    def ide_find_next(self, search_text):
        '''
        如果当前编辑器中有选中的文字,则直接显示对话框。
        对话框中的文字,缺省被选中,可以被全文粘贴。
        然后查找定义。 
        search_text string 需要检索的文字
        '''
        view_editor = self.multiEditors.get_current_ide_editor()
        if view_editor is None:
            return

        self._ide_search_text_next(view_editor.cmdList.get_buffer(),
                                   search_text)

    def ide_find_in_files(self):
        '''
        在多个文件中检索,比如文件夹内检索,打开的文件中检索,或者项目中检索等。
        '''

    def _ide_get_selected_text_or_word(self):
        ''' 从编辑器中得到当前被选中的文字,
        如果没有就返回光标所在的单词,
        如果都无法达到,就返回None 
        '''
        text_buf = self._ide_get_editor_buffer()
        selection = text_buf.get_selection_bounds()

        text = None
        if len(selection) > 0:
            # 已经有选中的文字。
            start, end = selection
            text = text_buf.get_text(start, end, False)
        else:

            # 没有选中任何的文字
            mark = text_buf.get_insert()
            word_start = text_buf.get_iter_at_mark(mark)
            word_end = text_buf.get_iter_at_mark(mark)

            # 得到以空格为区分的单词开头。
            while True:
                if word_start.starts_word():
                    n = word_start.copy()
                    # 获得前一个字符。
                    if not n.backward_char():
                        break
                    # 这里的算法应该有问题,如果判断为 空格,则不无法通过,不明白为什么?
                    if text_buf.get_text(n, word_start, False) != "_":
                        break

                word_start.backward_word_start()

            # 得到以空格为区分的单词结尾。
            while True:
                if word_end.ends_word():
                    n = word_end.copy()
                    if not n.forward_char():
                        break
                    if text_buf.get_text(word_end, n, False) != "_":
                        break

                word_end.forward_word_end()

            text = text_buf.get_text(word_start, word_end, False)

        print 'selected text or word is "', text, '"'

        return text

    def _ide_set_completion(self, ideProject):
        ''' 设定当前的编辑器的单词补足,当切换不同的Project时,才有必要 '''

        # 单词补齐,使用CompletionWords

        #配置单词自动补齐,使用自定义的CompletionProvider
        editor = self.multiEditors.get_current_editor()
        completion = cmdList.props.completion

        # 清除之前的所有provider
        providers = completion.get_providers()
        for p in providers:
            completion.remove_provider(p)

        # 加入新的Provider
        completion.add_provider(ideProject.get_completion_provider())

    def _ide_get_editor_buffer(self):
        editor = self.multiEditors.get_current_editor()
        if editor is None:
            return None

        return editor.get_buffer()

    def ide_add_cmd(self):
        # 在当前位置添加一个命令。
        ide_editor = self.mutilePages.get_current_ide_editor()
        viewPage = ide_editor.view
        viewPage.add_cmd()

    def ide_del_cmd(self):
        # 删除当前位置的命令。
        ide_editor = self.mutilePages.get_current_ide_editor()
        viewPage = ide_editor.view
        viewPage.del_cmd()

    def ide_move_up_cmd(self):
        # 将当前命令向上移动一个位置
        ide_editor = self.mutilePages.get_current_ide_editor()
        viewPage = ide_editor.view
        viewPage.move_up_cmd()

    def ide_move_down_cmd(self):
        # 将当前命令向下移动一个位置
        ide_editor = self.mutilePages.get_current_ide_editor()
        viewPage = ide_editor.view
        viewPage.move_down_cmd()