class SettingDialog(QDialog): def __init__(self, mainWindow): super(SettingDialog, self).__init__() self.setWindowFlags(Qt.WindowCloseButtonHint) self.setAttribute(Qt.WA_DeleteOnClose) self.mainWindow = mainWindow self.setWindowTitle('Settings') position = self.mainWindow.getPopUpPosition(600, 510) self.setGeometry(position.x(), position.y(), 600, 510) self.setFixedHeight(510) self.setFixedWidth(600) verticalLayout = QVBoxLayout() layout = QHBoxLayout() layout.setContentsMargins(5, 5, 5, 5) self.settingList = QListWidget() layout.addWidget(self.settingList, 1) settingContent = QWidget(self) self.layout = QStackedLayout() settingContent.setLayout(self.layout) self.setUpPages() self.settingList.itemSelectionChanged.connect(self.switchSettingPage) horizontalButtonLayout = QHBoxLayout() cancelButton = QPushButton("Cancel") cancelButton.clicked.connect(self.close) saveButton = QPushButton("Save") saveButton.clicked.connect(self.saveAll) horizontalButtonLayout.addWidget(saveButton) horizontalButtonLayout.addWidget(cancelButton) verticalLayout.addLayout(layout) verticalLayout.addLayout(horizontalButtonLayout) layout.addWidget(settingContent, 9) self.setLayout(verticalLayout) self.exec() def setUpPages(self): self.settingList.addItem("Main") self.layout.addWidget(MainWidget(self)) self.settingList.addItem("Colors") self.layout.addWidget(ColorsWidget(self)) self.settingList.addItem("Macros") self.layout.addWidget(MacrosWidget(self)) self.settingList.addItem("Notification") self.layout.addWidget(NotificationWidget(self)) def switchSettingPage(self): self.layout.setCurrentIndex(self.settingList.currentRow()) def saveAll(self): for i in range(self.layout.count() - 1, -1, -1): self.layout.widget(i).saveSetting() self.accept()
class Window(BaseWindow): def __init__(self): super(Window, self).__init__() self.last_index = 0 self.setFixedSize(WINDOW_WIDTH, WINDOW_HEIGHT) # 要想使 move_center 起作用,必须设置 resize self.resize(WINDOW_WIDTH, WINDOW_HEIGHT) self.move_center() self.setWindowIcon(QIcon(abs_path('static/images/icon/logo.png'))) self.setWindowTitle('江科大课表导出 v1.0') self.stack_layout = QStackedLayout() self.stack_layout.addWidget(StepHello(self.stack_layout)) self.stack_layout.addWidget(StepAccount(self.stack_layout)) self.stack_layout.addWidget(StepDate(self.stack_layout)) self.stack_layout.addWidget(StepSuccess(self.stack_layout)) self.stack_layout.addWidget(StepMistake(self.stack_layout)) self.stack_layout.setCurrentIndex(self.last_index) self.stack_layout.currentChanged.connect(self.interface_changed) self.setLayout(self.stack_layout) self.show() def interface_changed(self): if self.last_index < self.stack_layout.currentIndex(): self.last_index = self.stack_layout.currentIndex() elif self.last_index == 4 and self.stack_layout.currentIndex() == 0: for i in range(3)[::-1]: self.stack_layout.widget(i).step_ani(True) self.last_index = 0 elif self.last_index in [3, 4 ] and self.stack_layout.currentIndex() == 2: self.stack_layout.widget(2).step_ani(True) self.last_index = 2 elif self.last_index == 2 and self.stack_layout.currentIndex() == 1: self.stack_layout.widget(1).step_ani(True) self.last_index = 1 elif self.last_index == 1 and self.stack_layout.currentIndex() == 0: self.stack_layout.widget(0).step_ani(True) self.last_index = 0
class _MainContainer(QWidget): ############################################################################### # MainContainer SIGNALS ############################################################################### """ newFileOpened(QString) allTabClosed() runFile(QString) addToProject(QString) showFileInExplorer(QString) recentTabsModified() currentEditorChanged(QString) fileOpened(QString) ---------migrationAnalyzed() findOcurrences(QString) ---------updateFileMetadata() editorKeyPressEvent(QEvent) locateFunction(QString, QString, bool) [functionName, filePath, isVariable] updateLocator(QString) beforeFileSaved(QString) fileSaved(QString) openPreferences() --------openProject(QString) ---------dontOpenStartPage() """ ############################################################################### fileOpened = pyqtSignal('QString') updateLocator = pyqtSignal('QString') currentEditorChanged = pyqtSignal('QString') beforeFileSaved = pyqtSignal('QString') fileSaved = pyqtSignal('QString') def __init__(self, parent=None): super(_MainContainer, self).__init__(parent) self.setContentsMargins(0, 0, 0, 0) self._parent = parent self._vbox = QVBoxLayout(self) self._vbox.setContentsMargins(0, 0, 0, 0) self._vbox.setSpacing(0) self.stack = QStackedLayout() self.stack.setStackingMode(QStackedLayout.StackAll) self._vbox.addLayout(self.stack) self.splitter = dynamic_splitter.DynamicSplitter() self.setAcceptDrops(True) # self._files_handler = files_handler.FilesHandler(self) self._add_file_folder = add_file_folder.AddFileFolderWidget(self) # documentation browser self.docPage = None # Code Navigation # self._locator = locator.GoToDefinition() self.__codeBack = [] self.__codeForward = [] self.__bookmarksFile = '' self.__bookmarksPos = -1 self.__breakpointsFile = '' self.__breakpointsPos = -1 self.__operations = { 0: self._navigate_code_jumps, 1: self._navigate_bookmarks, 2: self._navigate_breakpoints } # self.locateFunction['QString', # 'QString', # bool].connect(self.locate_function) IDE.register_service('main_container', self) # Register signals connections connections = ({ 'target': 'main_container', 'signal_name': 'updateLocator', 'slot': self._explore_file_code }, { 'target': 'filesystem', 'signal_name': 'projectOpened', 'slot': self._explore_code }, { 'target': 'projects_explorer', 'signal_name': 'updateLocator', 'slot': self._explore_code }) """ {'target': 'menu_file', 'signal_name': 'openFile(QString)', 'slot': self.open_file}, {'target': 'explorer_container', 'signal_name': 'goToDefinition(int)', 'slot': self.editor_go_to_line}, {'target': 'explorer_container', 'signal_name': 'pep8Activated(bool)', 'slot': self.reset_pep8_warnings}, {'target': 'explorer_container', 'signal_name': 'lintActivated(bool)', 'slot': self.reset_lint_warnings}, {'target': 'filesystem', 'signal_name': 'projectOpened', 'slot': self._explore_code}, {'target': 'main_container', 'signal_name': 'updateLocator(QString)', 'slot': self._explore_file_code}, ) """ IDE.register_signals('main_container', connections) self.selector = main_selector.MainSelector(self) self._opening_dialog = False self.add_widget(self.selector) if settings.SHOW_START_PAGE: self.show_start_page() self.selector.changeCurrent[int].connect(self._change_current_stack) # self.selector.removeWidget[int].connect(self._remove_item_from_stack) # self.selector.ready.connect(self._selector_ready) self.selector.animationCompleted.connect( self._selector_animation_completed) # self.closeDialog['PyQt_PyObject'].connect(self.remove_widget) def install(self): ide = IDE.get_service('ide') ide.place_me_on("main_container", self, "central", top=True) self.combo_area = combo_editor.ComboEditor(original=True) self.combo_area.allFilesClosed.connect(self._files_closed) # self.combo_area.allFilesClosed.connect(self._files_closed) self.splitter.add_widget(self.combo_area) self.add_widget(self.splitter) self.current_widget = self.combo_area # Code Locator self._code_locator = locator_widget.LocatorWidget(ide) ui_tools.install_shortcuts(self, actions.ACTIONS, ide) def show_locator(self): """Show the locator widget""" if not self._code_locator.isVisible(): self._code_locator.show() def _explore_code(self): """ Update locator metadata for the current projects """ self._code_locator.explore_code() def _explore_file_code(self, path): """ Update locator metadata for the file in path """ self._code_locator.explore_file_code(path) def add_status_bar(self, status): self._vbox.addWidget(status) @property def combo_header_size(self): return self.combo_area.bar.height() def add_widget(self, widget): self.stack.addWidget(widget) def remove_widget(self, widget): self.stack.removeWidget(widget) def _close_dialog(self, widget): self.emit(SIGNAL("closeDialog(PyQt_PyObject)"), widget) self.disconnect(widget, SIGNAL("finished(int)"), lambda: self._close_dialog(widget)) def show_dialog(self, widget): self._opening_dialog = True # self.connect(widget, SIGNAL("finished(int)"), # lambda: self._close_dialog(widget)) self.setVisible(True) self.stack.addWidget(widget) self.show_selector() def show_selector(self): if self.selector != self.stack.currentWidget(): temp_dir = os.path.join(QDir.tempPath(), "ninja-ide") if not os.path.exists(temp_dir): os.mkdir(temp_dir) collected_data = [] current = self.stack.currentIndex() for index in range(self.stack.count()): widget = self.stack.widget(index) if widget == self.selector: continue pixmap = QWidget.grab(widget, widget.rect()) path = os.path.join(temp_dir, "screen%s.png" % index) pixmap.save(path) collected_data.append((index, path)) self.selector.set_model(collected_data) self._selector_ready() """ if self.selector != self.stack.currentWidget(): temp_dir = os.path.join(QDir.tempPath(), "ninja-ide") if not os.path.exists(temp_dir): os.mkdir(temp_dir) collected_data = [] current = self.stack.currentIndex() for index in range(self.stack.count()): widget = self.stack.widget(index) if widget == self.selector: continue closable = True if widget == self.splitter: closable = False pixmap = QWidget.grab(widget, widget.rect()) path = os.path.join(temp_dir, "screen%s.png" % index) pixmap.save(path) if index == current: self.selector.set_preview(index, path) collected_data.insert(0, (index, path, closable)) else: collected_data.append((index, path, closable)) self.selector.set_model(collected_data) else: self.selector.close_selector() """ def _selector_ready(self): print(self.stack.currentWidget()) self.stack.setCurrentWidget(self.selector) print(self.stack.currentWidget()) self.selector.start_animation() def _selector_animation_completed(self): if self._opening_dialog: # We choose the last one with -2, -1 (for last one) + # -1 for the hidden selector widget which is in the stacked too. self.selector.open_item(self.stack.count() - 2) self._opening_dialog = False def _change_current_stack(self, index): self.stack.setCurrentIndex(index) def _remove_item_from_stack(self, index): widget = self.stack.takeAt(index) del widget def show_editor_area(self): self.stack.setCurrentWidget(self.splitter) def _files_closed(self): if settings.SHOW_START_PAGE: self.show_start_page() def change_visibility(self): """Show/Hide the Main Container area.""" if self.isVisible(): self.hide() else: self.show() def expand_symbol_combo(self): self.stack.setCurrentWidget(self.splitter) self.current_widget.show_combo_symbol() def expand_file_combo(self): self.stack.setCurrentWidget(self.splitter) self.current_widget.show_combo_file() def locate_function(self, function, filePath, isVariable): """Move the cursor to the proper position in the navigate stack.""" editorWidget = self.get_current_editor() if editorWidget: self.__codeBack.append( (editorWidget.file_path, editorWidget.getCursorPosition())) self.__codeForward = [] self._locator.navigate_to(function, filePath, isVariable) def run_file(self, path): self.emit(SIGNAL("runFile(QString)"), path) def _add_to_project(self, path): self.emit(SIGNAL("addToProject(QString)"), path) def _show_file_in_explorer(self, path): self.emit(SIGNAL("showFileInExplorer(QString)"), path) def paste_history(self): """Paste the text from the copy/paste history.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): line, index = editorWidget.getCursorPosition() central = IDE.get_service('central_container') if central: editorWidget.insertAt(central.get_paste(), line, index) def copy_history(self): """Copy the selected text into the copy/paste history.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): copy = editorWidget.selectedText() central = IDE.get_service('central_container') if central: central.add_copy(copy) def import_from_everywhere(self): """Insert an import line from any place in the editor.""" editorWidget = self.get_current_editor() if editorWidget: dialog = from_import_dialog.FromImportDialog(editorWidget, self) dialog.show() def add_back_item_navigation(self): """Add an item to the back stack and reset the forward stack.""" editorWidget = self.get_current_editor() if editorWidget: self.__codeBack.append( (editorWidget.file_path, editorWidget.cursor_position)) self.__codeForward = [] def preview_in_browser(self): """Load the current html file in the default browser.""" editorWidget = self.get_current_editor() if editorWidget: if not editorWidget.file_path: self.save_file() ext = file_manager.get_file_extension(editorWidget.file_path) if ext in ('html', 'shpaml', 'handlebars', 'tpl'): webbrowser.open_new_tab(editorWidget.file_path) def add_bookmark_breakpoint(self): """Add a bookmark or breakpoint to the current file in the editor.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): if self.current_widget.bar.code_navigator.operation == 1: editorWidget.handle_bookmarks_breakpoints( editorWidget.getCursorPosition()[0], Qt.ControlModifier) elif self.current_widget.bar.code_navigator.operation == 2: editorWidget.handle_bookmarks_breakpoints( editorWidget.getCursorPosition()[0], Qt.NoModifier) def __navigate_with_keyboard(self, val): """Navigate between the positions in the jump history stack.""" op = self.current_widget.bar.code_navigator.operation self.navigate_code_history(val, op) def navigate_code_history(self, val, op): """Navigate the code history.""" self.__operations[op](val) def _navigate_code_jumps(self, val): """Navigate between the jump points.""" node = None if not val and self.__codeBack: node = self.__codeBack.pop() editorWidget = self.get_current_editor() if editorWidget: self.__codeForward.append( (editorWidget.file_path, editorWidget.getCursorPosition())) elif val and self.__codeForward: node = self.__codeForward.pop() editorWidget = self.get_current_editor() if editorWidget: self.__codeBack.append( (editorWidget.file_path, editorWidget.getCursorPosition())) if node: filename = node[0] line, col = node[1] self.open_file(filename, line, col) def _navigate_breakpoints(self, val): """Navigate between the breakpoints.""" # FIXME: put navigate breakpoints and bookmarks as one method. breakList = list(settings.BREAKPOINTS.keys()) breakList.sort() if not breakList: return if self.__breakpointsFile not in breakList: self.__breakpointsFile = breakList[0] index = breakList.index(self.__breakpointsFile) breaks = settings.BREAKPOINTS.get(self.__breakpointsFile, []) lineNumber = 0 # val == True: forward if val: if (len(breaks) - 1) > self.__breakpointsPos: self.__breakpointsPos += 1 lineNumber = breaks[self.__breakpointsPos] elif len(breaks) > 0: if index < (len(breakList) - 1): self.__breakpointsFile = breakList[index + 1] else: self.__breakpointsFile = breakList[0] self.__breakpointsPos = 0 lineNumber = settings.BREAKPOINTS[self.__breakpointsFile][0] else: if self.__breakpointsPos > 0: self.__breakpointsPos -= 1 lineNumber = breaks[self.__breakpointsPos] elif len(breaks) > 0: self.__breakpointsFile = breakList[index - 1] breaks = settings.BREAKPOINTS[self.__breakpointsFile] self.__breakpointsPos = len(breaks) - 1 lineNumber = breaks[self.__breakpointsPos] if file_manager.file_exists(self.__breakpointsFile): self.open_file(self.__breakpointsFile, lineNumber, None, True) else: settings.BREAKPOINTS.pop(self.__breakpointsFile) if settings.BREAKPOINTS: self._navigate_breakpoints(val) def _navigate_bookmarks(self, val): """Navigate between the bookmarks.""" bookList = list(settings.BOOKMARKS.keys()) bookList.sort() if not bookList: return if self.__bookmarksFile not in bookList: self.__bookmarksFile = bookList[0] index = bookList.index(self.__bookmarksFile) bookms = settings.BOOKMARKS.get(self.__bookmarksFile, []) lineNumber = 0 # val == True: forward if val: if (len(bookms) - 1) > self.__bookmarksPos: self.__bookmarksPos += 1 lineNumber = bookms[self.__bookmarksPos] elif len(bookms) > 0: if index < (len(bookList) - 1): self.__bookmarksFile = bookList[index + 1] else: self.__bookmarksFile = bookList[0] self.__bookmarksPos = 0 lineNumber = settings.BOOKMARKS[self.__bookmarksFile][0] else: if self.__bookmarksPos > 0: self.__bookmarksPos -= 1 lineNumber = bookms[self.__bookmarksPos] elif len(bookms) > 0: self.__bookmarksFile = bookList[index - 1] bookms = settings.BOOKMARKS[self.__bookmarksFile] self.__bookmarksPos = len(bookms) - 1 lineNumber = bookms[self.__bookmarksPos] if file_manager.file_exists(self.__bookmarksFile): self.open_file(self.__bookmarksFile, lineNumber, None, True) else: # settings.BOOKMARKS.pop(self.__bookmarksFile) if settings.BOOKMARKS: self._navigate_bookmarks(val) def count_file_code_lines(self): """Count the lines of code in the current file.""" editorWidget = self.get_current_editor() if editorWidget: block_count = editorWidget.lines() blanks = re.findall('(^\n)|(^(\s+)?#)|(^( +)?($|\n))', editorWidget.text(), re.M) blanks_count = len(blanks) resume = self.tr("Lines code: %s\n") % (block_count - blanks_count) resume += (self.tr("Blanks and commented lines: %s\n\n") % blanks_count) resume += self.tr("Total lines: %s") % blockdget msgBox.exec_() msgBox = QMessageBox(QMessageBox.Information, self.tr("Summary of lines"), resume, QMessageBox.Ok, editorWidget) def editor_cut(self): editorWidget = self.get_current_editor() if editorWidget: editorWidget.cut() def editor_copy(self): editorWidget = self.get_current_editor() if editorWidget: editorWidget.copy() def editor_paste(self): editorWidget = self.get_current_editor() if editorWidget: editorWidget.paste() def editor_upper(self): editorWidget = self.get_current_editor() if editorWidget: editorWidget.to_upper() def editor_lower(self): editorWidget = self.get_current_editor() if editorWidget: editorWidget.to_lower() def editor_title(self): editorWidget = self.get_current_editor() if editorWidget: editorWidget.to_title() def editor_go_to_definition(self): """Search the definition of the method or variable under the cursor. If more than one method or variable is found with the same name, shows a table with the results and let the user decide where to go.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): editorWidget.go_to_definition() def editor_redo(self): """Execute the redo action in the current editor.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): editorWidget.redo() def editor_undo(self): editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): editorWidget.undo() def editor_indent_less(self): """Indent 1 position to the left for the current line or selection.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): editorWidget.indent_less() def editor_indent_more(self): """Indent 1 position to the right for the current line or selection.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): editorWidget.indent_more() def editor_insert_debugging_prints(self): """Insert a print statement in each selected line.""" editorWidget = self.get_current_editor() if editorWidget: helpers.insert_debugging_prints(editorWidget) def editor_insert_pdb(self): """Insert a pdb.set_trace() statement in tjhe current line.""" editorWidget = self.get_current_editor() if editorWidget: helpers.insert_pdb(editorWidget) def editor_comment(self): """Mark the current line or selection as a comment.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): helpers.comment_or_uncomment(editorWidget) def editor_uncomment(self): """Uncomment the current line or selection.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): helpers.uncomment(editorWidget) def editor_insert_horizontal_line(self): """Insert an horizontal lines of comment symbols.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): helpers.insert_horizontal_line(editorWidget) def editor_insert_title_comment(self): """Insert a Title surrounded by comment symbols.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): helpers.insert_title_comment(editorWidget) def editor_remove_trailing_spaces(self): """Remove the trailing spaces in the current editor.""" editorWidget = self.get_current_editor() if editorWidget: helpers.remove_trailing_spaces(editorWidget) def editor_replace_tabs_with_spaces(self): """Replace the Tabs with Spaces in the current editor.""" editorWidget = self.get_current_editor() if editorWidget: helpers.replace_tabs_with_spaces(editorWidget) def editor_move_up(self): """Move the current line or selection one position up.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): helpers.move_up(editorWidget) def editor_move_down(self): """Move the current line or selection one position down.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): helpers.move_down(editorWidget) def editor_remove_line(self): """Remove the current line or selection.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): helpers.remove_line(editorWidget) def editor_duplicate(self): """Duplicate the current line or selection.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): helpers.duplicate(editorWidget) def editor_highlight_word(self): """Highlight the occurrences of the current word in the editor.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): editorWidget.highlight_selected_word() def editor_complete_declaration(self): """Do the opposite action that Complete Declaration expect.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): editorWidget.complete_declaration() def editor_go_to_line(self, line): """ Jump to the specified line in the current editor. """ editorWidget = self.get_current_editor() if editorWidget: editorWidget.go_to_line(line) editorWidget.setFocus() def zoom_in_editor(self): """Increase the font size in the current editor.""" editorWidget = self.get_current_editor() if editorWidget: editorWidget.zoom(1.0) def zoom_out_editor(self): """Decrease the font size in the current editor.""" editorWidget = self.get_current_editor() if editorWidget: editorWidget.zoom(-1.0) def reset_zoom(self): editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.reset_zoom() def recent_files_changed(self): self.emit(SIGNAL("recentTabsModified()")) def dragEnterEvent(self, event): if event.mimeData().hasUrls(): event.accept() else: event.ignore() def dropEvent(self, event): file_path = event.mimeData().urls()[0].toLocalFile() self.open_file(file_path) def setFocus(self): widget = self.get_current_widget() if widget: widget.setFocus() def current_editor_changed(self, filename): """Notify the new filename of the current editor.""" if filename is None: filename = translations.TR_NEW_DOCUMENT self.currentEditorChanged.emit(filename) def show_split(self, orientation_vertical=False): # IDE.select_current(self.current_widget.currentWidget()) self.current_widget.split_editor(orientation_vertical) def add_editor(self, fileName=None, ignore_checkers=False): ninjaide = IDE.get_service('ide') editable = ninjaide.get_or_create_editable(fileName) if editable.editor: self.current_widget.set_current(editable) return self.current_widget.currentWidget() else: editable.ignore_checkers = ignore_checkers editorWidget = self.create_editor_from_editable(editable) # add the tab keep_index = (self.splitter.count() > 1 and self.combo_area.stacked.count() > 0) self.combo_area.add_editor(editable, keep_index) # emit a signal about the file open self.fileOpened.emit(fileName) if not keep_index: self.current_widget.set_current(editable) self.stack.setCurrentWidget(self.splitter) editorWidget.setFocus() return editorWidget def create_editor_from_editable(self, editable): neditor = editor.create_editor(editable) # Connect signals neditor.zoomChanged[int].connect(self._show_zoom_indicator) neditor.destroyed.connect(self._editor_destroyed) editable.fileSaved.connect(self._editor_tab_was_saved) neditor.addBackItemNavigation.connect(self.add_back_item_navigation) # self.connect(editable, SIGNAL("fileSaved(PyQt_PyObject)"), # self._editor_tab_was_saved) # editorWidget.font_changed.connect(self.show_zoom_indicator) # self.connect(editorWidget, SIGNAL("openDropFile(QString)"), # self.open_file) # self.connect(editorWidget, SIGNAL("addBackItemNavigation()"), # self.add_back_item_navigation) # self.connect(editorWidget, # SIGNAL("locateFunction(QString, QString, bool)"), # self._editor_locate_function) # self.connect(editorWidget, SIGNAL("findOcurrences(QString)"), # self._find_occurrences) # keyPressEventSignal for plugins # self.connect(editorWidget, SIGNAL("keyPressEvent(QEvent)"), # self._editor_keyPressEvent) return neditor def _editor_destroyed(self): ui_tools.FadingIndicator.editor_destroyed() def _show_zoom_indicator(self, text): neditor = self.get_current_editor() ui_tools.FadingIndicator.show_text(neditor, "Zoom: {}%".format(str(text))) def reset_pep8_warnings(self, value): pass # FIXME: check how we handle this # for i in range(self._tabMain.count()): # widget = self._tabMain.widget(i) # if type(widget) is editor.Editor: # if value: # widget.syncDocErrorsSignal = True # widget.pep8.check_style() # else: # widget.hide_pep8_errors() def reset_lint_warnings(self, value): pass #FIXME: check how we handle this # for i in range(self._tabMain.count()): #widget = self._tabMain.widget(i) #if type(widget) is editor.Editor: #if value: #widget.syncDocErrorsSignal = True #widget.errors.check_errors() #else: #widget.hide_lint_errors() def show_zoom_indicator(self, text): ui_tools.FadingIndicator.show_text(self, "Zoom: {0}%".format(text)) def _find_occurrences(self, word): self.emit(SIGNAL("findOcurrences(QString)"), word) def _editor_keyPressEvent(self, event): self.emit(SIGNAL("editorKeyPressEvent(QEvent)"), event) def _editor_locate_function(self, function, filePath, isVariable): self.emit(SIGNAL("locateFunction(QString, QString, bool)"), function, filePath, isVariable) def _editor_tab_was_saved(self, editable=None): self.updateLocator.emit(editable.file_path) # self.emit(SIGNAL("updateLocator(QString)"), editable.file_path) def get_current_widget(self): return self.current_widget.currentWidget() def get_current_editor(self): """Return the Actual Editor or None Return an instance of Editor if the Current Tab contains an Editor or None if it is not an instance of Editor""" widget = self.current_widget.currentWidget() if isinstance(widget, editor.NEditor): return widget return None def reload_file(self, editorWidget=None): if editorWidget is None: editorWidget = self.get_current_editor() editorWidget.neditable.reload_file() def open_image(self, fileName): try: if not self.is_open(fileName): viewer = image_viewer.ImageViewer(fileName) # self.add_tab(viewer, file_manager.get_basename(fileName)) # viewer.ID = fileName else: self.move_to_open(fileName) except Exception as reason: logger.error('open_image: %s', reason) QMessageBox.information(self, self.tr("Incorrect File"), self.tr("The image couldn\'t be open")) def open_file(self, filename='', line=-1, col=0, ignore_checkers=False): logger.debug("will try to open %s" % filename) if not filename: logger.debug("has nofilename") if settings.WORKSPACE: directory = settings.WORKSPACE else: directory = os.path.expanduser("~") editorWidget = self.get_current_editor() ninjaide = IDE.get_service('ide') if ninjaide: current_project = ninjaide.get_current_project() if current_project is not None: directory = current_project elif editorWidget is not None and editorWidget.file_path: directory = file_manager.get_folder( editorWidget.file_path) extensions = ';;'.join([ '{}(*{})'.format(e.upper()[1:], e) for e in settings.SUPPORTED_EXTENSIONS + ['.*', ''] ]) fileNames = QFileDialog.getOpenFileNames(self, self.tr("Open File"), directory, extensions)[0] else: logger.debug("has filename") fileNames = [filename] if not fileNames: return for filename in fileNames: image_extensions = ('bmp', 'gif', 'jpeg', 'jpg', 'png') if file_manager.get_file_extension(filename) in image_extensions: logger.debug("will open as image") self.open_image(filename) elif file_manager.get_file_extension(filename).endswith('ui'): logger.debug("will load in ui editor") self.w = uic.loadUi(filename) self.w.show() else: logger.debug("will try to open: " + filename) self.__open_file(filename, line, col, ignore_checkers) def __open_file(self, fileName='', line=-1, col=0, ignore_checkers=False): try: editorWidget = self.add_editor(fileName, ignore_checkers=ignore_checkers) if line != -1: editorWidget.go_to_line(line, col) self.currentEditorChanged.emit(fileName) except file_manager.NinjaIOException as reason: QMessageBox.information(self, self.tr("The file couldn't be open"), str(reason)) def is_open(self, filename): pass #return self.tabs.is_open(filename) != -1 def move_to_open(self, filename): pass #FIXME: add in the current split? #if self.tabs.is_open(filename) != -1: #self.tabs.move_to_open(filename) #self.tabs.currentWidget().setFocus() #self.emit(SIGNAL("currentEditorChanged(QString)"), filename) def get_widget_for_id(self, filename): pass #widget = None #index = self.tabs.is_open(filename) #if index != -1: #widget = self.tabs.widget(index) #return widget def change_open_tab_id(self, idname, newId): """Search for the Tab with idname, and set the newId to that Tab.""" pass #index = self.tabs.is_open(idname) #if index != -1: #widget = self.tabs.widget(index) #tabName = file_manager.get_basename(newId) #self.tabs.change_open_tab_name(index, tabName) #widget.ID = newId def close_deleted_file(self, idname): """Search for the Tab with id, and ask the user if should be closed.""" pass #index = self.tabs.is_open(idname) #if index != -1: #result = QMessageBox.question(self, self.tr("Close Deleted File"), #self.tr("Are you sure you want to close the deleted file?\n" #"The content will be completely deleted."), #buttons=QMessageBox.Yes | QMessageBox.No) #if result == QMessageBox.Yes: #self.tabs.removeTab(index) def save_file(self, editorWidget=None): # FIXME: check how we handle this if not editorWidget: editorWidget = self.get_current_editor() if editorWidget is None: return False # Ok, we have an editor instance # Save to file only if editor really was modified if editorWidget.is_modified: try: if (editorWidget.nfile.is_new_file or not editorWidget.nfile.has_write_permission()): return self.save_file_as() self.beforeFileSaved.emit(editorWidget.file_path) if settings.REMOVE_TRAILING_SPACES: helpers.remove_trailing_spaces(editorWidget) # New line at end # FIXME: from settings helpers.insert_block_at_end(editorWidget) # Save convent editorWidget.neditable.save_content() encoding = file_manager.get_file_encoding(editorWidget.text) editorWidget.encoding = encoding self.fileSaved.emit( self.tr("File Saved: {}".format(editorWidget.file_path))) return True except Exception as reason: logger.error('save_file: %s', reason) QMessageBox.information(self, self.tr("Save Error"), self.tr("The file couldn't be saved!")) return False def save_file_as(self): editorWidget = self.get_current_editor() if not editorWidget: return False try: filters = '(*.py);;(*.*)' if editorWidget.file_path: # existing file ext = file_manager.get_file_extension(editorWidget.file_path) if ext != 'py': filters = '(*.%s);;(*.py);;(*.*)' % ext save_folder = self._get_save_folder(editorWidget.file_path) fileName = QFileDialog.getSaveFileName(self._parent, self.tr("Save File"), save_folder, filters)[0] if not fileName: return False if settings.REMOVE_TRAILING_SPACES: helpers.remove_trailing_spaces(editorWidget) ext = file_manager.get_file_extension(fileName) if not ext: fileName = '%s.%s' % ( fileName, 'py', ) editorWidget.neditable.save_content(path=fileName) # editorWidget.register_syntax( # file_manager.get_file_extension(fileName)) self.fileSaved.emit(self.tr("File Saved: {}".format(fileName))) self.currentEditorChanged.emit(fileName) return True except file_manager.NinjaFileExistsException as ex: QMessageBox.information( self, self.tr("File Already Exists"), (self.tr("Invalid Path: the file '%s' " " already exists.") % ex.filename)) except Exception as reason: logger.error('save_file_as: %s', reason) QMessageBox.information(self, self.tr("Save Error"), self.tr("The file couldn't be saved!")) return False def _get_save_folder(self, fileName): """ Returns the root directory of the 'Main Project' or the home folder """ ninjaide = IDE.get_service('ide') current_project = ninjaide.get_current_project() if current_project: return current_project.path return os.path.expanduser("~") def save_project(self, projectFolder): pass #FIXME: check how we handle this #for i in range(self._tabMain.count()): #editorWidget = self._tabMain.widget(i) #if type(editorWidget) is editor.Editor and \ #file_manager.belongs_to_folder(projectFolder, #editorWidget.file_path): #reloaded = self._tabMain.check_for_external_modifications( #editorWidget) #if not reloaded: #self.save_file(editorWidget) #for i in range(self.tabsecondary.count()): #editorWidget = self.tabsecondary.widget(i) #if type(editorWidget) is editor.Editor and \ #file_manager.belongs_to_folder(projectFolder, #editorWidget.file_path): #reloaded = self.tabsecondary.check_for_external_modifications( #editorWidget) #if not reloaded: #self.save_file(editorWidget) def save_all(self): pass #FIXME: check how we handle this #for i in range(self._tabMain.count()): #editorWidget = self._tabMain.widget(i) #if type(editorWidget) is editor.Editor: #reloaded = self._tabMain.check_for_external_modifications( #editorWidget) #if not reloaded: #self.save_file(editorWidget) #for i in range(self.tabsecondary.count()): #editorWidget = self.tabsecondary.widget(i) #self.tabsecondary.check_for_external_modifications(editorWidget) #if type(editorWidget) is editor.Editor: #reloaded = self.tabsecondary.check_for_external_modifications( #editorWidget) #if not reloaded: #self.save_file(editorWidget) def call_editors_function(self, call_function, *arguments): pass #args = arguments[0] #kwargs = arguments[1] #for i in range(self.tabs.count()): #editorWidget = self.tabs.widget(i) #if isinstance(editorWidget, editor.Editor): #function = getattr(editorWidget, call_function) #function(*args, **kwargs) #TODO: add other splits def show_start_page(self): start = self.stack.widget(0) if isinstance(start, start_page.StartPage): self.stack.setCurrentIndex(0) else: startPage = start_page.StartPage(parent=self) # self.connect(startPage, SIGNAL("openProject(QString)"), # self.open_project) # self.connect(startPage, SIGNAL("openPreferences()"), # lambda: self.emit(SIGNAL("openPreferences()"))) # Connections startPage.newFile.connect(self.add_editor) self.stack.insertWidget(0, startPage) self.stack.setCurrentIndex(0) def show_python_doc(self): if sys.platform == 'win32': self.docPage = browser_widget.BrowserWidget( 'http://docs.python.org/') else: process = runner.start_pydoc() self.docPage = browser_widget.BrowserWidget(process[1], process[0]) self.add_tab(self.docPage, translations.TR_PYTHON_DOC) def show_report_bugs(self): webbrowser.open(resources.BUGS_PAGE) def show_plugins_doc(self): bugsPage = browser_widget.BrowserWidget(resources.PLUGINS_DOC, self) self.add_tab(bugsPage, translations.TR_HOW_TO_WRITE_PLUGINS) def editor_jump_to_line(self, lineno=None): """Jump to line *lineno* if it is not None otherwise ask to the user the line number to jump """ editorWidget = self.get_current_editor() if editorWidget: editorWidget.jump_to_line(lineno=lineno) def get_opened_documents(self): #return self.tabs.get_documents_data() return [] def check_for_unsaved_files(self): pass #return self.tabs._check_unsaved_tabs() def get_unsaved_files(self): pass #return self.tabs.get_unsaved_files() def reset_editor_flags(self): pass #for i in range(self.tabs.count()): #widget = self.tabs.widget(i) #if isinstance(widget, editor.Editor): #widget.set_flags() def _specify_syntax(self, widget, syntaxLang): if isinstance(widget, editor.Editor): widget.restyle(syntaxLang) def apply_editor_theme(self, family, size): pass #for i in range(self.tabs.count()): #widget = self.tabs.widget(i) #if isinstance(widget, editor.Editor): #widget.restyle() #widget.set_font(family, size) def update_editor_margin_line(self): pass #for i in range(self.tabs.count()): #widget = self.tabs.widget(i) #if isinstance(widget, editor.Editor): #widget._update_margin_line() def open_project(self, path): self.emit(SIGNAL("openProject(QString)"), path) def close_python_doc(self): pass # close the python document server (if running) # if self.docPage: # index = self.tabs.indexOf(self.docPage) # self.tabs.removeTab(index) # assign None to the browser # self.docPage = None def close_file(self): self.current_widget.close_current_file() def create_file(self, base_path, project_path): self._add_file_folder.create_file(base_path, project_path) def create_folder(self, base_path, project_path): self._add_file_folder.create_folder(base_path, project_path) def change_tab(self): """Change the tab in the current TabWidget.""" self.stack.setCurrentWidget(self.splitter) # self._files_handler.next_item() def change_tab_reverse(self): """Change the tab in the current TabWidget backwards.""" self.stack.setCurrentWidget(self.splitter) # self._files_handler.previous_item() def toggle_tabs_and_spaces(self): """Toggle Show/Hide Tabs and Spaces""" settings.SHOW_TABS_AND_SPACES = not settings.SHOW_TABS_AND_SPACES qsettings = IDE.ninja_settings() qsettings.setValue('preferences/editor/show_tabs_and_spaces', settings.SHOW_TABS_AND_SPACES) neditor = self.get_current_editor() if neditor is not None: neditor.show_whitespaces = settings.SHOW_TABS_AND_SPACES def show_navigation_buttons(self): """Show Navigation menu.""" self.stack.setCurrentWidget(self.splitter) self.combo_area.show_menu_navigation() def change_split_focus(self): pass #FIXME: check how we handle this #if self.actualTab == self._tabMain and self.tabsecondary.isVisible(): #self.actualTab = self.tabsecondary #else: #self.actualTab = self._tabMain #widget = self.actualTab.currentWidget() #if widget is not None: #widget.setFocus() def shortcut_index(self, index): pass #self.tabs.setCurrentIndex(index) def print_file(self): """Call the print of ui_tool Call print of ui_tool depending on the focus of the application""" #TODO: Add funtionality for proyect tab and methods tab editorWidget = self.get_current_editor() if editorWidget is not None: fileName = "newDocument.pdf" if editorWidget.file_path: fileName = file_manager.get_basename(editorWidget.file_path) fileName = fileName[:fileName.rfind('.')] + '.pdf' ui_tools.print_file(fileName, editorWidget.print_) def split_assistance(self): dialog = split_orientation.SplitOrientation(self) dialog.show() # def close_split(self): # if self.current_widget != self.combo_area: # self.current_widget.bar.close_split() # def split_vertically(self): # self.show_split(False) # def split_horizontally(self): # self.show_split(True) def navigate_back(self): self.__navigate_with_keyboard(False) def navigate_forward(self): self.__navigate_with_keyboard(True)
class ComboEditor(QWidget): # Signals closeSplit = pyqtSignal('PyQt_PyObject') splitEditor = pyqtSignal('PyQt_PyObject', 'PyQt_PyObject', Qt.Orientation) allFilesClosed = pyqtSignal() about_to_close_combo_editor = pyqtSignal() fileClosed = pyqtSignal("PyQt_PyObject") def __init__(self, original=False): super(ComboEditor, self).__init__(None) self.__original = original self.__undocked = [] self._symbols_index = [] vbox = QVBoxLayout(self) vbox.setContentsMargins(0, 0, 0, 0) vbox.setSpacing(0) self.bar = ActionBar(main_combo=original) vbox.addWidget(self.bar) # Info bar # self.info_bar = InfoBar(self) # self.info_bar.setVisible(False) # vbox.addWidget(self.info_bar) self.stacked = QStackedLayout() vbox.addLayout(self.stacked) self._main_container = IDE.get_service('main_container') if not self.__original: self._main_container.fileOpened['QString'].connect( self._file_opened_by_main) self.bar.combo_files.showComboSelector.connect( self._main_container.show_files_handler) self.bar.combo_files.hideComboSelector.connect( self._main_container.hide_files_handler) self.bar.change_current['PyQt_PyObject', int].connect(self._set_current) self.bar.splitEditor[bool].connect(self.split_editor) self.bar.runFile['QString'].connect(self._run_file) self.bar.closeSplit.connect(lambda: self.closeSplit.emit(self)) self.bar.addToProject['QString'].connect(self._add_to_project) self.bar.showFileInExplorer['QString'].connect( self._show_file_in_explorer) self.bar.goToSymbol[int].connect(self._go_to_symbol) self.bar.undockEditor.connect(self.undock_editor) self.bar.reopenTab['QString'].connect( lambda path: self._main_container.open_file(path)) self.bar.closeImageViewer.connect(self._close_image) self.bar.code_navigator.previousPressed.connect(self._navigate_code) self.bar.code_navigator.nextPressed.connect(self._navigate_code) # self.connect(self.bar, SIGNAL("recentTabsModified()"), # lambda: self._main_container.recent_files_changed()) # self.connect(self.bar.code_navigator.btnPrevious, # SIGNAL("clicked()"), # lambda: self._navigate_code(False)) # self.connect(self.bar.code_navigator.btnNext, SIGNAL("clicked()"), # lambda: self._navigate_code(True)) def _navigate_code(self, operation, forward=True): self._main_container.navigate_code_history(operation, forward) # op = self.bar.code_navigator.operation # self._main_container.navigate_code_history(val, op) def current_editor(self): return self.stacked.currentWidget() def setFocus(self): super(ComboEditor, self).setFocus() self.current_editor().setFocus() self._editor_with_focus() def _file_opened_by_main(self, path): index = self.stacked.currentIndex() ninjaide = IDE.get_service('ide') editable = ninjaide.get_or_create_editable(path) self.add_editor(editable) self.bar.set_current_by_index(index) if index == -1: self.bar.set_current_by_index(0) def add_image_viewer(self, viewer): """Add Image Viewer widget to the UI area""" self.stacked.addWidget(viewer) viewer.scaleFactorChanged.connect( self.bar.image_viewer_controls.update_scale_label) viewer.imageSizeChanged.connect( self.bar.image_viewer_controls.update_size_label) self.bar.add_item(viewer.display_name(), None) viewer.create_scene() if not self.bar.isVisible(): self.bar.setVisible(True) def add_editor(self, neditable, keep_index=False): """Add Editor Widget to the UI area.""" if neditable.editor: if self.__original: editor = neditable.editor else: # editor = neditable.editor.clone() editor = self._main_container.create_editor_from_editable( neditable) neditable.editor.link(editor) current_index = self.stacked.currentIndex() new_index = self.stacked.addWidget(editor) self.stacked.setCurrentIndex(new_index) self.bar.add_item(neditable.display_name, neditable) # Bar is not visible because all the files have been closed, # so if a new file is opened, show the bar if not self.bar.isVisible(): self.bar.setVisible(True) if keep_index: self.bar.set_current_by_index(current_index) # Connections neditable.fileClosing.connect(self._close_file) neditable.fileSaved.connect(self._update_symbols) editor.editorFocusObtained.connect(self._editor_with_focus) editor.modificationChanged.connect(self._editor_modified) editor.cursor_position_changed[int, int].connect( self._update_cursor_position) editor.current_line_changed[int].connect(self._set_current_symbol) if neditable._swap_file.dirty: self._editor_modified(True, sender=editor) neditable.checkersUpdated.connect(self._show_notification_icon) # Connect file system signals only in the original if self.__original: neditable.askForSaveFileClosing.connect(self._ask_for_save) neditable.fileChanged.connect(self._file_has_been_modified) # Load Symbols self._load_symbols(neditable) def show_combo_file(self): self.bar.combo.showPopup() def show_combo_symbol(self): self.bar.symbols_combo.showPopup() def show_combo_set_language(self): self.bar.set_language_combo.showPopup() def unlink_editors(self): for index in range(self.stacked.count()): widget = self.stacked.widget(index) # widget.setDocument(QsciDocument()) def clone(self): combo = ComboEditor() for neditable in self.bar.get_editables(): combo.add_editor(neditable) return combo def split_editor(self, orientation): new_combo = self.clone() self.splitEditor.emit(self, new_combo, orientation) def undock_editor(self): new_combo = ComboEditor() for neditable in self.bar.get_editables(): new_combo.add_editor(neditable) self.__undocked.append(new_combo) new_combo.setWindowTitle("NINJA-IDE") editor = self.current_editor() new_combo.set_current(editor.neditable) new_combo.resize(700, 500) new_combo.about_to_close_combo_editor.connect(self._remove_undock) new_combo.show() def _remove_undock(self): widget = self.sender() self.__undocked.remove(widget) def close_current_file(self): self.bar.about_to_close_file() def _close_image(self, index): layout_item = self.stacked.takeAt(index) layout_item.widget().deleteLater() if self.stacked.isEmpty(): self.bar.hide() self.allFilesClosed.emit() def _close_file(self, neditable): index = self.bar.close_file(neditable) layoutItem = self.stacked.takeAt(index) # neditable.editor.completer.cc.unload_module() self.fileClosed.emit(neditable.nfile) layoutItem.widget().deleteLater() if self.stacked.isEmpty(): self.bar.hide() self.allFilesClosed.emit() tree_symbols = IDE.get_service("symbols_explorer") if tree_symbols is not None: tree_symbols.clear() def _editor_with_focus(self): self._main_container.combo_area = self editor = self.current_editor() if editor is not None: self._main_container.current_editor_changed( editor.neditable.file_path) self._load_symbols(editor.neditable) editor.neditable.update_checkers_display() def _ask_for_save(self, neditable): val = QMessageBox.No fileName = neditable.nfile.file_name val = QMessageBox.question( self, (self.tr('The file %s was not saved') % fileName), self.tr("Do you want to save before closing?"), QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel) if val == QMessageBox.No: neditable.nfile.close(force_close=True) elif val == QMessageBox.Yes: neditable.ignore_checkers = True self._main_container.save_file(neditable.editor) neditable.nfile.close() @pyqtSlot("PyQt_PyObject") def _recovery(self, neditable): print("lalalal") def _file_has_been_modified(self, neditable): index = self.bar.combo_files.findData(neditable) self.stacked.setCurrentIndex(index) self.bar.combo_files.setCurrentIndex(index) msg_box = QMessageBox(self) msg_box.setIcon(QMessageBox.Information) msg_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No) msg_box.setDefaultButton(QMessageBox.Yes) msg_box.setWindowTitle(translations.TR_FILE_HAS_BEEN_MODIFIED) msg_box.setText(translations.TR_FILE_MODIFIED_OUTSIDE % neditable.display_name) result = msg_box.exec_() if result == QMessageBox.Yes: neditable.reload_file() return def _run_file(self, path): self._main_container.run_file(path) def _add_to_project(self, path): self._main_container._add_to_project(path) def _show_file_in_explorer(self, path): '''Connected to ActionBar's showFileInExplorer(QString) signal, forwards the file path on to the main container.''' self._main_container._show_file_in_explorer(path) def set_current(self, neditable): if neditable: self.bar.set_current_file(neditable) def _set_current(self, neditable, index): self.stacked.setCurrentIndex(index) if neditable: self.bar.image_viewer_controls.setVisible(False) self.bar.code_navigator.setVisible(True) self.bar.symbols_combo.setVisible(True) self.bar.lbl_position.setVisible(True) editor = self.current_editor() self._update_cursor_position(ignore_sender=True) editor.setFocus() self._main_container.current_editor_changed(neditable.file_path) self._load_symbols(neditable) # self._show_file_in_explorer(neditable.file_path) neditable.update_checkers_display() else: self.bar.combo_files.setCurrentIndex(index) viewer_widget = self.stacked.widget(index) self._main_container.current_editor_changed( viewer_widget.image_filename) self.bar.image_viewer_controls.setVisible(True) self.bar.code_navigator.setVisible(False) self.bar.symbols_combo.setVisible(False) self.bar.lbl_position.setVisible(False) def widget(self, index): return self.stacked.widget(index) def count(self): """Return the number of editors opened.""" return self.stacked.count() def _update_cursor_position(self, line=0, col=0, ignore_sender=False): obj = self.sender() editor = self.current_editor() # Check if it's current to avoid signals from other splits. if ignore_sender or editor == obj: line += 1 self.bar.update_line_col(line, col) def _set_current_symbol(self, line, ignore_sender=False): obj = self.sender() editor = self.current_editor() # Check if it's current to avoid signals from other splits. if ignore_sender or editor == obj: index = bisect.bisect(self._symbols_index, line) if (index >= len(self._symbols_index) or self._symbols_index[index] > (line + 1)): index -= 1 self.bar.set_current_symbol(index) def _editor_modified(self, value, sender=None): if sender is None: sender = self.sender() neditable = sender.neditable if value: text = "\u2022 %s" % neditable.display_name self.bar.update_item_text(neditable, text) else: self.bar.update_item_text(neditable, neditable.display_name) def _go_to_symbol(self, index): line = self._symbols_index[index] editor = self.current_editor() editor.go_to_line(line, center=True) editor.setFocus() def _update_symbols(self, neditable): editor = self.current_editor() # Check if it's current to avoid signals from other splits. if editor.neditable == neditable: self._load_symbols(neditable) def _update_combo_info(self, neditable): self.bar.update_item_text(neditable, neditable.display_name) self._main_container.current_editor_changed(neditable.file_path) def _load_symbols(self, neditable): # Get symbols handler by language symbols_handler = handlers.get_symbols_handler(neditable.language()) if symbols_handler is None: return source = neditable.editor.text source = source.encode(neditable.editor.encoding) symbols, symbols_simplified = symbols_handler.obtain_symbols( source, simple=True) self._symbols_index = sorted(symbols_simplified.keys()) symbols_simplified = sorted(list(symbols_simplified.items()), key=lambda x: x[0]) self.bar.add_symbols(symbols_simplified) line, _ = neditable.editor.cursor_position self._set_current_symbol(line, True) tree_symbols = IDE.get_service('symbols_explorer') if tree_symbols is not None: tree_symbols.update_symbols_tree(symbols, neditable.file_path) def _show_notification_icon(self, neditable): checkers = neditable.sorted_checkers icon = QIcon() for items in checkers: checker, color, _ = items if checker.checks: if isinstance(checker.checker_icon, int): icon = self.style().standardIcon(checker.checker_icon) elif isinstance(checker.checker_icon, str): icon = QIcon(checker.checker_icon) # FIXME: sucks else: icon = QIcon(checker.checker_icon) break self.bar.update_item_icon(neditable, icon) def show_menu_navigation(self): self.bar.code_navigator.show_menu_navigation() def closeEvent(self, event): self.about_to_close_combo_editor.emit() # self.emit(SIGNAL("aboutToCloseComboEditor()")) super(ComboEditor, self).closeEvent(event) def reject(self): if not self.__original: super(ComboEditor, self).reject()
class _MainContainer(QWidget): currentEditorChanged = pyqtSignal(str) fileOpened = pyqtSignal(str) beforeFileSaved = pyqtSignal(str) fileSaved = pyqtSignal(str) runFile = pyqtSignal(str) showFileInExplorer = pyqtSignal(str) addToProject = pyqtSignal(str) allFilesClosed = pyqtSignal() def __init__(self, parent=None): super().__init__(parent) self.setAcceptDrops(True) self._vbox = QVBoxLayout(self) self._vbox.setContentsMargins(0, 0, 0, 0) self._vbox.setSpacing(0) self.stack = QStackedLayout() self.stack.setStackingMode(QStackedLayout.StackAll) self._vbox.addLayout(self.stack) self.splitter = dynamic_splitter.DynamicSplitter() self._files_handler = files_handler.FilesHandler(self) # Code Navigation self.__code_back = [] self.__code_forward = [] self.__operations = { 0: self._navigate_code_jumps, 1: self._navigate_bookmarks } # Recent files list self.__last_opened_files = [] # QML UI self._add_file_folder = add_file_folder.AddFileFolderWidget(self) if settings.SHOW_START_PAGE: self.show_start_page() IDE.register_service("main_container", self) # Register signals connections connections = ( # "slot": self._explore_code { "target": "filesystem", "signal_name": "projectOpened", "slot": self._explore_code }, # "slot": self._explore_code { "target": "filesystem", "signal_name": "projectClosed", "slot": self._explore_code }) IDE.register_signals("main_container", connections) fhandler_short = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Tab), self) fhandler_short.activated.connect(self.show_files_handler) # Added for set language def install(self): ninjaide = IDE.get_service("ide") ninjaide.place_me_on("main_container", self, "central", top=True) self.combo_area = combo_editor.ComboEditor(original=True) self.combo_area.allFilesClosed.connect(self._files_closed) self.combo_area.allFilesClosed.connect( lambda: self.allFilesClosed.emit()) self.combo_area.fileClosed.connect(self._add_to_last_opened) self.splitter.add_widget(self.combo_area) self.add_widget(self.splitter) # Code Locator self._code_locator = locator_widget.LocatorWidget(ninjaide) data_settings = IDE.data_settings() recent_files = data_settings.value("lastSession/recentFiles") if recent_files is not None: self.__last_opened_files = recent_files ui_tools.install_shortcuts(self, actions.ACTIONS, ninjaide) def run_file(self, filepath): self.runFile.emit(filepath) def _show_file_in_explorer(self, filepath): self.showFileInExplorer.emit(filepath) def _add_to_project(self, filepath): self.addToProject.emit(filepath) def show_files_handler(self): self._files_handler.next_item() def hide_files_handler(self): self._files_handler.hide() def import_from_everywhere(self): """Insert an import line from any place in the editor.""" editorWidget = self.get_current_editor() if editorWidget: dialog = from_import_dialog.FromImportDialog(editorWidget, self) dialog.show() def navigate_code_history(self, operation, forward): self.__operations[operation](forward) def _navigate_code_jumps(self, forward=False): """Navigate between the jump points""" node = None if not forward and self.__code_back: if len(self.__code_back) == 1: return node = self.__code_back.pop() self.__code_forward.append(node) node = self.__code_back[-1] elif forward and self.__code_forward: node = self.__code_forward.pop() self.__code_back.append(node) if node is not None: filename = node[0] line, col = node[1] self.open_file(filename, line, col) def _navigate_bookmarks(self, forward=True): """Navigate between the bookmarks""" current_editor = self.get_current_editor() current_editor.navigate_bookmarks(forward=forward) def _set_focus_to_editor(self): status_bar = IDE.get_service("status_bar") tools_doock = IDE.get_service("tools_dock") editor_widget = self.get_current_editor() if status_bar.isVisible() and tools_doock.isVisible(): status_bar.hide_status_bar() elif tools_doock.isVisible(): tools_doock._hide() elif status_bar.isVisible(): status_bar.hide_status_bar() if editor_widget is not None: editor_widget.extra_selections.remove("find") editor_widget.scrollbar().remove_marker("find") def split_assistance(self): editor_widget = self.get_current_editor() if editor_widget is not None: split_widget = split_orientation.SplitOrientation(self) split_widget.show() def show_dialog(self, widget): self.add_widget(widget) self.stack.setCurrentWidget(widget) def show_split(self, orientation_vertical=False): orientation = Qt.Horizontal if orientation_vertical: orientation = Qt.Vertical self.combo_area.split_editor(orientation) def show_locator(self): """Show the Locator Widget""" if not self._code_locator.isVisible(): self._code_locator.show() def _explore_code(self): """Update locator metadata for the current projects""" self._code_locator.explore_code() def _explore_file_code(self, path): """Update locator metadata for the file in path""" self._code_locator.explore_file_code(path) def current_editor_changed(self, filename): """Notify the new filename of the current editor""" if filename is None: filename = translations.TR_NEW_DOCUMENT self.currentEditorChanged.emit(filename) def get_current_editor(self): current_widget = self.combo_area.current_editor() if isinstance(current_widget, editor.NEditor): return current_widget return None @property def last_opened_files(self): return self.__last_opened_files def _add_to_last_opened(self, nfile): MAX_RECENT_FILES = 10 # FIXME: configuration if nfile.is_new_file: return file_path = nfile.file_path if file_path in self.__last_opened_files: self.__last_opened_files.remove(file_path) self.__last_opened_files.insert(0, file_path) if len(self.__last_opened_files) > MAX_RECENT_FILES: self.__last_opened_files.pop(-1) def clear_last_opened_files(self): self.__last_opened_files.clear() def open_file(self, filename='', line=-1, col=0, ignore_checkers=False): if not filename: logger.debug("Has no filename") if settings.WORKSPACE: directory = settings.WORKSPACE else: directory = os.path.expanduser("~") editor_widget = self.get_current_editor() ninjaide = IDE.get_service("ide") current_project = ninjaide.get_current_project() # TODO: handle current project in NProject if current_project is not None: directory = current_project.full_path elif editor_widget is not None and editor_widget.file_path: directory = file_manager.get_folder( editor_widget.file_path) filenames = QFileDialog.getOpenFileNames( self, translations.TR_OPEN_A_FILE, directory, settings.get_supported_extensions_filter(), initialFilter="Python files (*.py *.pyw)")[0] else: logger.debug("Has filename") filenames = [filename] if not filenames: return for filename in filenames: image_extensions = ("png", "jpg", "jpeg", "bmp", "gif") if file_manager.get_file_extension(filename) in image_extensions: logger.debug("Will open as image") self.open_image(filename) else: logger.debug("Will try to open: %s" % filename) self.__open_file(filename, line, col, ignore_checkers=ignore_checkers) def __open_file(self, filename, line, col, ignore_checkers=False): try: self.add_editor(filename) if line != -1: self.editor_go_to_line(line, col) self.currentEditorChanged.emit(filename) except file_manager.NinjaIOException as reason: QMessageBox.information(self, translations.TR_OPEN_FILE_ERROR, str(reason)) logger.error("The file %s couldn't be open" % filename) def open_image(self, filename): for index in range(self.combo_area.stacked.count()): widget = self.combo_area.stacked.widget(index) if isinstance(widget, image_viewer.ImageViewer): if widget.image_filename == filename: logger.debug("Image already open") self.combo_area._set_current(neditable=None, index=index) return viewer = image_viewer.ImageViewer(filename) self.combo_area.add_image_viewer(viewer) self.stack.setCurrentWidget(self.splitter) def autosave_file(self): for neditable in self.combo_area.bar.get_editables(): neditable.autosave_file() def save_file(self, editor_widget=None): if editor_widget is None: # This may return None if there is not editor present editor_widget = self.get_current_editor() if editor_widget is None: return False # Ok, we have an editor instance # Save to file only if editor really was modified if editor_widget.is_modified: try: if editor_widget.nfile.is_new_file or \ not editor_widget.nfile.has_write_permission(): return self.save_file_as(editor_widget) file_path = editor_widget.file_path # Emit signal before save self.beforeFileSaved.emit(file_path) if settings.REMOVE_TRAILING_SPACES: editor_widget.remove_trailing_spaces() if settings.ADD_NEW_LINE_AT_EOF: editor_widget.insert_block_at_end() # Save content editor_widget.neditable.save_content() # FIXME: encoding message = translations.TR_FILE_SAVED.format(file_path) self.fileSaved.emit(message) return True except Exception as reason: logger.error("Save file error: %s" % reason) QMessageBox.information(self, translations.TR_SAVE_FILE_ERROR_TITLE, translations.TR_SAVE_FILE_ERROR_BODY) return False def save_file_as(self, editor_widget=None): force = False if editor_widget is None: # We invoque from menu editor_widget = self.get_current_editor() if editor_widget is None: # We haven't editor in main container return False force = True try: filters = "(*.py);;(*.*)" if editor_widget.file_path is not None: # Existing file extension = file_manager.get_file_extension( editor_widget.file_path) if extension != 'py': filters = "(*.%s);;(*.py);;(*.*)" % extension save_folder = self._get_save_folder(editor_widget.file_path) else: save_folder = settings.WORKSPACE filename = QFileDialog.getSaveFileName( self, translations.TR_SAVE_FILE_DIALOG, save_folder, filters)[0] if not filename: return False # FIXME: remove trailing spaces extension = file_manager.get_file_extension(filename) if not extension: filename = "%s.%s" % (filename, "py") editor_widget.neditable.save_content(path=filename, force=force) self.fileSaved.emit(translations.TR_FILE_SAVED.format(filename)) self.currentEditorChanged.emit(filename) return True except file_manager.NinjaFileExistsException as reason: QMessageBox.information( self, translations.TR_FILE_ALREADY_EXISTS_TITLE, translations.TR_FILE_ALREADY_EXISTS_BODY.format( reason.filename)) except Exception as reason: logger.error("Save file as: %s", reason) QMessageBox.information(self, translations.TR_SAVE_FILE_ERROR_TITLE, translations.TR_SAVE_FILE_ERROR_BODY) return False def save_project(self, project_path): """Save all files in the project path""" for neditable in self.combo_area.bar.get_editables(): file_path = neditable.file_path if file_path is None: # FIXME: New edited files will not be saved, its ok? continue if file_manager.belongs_to_folder(project_path, file_path): neditable.save_content() def _get_save_folder(self, filename): """Returns the root directory of the 'Main Project' or the home folder""" ninjaide = IDE.get_service("ide") current_project = ninjaide.get_current_project() if current_project is not None: return current_project.path return os.path.expanduser("~") def close_file(self): self.combo_area.close_current_file() def add_editor(self, filename=None): ninjaide = IDE.get_service("ide") editable = ninjaide.get_or_create_editable(filename) if editable.editor: # If already open logger.debug("%s is already open" % filename) self.combo_area.set_current(editable) return self.combo_area.current_editor() else: pass editor_widget = self.create_editor_from_editable(editable) # Add the tab keep_index = (self.splitter.count() > 1 and self.combo_area.stacked.count() > 0) self.combo_area.add_editor(editable, keep_index) # Emit a signal about the file open self.fileOpened.emit(filename) if keep_index: self.combo_area.set_current(editable) self.stack.setCurrentWidget(self.splitter) editor_widget.setFocus() return editor_widget def create_editor_from_editable(self, editable): neditor = editor.create_editor(editable) neditor.zoomChanged.connect(self._on_zoom_changed) neditor.addBackItemNavigation.connect(self.add_back_item_navigation) editable.fileSaved.connect( lambda neditable: self._explore_file_code(neditable.file_path)) return neditor def add_back_item_navigation(self): editor_widget = self.get_current_editor() if editor_widget is not None: item = (editor_widget.file_path, editor_widget.cursor_position) if item not in self.__code_back: self.__code_back.append(item) def _on_zoom_changed(self, zoom): text = "Zoom: {}%".format(str(zoom)) ide = IDE.get_service("ide") ide.show_message(text) def add_widget(self, widget): self.stack.addWidget(widget) def show_start_page(self): """Show Start Page widget in main container""" startp = self.stack.widget(0) if isinstance(startp, start_page.StartPage): self.stack.setCurrentIndex(0) else: startp = start_page.StartPage(parent=self) startp.newFile.connect(self.add_editor) self.stack.insertWidget(0, startp) self.stack.setCurrentIndex(0) def _files_closed(self): if settings.SHOW_START_PAGE: self.show_start_page() def add_status_bar(self, status_bar): self._vbox.addWidget(status_bar) def create_file(self, base_path, project_path): self._add_file_folder.create_file(base_path, project_path) def create_folder(self, base_path, project_path): self._add_file_folder.create_folder(base_path, project_path) def restyle_editor(self): neditables = self.combo_area.bar.get_editables() for neditable in neditables: neditable.editor.restyle() def zoom_in_editor(self): """Increase the font size in the current editor""" editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.zoom(1.) def zoom_out_editor(self): """Decrease the font size in the current editor""" editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.zoom(-1.) def reset_zoom_editor(self): """Reset the to original font size in the current editor""" editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.reset_zoom() def editor_move_up(self): editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.move_up_down(up=True) def editor_move_down(self): editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.move_up_down() def editor_duplicate_line(self): editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.duplicate_line() def editor_toggle_comment(self): """Mark the current line or selection as a comment.""" editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.comment_or_uncomment() def editor_go_to_line(self, line, column=0, center=True): editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.go_to_line(line, column, center) editor_widget.setFocus() def _editor_settings_changed(self, key, value): key = key.split("/")[-1] editor_widget = self.get_current_editor() if editor_widget is not None: callback = getattr(editor.NEditor, key, False) if callback: callback = callback if not hasattr(callback, "__call__"): # Property! callback = callback.fset callback(editor_widget, value) def toggle_tabs_and_spaces(self): """Toggle Show/Hide Tabs and Spaces""" settings.SHOW_TABS_AND_SPACES = not settings.SHOW_TABS_AND_SPACES qsettings = IDE.ninja_settings() qsettings.setValue('preferences/editor/showTabsAndSpaces', settings.SHOW_TABS_AND_SPACES) neditor = self.get_current_editor() if neditor is not None: neditor.show_whitespaces = settings.SHOW_TABS_AND_SPACES def __navigate_with_keyboard(self, forward): """Navigate between the positions in the jump history stack.""" operation = self.combo_area.bar.code_navigator.operation self.navigate_code_history(operation, forward) def navigate_back(self): self.__navigate_with_keyboard(forward=False) def navigate_forward(self): self.__navigate_with_keyboard(forward=True)
class _MainContainer(QWidget): ############################################################################### # MainContainer SIGNALS ############################################################################### """ newFileOpened(QString) allTabClosed() runFile(QString) addToProject(QString) showFileInExplorer(QString) recentTabsModified() currentEditorChanged(QString) fileOpened(QString) ---------migrationAnalyzed() findOcurrences(QString) ---------updateFileMetadata() editorKeyPressEvent(QEvent) locateFunction(QString, QString, bool) [functionName, filePath, isVariable] updateLocator(QString) beforeFileSaved(QString) fileSaved(QString) openPreferences() --------openProject(QString) ---------dontOpenStartPage() """ newFileOpened = pyqtSignal(str) allTabClosed = pyqtSignal() runFile = pyqtSignal(str) addToProject = pyqtSignal(str) showFileInExplorer = pyqtSignal(str) recentTabsModified = pyqtSignal() currentEditorChanged = pyqtSignal(str) fileOpened = pyqtSignal(str) migrationAnalyzed = pyqtSignal()#----------- findOcurrences = pyqtSignal(str) updateFileMetadata = pyqtSignal()#----------- editorKeyPressEvent = pyqtSignal('QEvent*') locateFunction = pyqtSignal(str, str, bool) updateLocator = pyqtSignal(str) beforeFileSaved = pyqtSignal(str) fileSaved = pyqtSignal(str) openPreferences = pyqtSignal() openProject = pyqtSignal(str)#----------- dontOpenStartPage = pyqtSignal()#----------- closeDialog = pyqtSignal('QObject*') allTabsClosed = pyqtSignal() splitEditor = pyqtSignal('QWidget*', 'QWidget*', bool) closeSplit = pyqtSignal(QWidget) toRemovePreview = pyqtSignal() ############################################################################### def __init__(self, parent=None): super(_MainContainer, self).__init__(parent) self._parent = parent self._vbox = QVBoxLayout(self) self._vbox.setContentsMargins(0, 0, 0, 0) self._vbox.setSpacing(0) self.stack = QStackedLayout() self.stack.setStackingMode(QStackedLayout.StackAll) self._vbox.addLayout(self.stack) self.splitter = dynamic_splitter.DynamicSplitter() self.setAcceptDrops(True) # self._files_handler = files_handler.FilesHandler(self) self._add_file_folder = add_file_folder.AddFileFolderWidget(self) self.tdir = None #documentation browser self.docPage = None #Code Navigation self._locator = locator.GoToDefinition() self.__codeBack = [] self.__codeForward = [] self.__bookmarksFile = '' self.__bookmarksPos = -1 self.__breakpointsFile = '' self.__breakpointsPos = -1 self.__operations = { 0: self._navigate_code_jumps, 1: self._navigate_bookmarks, 2: self._navigate_breakpoints} self.locateFunction.connect(self.locate_function) IDE.register_service('main_container', self) #Register signals connections connections = ( {'target': 'menu_file', 'signal_name': 'openFile',#(QString) 'slot': self.open_file}, {'target': 'explorer_container', 'signal_name': 'goToDefinition',#(int) 'slot': self.editor_go_to_line}, {'target': 'explorer_container', 'signal_name': 'pep8Activated',#(bool) 'slot': self.reset_pep8_warnings}, {'target': 'explorer_container', 'signal_name': 'lintActivated',#(bool) 'slot': self.reset_lint_warnings}, ) IDE.register_signals('main_container', connections) self.selector = main_selector.MainSelector(self) self._opening_dialog = False self.add_widget(self.selector) if settings.SHOW_START_PAGE: self.show_start_page() self.selector.changeCurrent[int].connect(self._change_current_stack) self.selector.removeWidget[int].connect(self._remove_item_from_stack) self.selector.ready.connect(self._selector_ready) self.selector.closePreviewer.connect(self._selector_Close) self.selector.animationCompleted.connect(self._selector_animation_completed) self.closeDialog.connect(self.remove_widget) self.stack.widgetRemoved[int].connect(lambda i:print("widgetRemoved._-", i)) def install(self): ide = IDE.getInstance() ide.place_me_on("main_container", self, "central", top=True) self.combo_area = combo_editor.ComboEditor(original=True) self.combo_area.allFilesClosed.connect(self._files_closed) self.splitter.add_widget(self.combo_area) self.add_widget(self.splitter) self.current_widget = self.combo_area ui_tools.install_shortcuts(self, actions.ACTIONS, ide) def add_status_bar(self, status): self._vbox.addWidget(status) @property def combo_header_size(self): return self.combo_area.bar.height() def add_widget(self, widget): i = self.stack.addWidget(widget) #if not isinstance(widget, start_page.StartPage): self.tryMakeImagePreview(i) def remove_widget(self, widget): #self.toRemovePreview.emit(self.stack.widget(widget)) self.stack.removeWidget(widget) def _close_dialog(self, widget): self.closeDialog.emit(widget) widget.finished[int].disconnect()#lambda i: self._close_dialog(widget)) def show_dialog(self, widget): print("\n\nshow_dialog", self.isVisible()) self._opening_dialog = True widget.finished[int].connect(lambda i: self._close_dialog(widget)) widget.setVisible(True) self.show_selector() def show_selector(self): print("\n\nshow_selector::", self.selector, self.stack.currentWidget()) if self.selector != self.stack.currentWidget(): _dir = self.Successful_Tmp() if not _dir: print("failed!") return # temp_dir = os.path.join(QDir.tempPath(), "ninja-ide") # if not os.path.exists(temp_dir): # os.mkdir(temp_dir) collected_data = [] current = self.stack.currentIndex() for index in range(self.stack.count()): widget = self.stack.widget(index) if widget == self.selector: continue closable = True if widget == self.splitter: closable = False # path = os.path.join(temp_dir, "screen%s.png" % index) #ff = QFile(_dir, "screen%s.png" % index) path = _dir.absolutePath()+"/screen%s.png" % index pixmap = widget.grab()#widget.rect()) pixmap.save(path) #path = path.replace("\\", '/') #print("path::", path, QFileInfo(path).exists()) path = "file:///"+path if index == current: self.selector.set_preview(index, path)#QUrl(path) collected_data.insert(0, (index, path, closable)) else: collected_data.append((index, path, closable)) self.selector.set_model(collected_data) print("self.selector.set_model()", collected_data) self.stack.setCurrentWidget(self.selector) else: print("\n\n_selector_Close()") self._selector_Close() def Successful_Tmp(self):# CheckTmpDir, StateTmpDir failed = lambda: not self.tdir or not self.tdir.isValid() if failed():# not successfully self.tdir = QTemporaryDir() if failed(): QMessageBox.critical(self, "Unexpected Failurer", "The application has detected a problem trying to\nCreate or Access a Temporary File!.") return None else: self.tdir.setAutoRemove(True) d = QDir(self.tdir.path()) if not d.exists("ninja-ide"): if not d.mkdir("ninja-ide"): self.tdir = None d.cd("ninja-ide") return d def tryMakeImagePreview(self, index): return d = self.Successful_Tmp() if d: self.makeImagePreview(d, index) def makeImagePreview(self, _dir, index): return path = _dir.absolutePath()+"/screen%s.png" % index widget = self.stack.widget(index) pixmap = widget.grab()#widget.rect() pixmap.save(path) def _selector_ready(self): self.stack.setCurrentWidget(self.selector) self.selector.GoTo_GridPreviews() def _selector_Close(self): self.stack.setCurrentWidget(self.splitter) def _selector_animation_completed(self): if self._opening_dialog: # We choose the last one with -2, -1 (for last one) + # -1 for the hidden selector widget which is in the stacked too. self.selector.open_item(self.stack.count() - 2) self._opening_dialog = False def _change_current_stack(self, index): self.stack.setCurrentIndex(index) def _remove_item_from_stack(self, index): #self.toRemovePreview.emit(index) widget = self.stack.takeAt(index) del widget def show_editor_area(self): self.stack.setCurrentWidget(self.splitter) def _files_closed(self): if settings.SHOW_START_PAGE: self.show_start_page() def change_visibility(self): """Show/Hide the Main Container area.""" print("change_visibility11") if self.isVisible(): self.hide() else: self.show() def expand_symbol_combo(self): self.stack.setCurrentWidget(self.splitter) self.current_widget.show_combo_symbol() def expand_file_combo(self): print("expand_file_combo") self.stack.setCurrentWidget(self.splitter) self.current_widget.show_combo_file() def locate_function(self, function, filePath, isVariable): """Move the cursor to the proper position in the navigate stack.""" editorWidget = self.get_current_editor() if editorWidget: self.__codeBack.append((editorWidget.file_path, editorWidget.getCursorPosition())) self.__codeForward = [] self._locator.navigate_to(function, filePath, isVariable) def run_file(self, path): self.runFile.emit(path) def _add_to_project(self, path): self.addToProject.emit(path) def _show_file_in_explorer(self, path): self.showFileInExplorer.emit(path) def paste_history(self): """Paste the text from the copy/paste history.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): line, index = editorWidget.getCursorPosition() central = IDE.get_service('central_container') if central: editorWidget.insertAt(central.get_paste(), line, index) def copy_history(self): """Copy the selected text into the copy/paste history.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): copy = editorWidget.selectedText() central = IDE.get_service('central_container') if central: central.add_copy(copy) def import_from_everywhere(self): """Insert an import line from any place in the editor.""" editorWidget = self.get_current_editor() if editorWidget: dialog = from_import_dialog.FromImportDialog(editorWidget, self) dialog.show() def add_back_item_navigation(self): """Add an item to the back stack and reset the forward stack.""" editorWidget = self.get_current_editor() if editorWidget: self.__codeBack.append((editorWidget.file_path, editorWidget.getCursorPosition())) self.__codeForward = [] def preview_in_browser(self): """Load the current html file in the default browser.""" editorWidget = self.get_current_editor() if editorWidget: if not editorWidget.file_path: self.save_file() ext = file_manager.get_file_extension(editorWidget.file_path) if ext in ('html', 'shpaml', 'handlebars', 'tpl'): webbrowser.open_new_tab(editorWidget.file_path) def add_bookmark_breakpoint(self): """Add a bookmark or breakpoint to the current file in the editor.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): if self.current_widget.bar.code_navigator.operation == 1: editorWidget.handle_bookmarks_breakpoints( editorWidget.getCursorPosition()[0], Qt.ControlModifier) elif self.current_widget.bar.code_navigator.operation == 2: editorWidget.handle_bookmarks_breakpoints( editorWidget.getCursorPosition()[0], Qt.NoModifier) def __navigate_with_keyboard(self, val): """Navigate between the positions in the jump history stack.""" op = self.current_widget.bar.code_navigator.operation self.navigate_code_history(val, op) def navigate_code_history(self, val, op): """Navigate the code history.""" self.__operations[op](val) def _navigate_code_jumps(self, val): """Navigate between the jump points.""" node = None if not val and self.__codeBack: node = self.__codeBack.pop() editorWidget = self.get_current_editor() if editorWidget: self.__codeForward.append((editorWidget.file_path, editorWidget.getCursorPosition())) elif val and self.__codeForward: node = self.__codeForward.pop() editorWidget = self.get_current_editor() if editorWidget: self.__codeBack.append((editorWidget.file_path, editorWidget.getCursorPosition())) if node: filename = node[0] line, col = node[1] self.open_file(filename, line, col) def _navigate_breakpoints(self, val): """Navigate between the breakpoints.""" #FIXME: put navigate breakpoints and bookmarks as one method. breakList = list(settings.BREAKPOINTS.keys()) breakList.sort() if not breakList: return if self.__breakpointsFile not in breakList: self.__breakpointsFile = breakList[0] index = breakList.index(self.__breakpointsFile) breaks = settings.BREAKPOINTS.get(self.__breakpointsFile, []) lineNumber = 0 #val == True: forward if val: if (len(breaks) - 1) > self.__breakpointsPos: self.__breakpointsPos += 1 lineNumber = breaks[self.__breakpointsPos] elif len(breaks) > 0: if index < (len(breakList) - 1): self.__breakpointsFile = breakList[index + 1] else: self.__breakpointsFile = breakList[0] self.__breakpointsPos = 0 lineNumber = settings.BREAKPOINTS[self.__breakpointsFile][0] else: if self.__breakpointsPos > 0: self.__breakpointsPos -= 1 lineNumber = breaks[self.__breakpointsPos] elif len(breaks) > 0: self.__breakpointsFile = breakList[index - 1] breaks = settings.BREAKPOINTS[self.__breakpointsFile] self.__breakpointsPos = len(breaks) - 1 lineNumber = breaks[self.__breakpointsPos] if file_manager.file_exists(self.__breakpointsFile): self.open_file(self.__breakpointsFile, lineNumber, None, True) else: settings.BREAKPOINTS.pop(self.__breakpointsFile) if settings.BREAKPOINTS: self._navigate_breakpoints(val) def _navigate_bookmarks(self, val): """Navigate between the bookmarks.""" bookList = list(settings.BOOKMARKS.keys()) bookList.sort() if not bookList: return if self.__bookmarksFile not in bookList: self.__bookmarksFile = bookList[0] index = bookList.index(self.__bookmarksFile) bookms = settings.BOOKMARKS.get(self.__bookmarksFile, []) lineNumber = 0 #val == True: forward if val: if (len(bookms) - 1) > self.__bookmarksPos: self.__bookmarksPos += 1 lineNumber = bookms[self.__bookmarksPos] elif len(bookms) > 0: if index < (len(bookList) - 1): self.__bookmarksFile = bookList[index + 1] else: self.__bookmarksFile = bookList[0] self.__bookmarksPos = 0 lineNumber = settings.BOOKMARKS[self.__bookmarksFile][0] else: if self.__bookmarksPos > 0: self.__bookmarksPos -= 1 lineNumber = bookms[self.__bookmarksPos] elif len(bookms) > 0: self.__bookmarksFile = bookList[index - 1] bookms = settings.BOOKMARKS[self.__bookmarksFile] self.__bookmarksPos = len(bookms) - 1 lineNumber = bookms[self.__bookmarksPos] if file_manager.file_exists(self.__bookmarksFile): self.open_file(self.__bookmarksFile, lineNumber, None, True) else: settings.BOOKMARKS.pop(self.__bookmarksFile) if settings.BOOKMARKS: self._navigate_bookmarks(val) def count_file_code_lines(self): """Count the lines of code in the current file.""" editorWidget = self.get_current_editor() if editorWidget: block_count = editorWidget.lines() blanks = re.findall('(^\n)|(^(\s+)?#)|(^( +)?($|\n))', editorWidget.text(), re.M) blanks_count = len(blanks) resume = self.tr("Lines code: %s\n") % (block_count - blanks_count) resume += (self.tr("Blanks and commented lines: %s\n\n") % blanks_count) resume += self.tr("Total lines: %s") % block_count msgBox = QMessageBox(QMessageBox.Information, self.tr("Summary of lines"), resume, QMessageBox.Ok, editorWidget) msgBox.exec_() def editor_cut(self): editorWidget = self.get_current_editor() if editorWidget: editorWidget.cut() def editor_copy(self): editorWidget = self.get_current_editor() if editorWidget: editorWidget.copy() def editor_paste(self): editorWidget = self.get_current_editor() if editorWidget: editorWidget.paste() def editor_upper(self): editorWidget = self.get_current_editor() if editorWidget: editorWidget.to_upper() def editor_lower(self): editorWidget = self.get_current_editor() if editorWidget: editorWidget.to_lower() def editor_title(self): editorWidget = self.get_current_editor() if editorWidget: editorWidget.to_title() def editor_go_to_definition(self): """Search the definition of the method or variable under the cursor. If more than one method or variable is found with the same name, shows a table with the results and let the user decide where to go.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): editorWidget.go_to_definition() def editor_redo(self): """Execute the redo action in the current editor.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): editorWidget.redo() def editor_undo(self): editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): editorWidget.undo() def editor_indent_less(self): """Indent 1 position to the left for the current line or selection.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): editorWidget.indent_less() def editor_indent_more(self): """Indent 1 position to the right for the current line or selection.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): editorWidget.indent_more() def editor_insert_debugging_prints(self): """Insert a print statement in each selected line.""" editorWidget = self.get_current_editor() if editorWidget: helpers.insert_debugging_prints(editorWidget) def editor_insert_pdb(self): """Insert a pdb.set_trace() statement in tjhe current line.""" editorWidget = self.get_current_editor() if editorWidget: helpers.insert_pdb(editorWidget) def editor_comment(self): """Mark the current line or selection as a comment.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): helpers.comment(editorWidget) def editor_uncomment(self): """Uncomment the current line or selection.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): helpers.uncomment(editorWidget) def editor_insert_horizontal_line(self): """Insert an horizontal lines of comment symbols.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): helpers.insert_horizontal_line(editorWidget) def editor_insert_title_comment(self): """Insert a Title surrounded by comment symbols.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): helpers.insert_title_comment(editorWidget) def editor_remove_trailing_spaces(self): """Remove the trailing spaces in the current editor.""" editorWidget = self.get_current_editor() if editorWidget: helpers.remove_trailing_spaces(editorWidget) def editor_replace_tabs_with_spaces(self): """Replace the Tabs with Spaces in the current editor.""" editorWidget = self.get_current_editor() if editorWidget: helpers.replace_tabs_with_spaces(editorWidget) def editor_move_up(self): """Move the current line or selection one position up.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): helpers.move_up(editorWidget) def editor_move_down(self): """Move the current line or selection one position down.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): helpers.move_down(editorWidget) def editor_remove_line(self): """Remove the current line or selection.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): helpers.remove_line(editorWidget) def editor_duplicate(self): """Duplicate the current line or selection.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): helpers.duplicate(editorWidget) def editor_highlight_word(self): """Highlight the occurrences of the current word in the editor.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): editorWidget.highlight_selected_word() def editor_complete_declaration(self): """Do the opposite action that Complete Declaration expect.""" editorWidget = self.get_current_editor() if editorWidget and editorWidget.hasFocus(): editorWidget.complete_declaration() def editor_go_to_line(self, line, select=False):#def editor_go_to_line(self, line): """Jump to the specified line in the current editor.""" editorWidget = self.get_current_editor() print("\nluego en segundo lugar por aca") if editorWidget: editorWidget.jump_to_line(line)#select def editor_go_to_symbol_line(self, line, sym= "", select=False): """Jump to the specified line in the current editor.""" editorWidget = self.get_current_editor() print("\nluego en segundo lugar por aca") if editorWidget: editorWidget.go_to_symbol(line, sym, select)#select def zoom_in_editor(self): """Increase the font size in the current editor.""" editorWidget = self.get_current_editor() if editorWidget: editorWidget.zoom_in() def zoom_out_editor(self): """Decrease the font size in the current editor.""" editorWidget = self.get_current_editor() if editorWidget: editorWidget.zoom_out() def recent_files_changed(self): self.recentTabsModified.emit() def dragEnterEvent(self, event): if event.mimeData().hasUrls(): event.accept() else: event.ignore() def dropEvent(self, event): # file_path = event.mimeData().urls()[0].toLocalFile() # paths = [item.toLocalFile() for item in event.mimeData().urls()] self.open_files_fromUrlList(event.mimeData().urls()) # print("\n\n dropEvent", paths) # self.open_file(file_path) def setFocus(self): widget = self.get_current_widget() if widget: widget.setFocus() def current_editor_changed(self, filename): """Notify the new filename of the current editor.""" if filename is None: filename = translations.TR_NEW_DOCUMENT self.currentEditorChanged.emit(filename) def show_split(self, orientation_vertical=False): #IDE.select_current(self.current_widget.currentWidget()) self.current_widget.split_editor(orientation_vertical) def add_editor(self, fileName=None, ignore_checkers=False): print("filename::", fileName) ninjaide = IDE.getInstance() editable = ninjaide.get_or_create_editable(fileName) if editable.editor: self.current_widget.set_current(editable) print("\n\nreturn") return self.current_widget.currentWidget() else: editable.ignore_checkers = ignore_checkers editorWidget = self.create_editor_from_editable(editable) #add the tab keep_index = (self.splitter.count() > 1 and self.combo_area.stacked.count() > 0) self.combo_area.add_editor(editable, keep_index) #emit a signal about the file open self.fileOpened.emit(fileName) if keep_index: self.current_widget.set_current(editable) self.stack.setCurrentWidget(self.splitter) return editorWidget def create_editor_from_editable(self, editable): editorWidget = editor.create_editor(editable) #Connect signals editable.fileSaved.connect(self._editor_tab_was_saved) editorWidget.openDropFile.connect(self.open_file) editorWidget.addBackItemNavigation.connect(self.add_back_item_navigation) editorWidget.locateFunction.connect(self._editor_locate_function) editorWidget.findOcurrences.connect(self._find_occurrences) #keyPressEventSignal for plugins editorWidget.keyPressSignal.connect(self._editor_keyPressEvent) return editorWidget def reset_pep8_warnings(self, value): pass #FIXME: check how we handle this #for i in range(self._tabMain.count()): #widget = self._tabMain.widget(i) #if type(widget) is editor.Editor: #if value: #widget.syncDocErrorsSignal = True #widget.pep8.check_style() #else: #widget.hide_pep8_errors() def reset_lint_warnings(self, value): pass #FIXME: check how we handle this #for i in range(self._tabMain.count()): #widget = self._tabMain.widget(i) #if type(widget) is editor.Editor: #if value: #widget.syncDocErrorsSignal = True #widget.errors.check_errors() #else: #widget.hide_lint_errors() def _find_occurrences(self, word): self.findOcurrences.emit(word) def _editor_keyPressEvent(self, event): self.editorKeyPressEvent.emit(event) def _editor_locate_function(self, function, filePath, isVariable): self.locateFunction.emit(function, filePath, isVariable) def _editor_tab_was_saved(self, editable=None): self.updateLocator.emit(editable.file_path) def get_current_widget(self): return self.current_widget.currentWidget() def get_current_editor(self): """Return the Actual Editor or None Return an instance of Editor if the Current Tab contains an Editor or None if it is not an instance of Editor""" widget = self.current_widget.currentWidget() if isinstance(widget, editor.Editor): return widget return None def reload_file(self, editorWidget=None): if editorWidget is None: editorWidget = self.get_current_editor() if editorWidget is not None: editorWidget.neditable.reload_file() def add_tab(self, widget, tabName, tabIndex=None): pass #return self.tabs.add_tab(widget, tabName, index=tabIndex) def open_image(self, fileName): try: if not self.is_open(fileName): viewer = image_viewer.ImageViewer(fileName) self.add_tab(viewer, file_manager.get_basename(fileName)) viewer.ID = fileName else: self.move_to_open(fileName) except Exception as reason: logger.error('open_image: %s', reason) QMessageBox.information(self, self.tr("Incorrect File"), self.tr("The image couldn\'t be open")) def open_files_fromList(self, lst): for f in lst: self.open_file(f) def open_files_fromUrlList(self, lst): for f in lst: self.open_file(f.toLocalFile()) def open_file(self, filename='', line=-1, col=0, ignore_checkers=False): logger.debug("will try to open %s" % filename) if not filename: logger.debug("has nofilename") if settings.WORKSPACE: directory = settings.WORKSPACE else: directory = os.path.expanduser("~") editorWidget = self.get_current_editor() ninjaide = IDE.getInstance() if ninjaide: current_project = ninjaide.get_current_project() if current_project is not None: directory = current_project elif editorWidget is not None and editorWidget.file_path: directory = file_manager.get_folder( editorWidget.file_path) extensions = ';;'.join( ['{}(*{})'.format(e.upper()[1:], e) for e in settings.SUPPORTED_EXTENSIONS + ['.*', '']]) fileNames = QFileDialog.getOpenFileNames(self, self.tr("Open File"), directory, extensions)[0]#list() else: logger.debug("has filename") fileNames = [filename] if not fileNames: return print("\n\nopen_file") othersFileNames = [] image_extensions = ('bmp', 'gif', 'jpeg', 'jpg', 'png') for filename in fileNames: print("nombre", filename) if QFileInfo(filename).isDir(): othersFileNames.extend( QFileDialog.getOpenFileNames(None, "Select files", filename, "Files (*.*)")[0] ) elif file_manager.get_file_extension(filename) in image_extensions: logger.debug("will open as image") self.open_image(filename) elif file_manager.get_file_extension(filename).endswith('ui'): logger.debug("will load in ui editor") self.w = uic.loadUi(filename) self.w.show() else: logger.debug("will try to open: " + filename) self.__open_file(filename, line, col, ignore_checkers) for filename in othersFileNames: print("nombre", filename) if QFileInfo(filename).isDir(): continue elif file_manager.get_file_extension(filename) in image_extensions: logger.debug("will open as image") self.open_image(filename) elif file_manager.get_file_extension(filename).endswith('ui'): logger.debug("will load in ui editor") self.w = uic.loadUi(filename) self.w.show() else: logger.debug("will try to open: " + filename) self.__open_file(filename, line, col, ignore_checkers) def __open_file(self, fileName='', line=-1, col=0, ignore_checkers=False): print("unio", fileName) try: editorWidget = self.add_editor(fileName, ignore_checkers=ignore_checkers) if line != -1: editorWidget.set_cursor_position(line, col) self.currentEditorChanged.emit(fileName) except file_manager.NinjaIOException as reason: QMessageBox.information(self, self.tr("The file couldn't be open"), str(reason)) def is_open(self, filename): pass #return self.tabs.is_open(filename) != -1 def move_to_open(self, filename): pass #FIXME: add in the current split? #if self.tabs.is_open(filename) != -1: #self.tabs.move_to_open(filename) #self.tabs.currentWidget().setFocus() #self.emit(SIGNAL("currentEditorChanged(QString)"), filename) def get_widget_for_id(self, filename): pass #widget = None #index = self.tabs.is_open(filename) #if index != -1: #widget = self.tabs.widget(index) #return widget def change_open_tab_id(self, idname, newId): """Search for the Tab with idname, and set the newId to that Tab.""" pass #index = self.tabs.is_open(idname) #if index != -1: #widget = self.tabs.widget(index) #tabName = file_manager.get_basename(newId) #self.tabs.change_open_tab_name(index, tabName) #widget.ID = newId def close_deleted_file(self, idname): """Search for the Tab with id, and ask the user if should be closed.""" pass #index = self.tabs.is_open(idname) #if index != -1: #result = QMessageBox.question(self, self.tr("Close Deleted File"), #self.tr("Are you sure you want to close the deleted file?\n" #"The content will be completely deleted."), #buttons=QMessageBox.Yes | QMessageBox.No) #if result == QMessageBox.Yes: #self.tabs.removeTab(index) def save_file(self, editorWidget=None): #FIXME: check how we handle this if not editorWidget: editorWidget = self.get_current_editor() if not editorWidget: return False try: #editorWidget.just_saved = True if (editorWidget.nfile.is_new_file or not editorWidget.nfile.has_write_permission()): return self.save_file_as() self.beforeFileSaved.emit(editorWidget.file_path) if settings.REMOVE_TRAILING_SPACES: helpers.remove_trailing_spaces(editorWidget) editorWidget.neditable.save_content() #file_manager.store_file_content( #fileName, content, addExtension=False) encoding = file_manager.get_file_encoding(editorWidget.text()) editorWidget.encoding = encoding self.fileSaved.emit((self.tr("File Saved: %s") % editorWidget.file_path)) return True except Exception as reason: logger.error('save_file: %s', reason) QMessageBox.information(self, self.tr("Save Error"), self.tr("The file couldn't be saved!")) return False def save_file_as(self): editorWidget = self.get_current_editor() if not editorWidget: return False try: filters = '(*.py);;(*.*)' if editorWidget.file_path: ext = file_manager.get_file_extension(editorWidget.file_path) if ext != 'py': filters = '(*.%s);;(*.py);;(*.*)' % ext save_folder = self._get_save_folder(editorWidget.file_path) fileName = QFileDialog.getSaveFileName( self._parent, self.tr("Save File"), save_folder, filters) if not fileName: return False if settings.REMOVE_TRAILING_SPACES: helpers.remove_trailing_spaces(editorWidget) editorWidget.neditable.save_content(path=fileName) editorWidget.register_syntax( file_manager.get_file_extension(fileName)) self.fileSaved.emit((self.tr("File Saved: %s") % fileName)) self.currentEditorChanged.emit(fileName) return True except file_manager.NinjaFileExistsException as ex: QMessageBox.information(self, self.tr("File Already Exists"), (self.tr("Invalid Path: the file '%s' " " already exists.") % ex.filename)) except Exception as reason: logger.error('save_file_as: %s', reason) QMessageBox.information(self, self.tr("Save Error"), self.tr("The file couldn't be saved!")) return False def _get_save_folder(self, fileName): """ Returns the root directory of the 'Main Project' or the home folder """ ninjaide = IDE.getInstance() current_project = ninjaide.get_current_project() if current_project: return current_project.path return os.path.expanduser("~") def save_project(self, projectFolder): pass #FIXME: check how we handle this #for i in range(self._tabMain.count()): #editorWidget = self._tabMain.widget(i) #if type(editorWidget) is editor.Editor and \ #file_manager.belongs_to_folder(projectFolder, #editorWidget.file_path): #reloaded = self._tabMain.check_for_external_modifications( #editorWidget) #if not reloaded: #self.save_file(editorWidget) #for i in range(self.tabsecondary.count()): #editorWidget = self.tabsecondary.widget(i) #if type(editorWidget) is editor.Editor and \ #file_manager.belongs_to_folder(projectFolder, #editorWidget.file_path): #reloaded = self.tabsecondary.check_for_external_modifications( #editorWidget) #if not reloaded: #self.save_file(editorWidget) def save_all(self): pass #FIXME: check how we handle this #for i in range(self._tabMain.count()): #editorWidget = self._tabMain.widget(i) #if type(editorWidget) is editor.Editor: #reloaded = self._tabMain.check_for_external_modifications( #editorWidget) #if not reloaded: #self.save_file(editorWidget) #for i in range(self.tabsecondary.count()): #editorWidget = self.tabsecondary.widget(i) #self.tabsecondary.check_for_external_modifications(editorWidget) #if type(editorWidget) is editor.Editor: #reloaded = self.tabsecondary.check_for_external_modifications( #editorWidget) #if not reloaded: #self.save_file(editorWidget) def call_editors_function(self, call_function, *arguments): pass #args = arguments[0] #kwargs = arguments[1] #for i in range(self.tabs.count()): #editorWidget = self.tabs.widget(i) #if isinstance(editorWidget, editor.Editor): #function = getattr(editorWidget, call_function) #function(*args, **kwargs) #TODO: add other splits def show_start_page(self): start = self.stack.widget(0) if isinstance(start, start_page.StartPage): self.stack.setCurrentIndex(0) else: startPage = start_page.StartPage(parent=self) startPage.openProject.connect(self.open_project) startPage.openPreferences.connect(self.openPreferences.emit) startPage.newFile.connect(self.add_editor) startPage.openFiles.connect(self.open_files_fromList) self.stack.insertWidget(0, startPage) self.stack.setCurrentIndex(0) self.tryMakeImagePreview(0) #"screen0.png" def show_python_doc(self): if sys.platform == 'win32': self.docPage = browser_widget.BrowserWidget( 'http://docs.python.org/') else: process = runner.start_pydoc() self.docPage = browser_widget.BrowserWidget(process[1], process[0]) self.add_tab(self.docPage, translations.TR_PYTHON_DOC) def show_report_bugs(self): webbrowser.open(resources.BUGS_PAGE) def show_plugins_doc(self): bugsPage = browser_widget.BrowserWidget(resources.PLUGINS_DOC, self) self.add_tab(bugsPage, translations.TR_HOW_TO_WRITE_PLUGINS) def editor_jump_to_line(self, lineno=None): """Jump to line *lineno* if it is not None otherwise ask to the user the line number to jump """ editorWidget = self.get_current_editor() if editorWidget: editorWidget.jump_to_line(lineno=lineno) def get_opened_documents(self): #return self.tabs.get_documents_data() return [] def check_for_unsaved_files(self): pass #return self.tabs._check_unsaved_tabs() def get_unsaved_files(self): pass #return self.tabs.get_unsaved_files() def reset_editor_flags(self): pass #for i in range(self.tabs.count()): #widget = self.tabs.widget(i) #if isinstance(widget, editor.Editor): #widget.set_flags() def _specify_syntax(self, widget, syntaxLang): if isinstance(widget, editor.Editor): widget.restyle(syntaxLang) def apply_editor_theme(self, family, size): pass #for i in range(self.tabs.count()): #widget = self.tabs.widget(i) #if isinstance(widget, editor.Editor): #widget.restyle() #widget.set_font(family, size) def update_editor_margin_line(self): pass #for i in range(self.tabs.count()): #widget = self.tabs.widget(i) #if isinstance(widget, editor.Editor): #widget._update_margin_line() def open_project(self, path): print("open_project") self.openProject.emit(path) def close_python_doc(self): pass #close the python document server (if running) #if self.docPage: #index = self.tabs.indexOf(self.docPage) #self.tabs.removeTab(index) ##assign None to the browser #self.docPage = None def close_file(self): """Close the current tab in the current TabWidget.""" self.current_widget.close_current_file() def create_file(self, base_path, project_path): self._add_file_folder.create_file(base_path, project_path) def create_folder(self, base_path, project_path): self._add_file_folder.create_folder(base_path, project_path) def change_tab(self): """Change the tab in the current TabWidget.""" print("\nchange_tab") self.stack.setCurrentWidget(self.splitter) # self._files_handler.next_item() pass def change_tab_reverse(self): """Change the tab in the current TabWidget backwards.""" print("\nchange_tab_reverse") self.stack.setCurrentWidget(self.splitter) # self._files_handler.previous_item() def toggle_tabs_and_spaces(self): """ Toggle Show/Hide Tabs and Spaces """ settings.SHOW_TABS_AND_SPACES = not settings.SHOW_TABS_AND_SPACES qsettings = IDE.ninja_settings() qsettings.setValue('preferences/editor/showTabsAndSpaces', settings.SHOW_TABS_AND_SPACES) def show_navigation_buttons(self): """Show Navigation menu.""" self.stack.setCurrentWidget(self.splitter) self.combo_area.show_menu_navigation() def change_split_focus(self): pass #FIXME: check how we handle this #if self.actualTab == self._tabMain and self.tabsecondary.isVisible(): #self.actualTab = self.tabsecondary #else: #self.actualTab = self._tabMain #widget = self.actualTab.currentWidget() #if widget is not None: #widget.setFocus() def shortcut_index(self, index): pass #self.tabs.setCurrentIndex(index) def print_file(self): """Call the print of ui_tool Call print of ui_tool depending on the focus of the application""" #TODO: Add funtionality for proyect tab and methods tab editorWidget = self.get_current_editor() if editorWidget is not None: fileName = "newDocument.pdf" if editorWidget.file_path: fileName = file_manager.get_basename( editorWidget.file_path) fileName = fileName[:fileName.rfind('.')] + '.pdf' ui_tools.print_file(fileName, editorWidget.print_) def split_assistance(self): dialog = split_orientation.SplitOrientation(self) dialog.show() def close_split(self): if self.current_widget != self.combo_area: self.current_widget.bar.close_split() def split_vertically(self): self.show_split(False) def split_horizontally(self): self.show_split(True) def navigate_back(self): self.__navigate_with_keyboard(False) def navigate_forward(self): self.__navigate_with_keyboard(True)
class ComboEditor(QDialog): closeSplit = pyqtSignal(QWidget) aboutToCloseComboEditor = pyqtSignal() allFilesClosed = pyqtSignal() splitEditor = pyqtSignal("QWidget*", "QWidget*", bool) recentTabsModified = pyqtSignal() class NAVIGATE: prev = 0 next = 1 Q_ENUMS(NAVIGATE) def __init__(self, original=False, Force_Free=False): super(ComboEditor, self).__init__(None) #, Qt.WindowStaysOnTopHint) self.__original = original self.Force_Free = Force_Free self.__undocked = [] self._single_undocked = [] self._symbols_index = [] self.__OFiles = [] vbox = QVBoxLayout(self) vbox.setContentsMargins(0, 0, 0, 0) vbox.setSpacing(0) self.bar = ActionBar(self, main_combo=original) vbox.addWidget(self.bar) self.stackedEditor = QStackedLayout() vbox.addLayout(self.stackedEditor) self._main_container = IDE.get_service('main_container') if not self.__original and not self.Force_Free: self._main_container.fileOpened.connect(self._file_opened_by_main) # QApplication.instance().focusChanged["QWidget*", "QWidget*"].connect(\ # lambda w1, w2: QTimer.singleShot(10, lambda w1=w1, w2=w2: print("\n\nQApplication::focusChanged::", w1, w2))) self.bar.combo.showComboSelector.connect( self._main_container.change_tab) self.bar.changeCurrent.connect(self._set_current) self.bar.editorSplited.connect(self.split_editor) self.bar.runFile[str].connect(self._run_file) self.bar.closeFile.connect(lambda: self.closeSplit.emit(self)) self.bar.addToProject[str].connect(self._add_to_project) self.bar.showFileInExplorer.connect(self._show_file_in_explorer) self.bar.goToSymbol.connect(self._go_to_symbol) self.bar.undockEditor.connect(self.undock_editor) self.bar.undockThisEditor.connect(self.single_undock_editor) self.bar.reopenTab[str].connect(self._main_container.open_file) self.bar.recentTabsModified.connect( self._main_container.recent_files_changed) self.bar.code_navigator.btnPrevious.clicked['bool'].connect( lambda: self._navigate_code(self.NAVIGATE.prev)) self.bar.code_navigator.btnNext.clicked['bool'].connect( lambda: self._navigate_code(self.NAVIGATE.prev)) # QTimer.singleShot(39999, lambda : print("\n\ncombo:-:", self)) # def closeEvent(self, event): # for comboeditor in self._single_undocked: # print("has undocked", comboeditor) # comboeditor.reject() # comboeditor.deleteLater() # self.bar._close_all_files() # super(ComboEditor, self).closeEvent(event) def _navigate_code(self, val): op = self.bar.code_navigator.operation self._main_container.navigate_code_history(val, op) def setFocus(self): super(ComboEditor, self).setFocus() w = self.stackedEditor.currentWidget() if w: w.setFocus() self._editor_with_focus() def _file_opened_by_main(self, path): index = self.stackedEditor.currentIndex() ninjaide = IDE.getInstance() editable = ninjaide.get_or_create_editable(path) print("_file_opened_by_main", editable) self.add_editor(editable) self.bar.set_current_by_index(index) if index == -1: self.bar.set_current_by_index(0) def add_editor(self, neditable, keep_index=False): """Add Editor Widget to the UI area.""" if neditable.editor: if self.__original or self.Force_Free: editor = neditable.editor print("\n\nadd_editor() ignora por ahora!", editor) # disconnect old Signals try: editor.cursorPositionChanged[int, int].disconnect() except TypeError: pass try: editor.editorFocusObtained.disconnect() except TypeError: pass try: editor.currentLineChanged.disconnect() except TypeError: pass try: editor.modificationChanged['bool'].disconnect() except TypeError: pass try: neditable.checkersUpdated.disconnect() except TypeError: pass try: neditable.fileSaved.disconnect() except TypeError: pass # Disonnect file system signals only in the original try: neditable.fileClosing.disconnect() except TypeError: pass if self.__original: try: neditable.askForSaveFileClosing.disconnect() except TypeError: pass try: neditable.fileChanged.disconnect() except TypeError: pass else: editor = self._main_container.create_text_editor_from_editable( neditable) index = self.stackedEditor.currentIndex() self.stackedEditor.addWidget(editor) self.bar.add_item(neditable.display_name, neditable) if keep_index: self.bar.set_current_by_index(index) # Editor Signals editor.cursorPositionChanged[int, int].connect( self._update_cursor_position) editor.editorFocusObtained.connect(self._editor_with_focus) editor.currentLineChanged.connect(self._set_current_symbol) editor.modificationChanged['bool'].connect(self._editor_modified) neditable.checkersUpdated.connect(self._show_notification_icon) neditable.fileSaved.connect(self._update_symbols) neditable.fileSaved.connect(self._update_combo_info) # Connect file system signals only in the original neditable.fileClosing.connect(self._close_file) if self.__original: neditable.askForSaveFileClosing.connect(self._ask_for_save) neditable.fileChanged.connect(self._file_has_been_modified) # Load Symbols self._load_symbols(neditable) def show_combo_file(self): print("show_combo_file") self.bar.combo.showPopup() def show_combo_symbol(self): self.bar.symbols_combo.showPopup() def getOpenedFiles(self): return self.__OFiles.copy() def addOpenedFiles(self, fil): self.__OFiles.append(fil) def unlink_editors(self): for index in range(self.stackedEditor.count()): widget = self.stackedEditor.widget(index) widget.setDocument(QsciDocument()) def split_editor(self, orientationVertical): new_widget = ComboEditor() for neditable in self.bar.get_editables(): print("\nsplit_editor", neditable, new_widget) new_widget.add_editor(neditable) self.splitEditor.emit(self, new_widget, orientationVertical) def undock_editor(self): new_combo = ComboEditor() new_combo.setWindowTitle("NINJA-IDE") self.add_Undocked(new_combo) for neditable in self.bar.get_editables(): print("undock_editor", neditable) new_combo.add_editor(neditable) new_combo.resize(500, 500) new_combo.aboutToCloseComboEditor.connect(self._remove_undock) new_combo.show() def _remove_undock(self): print("_remove_undock", self.sender()) widget = self.sender() self.sub_Undocked(widget) def add_Undocked(self, combedit): self.__undocked.append(combedit) def sub_Undocked(self, combedit): self.__undocked.remove(combedit) def add_SingleUndocked(self, combedit): self._single_undocked.append(combedit) def sub_SingleUndocked(self, combedit): self._single_undocked.remove(combedit) # aún no se ha puesto en funcionamiento!. def single_split_editor(self, orientationVertical): new_widget = ComboEditor() for neditable in self.bar.get_editables(): print("\nsingle_split_editor", neditable, new_widget) new_widget.add_editor(neditable) self.splitEditor.emit(self, new_widget, orientationVertical) def single_undock_editor(self): new_combo = ComboEditor(Force_Free=True) new_combo.setWindowTitle("NINJA-IDE") self.add_SingleUndocked(new_combo) nEdit = self.stackedEditor.takeAt( self.stackedEditor.currentIndex()).widget() ide = IDE.getInstance() ide.unload_NEditable(nEdit) neditable = self.bar.take_editable() print("\n\nsingle_undock_editor:::", neditable, neditable.editor, nEdit, neditable.nfile) if self.stackedEditor.isEmpty(): self.allFilesClosed.emit() new_combo.add_editor(neditable) new_combo.stackedEditor.setCurrentIndex( 0) # new_combo.stackedEditor.setCurrentWidget(nEdit) new_combo.resize(500, 500) new_combo.aboutToCloseComboEditor.connect(self.single__remove_undock) new_combo.show() def single__remove_undock(self): print("single__remove_undock", self.sender()) widget = self.sender() self.sub_SingleUndocked(widget) ##widget.deleteLater() def bind_Editable(self, editable): self.bar.add_item(neditable.display_name, editable) def close_current_file(self): self.bar.about_to_close_file() def _close_file(self, neditable): print("\n\n_close_file", self.__original, self.Force_Free) index = self.bar.close_file(neditable) layoutItem = self.stackedEditor.takeAt(index) #neditable.editor.completer.cc.unload_module() self._add_to_last_opened(neditable.file_path) layoutItem.widget().deleteLater( ) # @@4 -> Comentando ésta linea desaparece el mensaje if self.stackedEditor.isEmpty(): self.allFilesClosed.emit() def _add_to_last_opened(self, path): if path not in settings.LAST_OPENED_FILES: settings.LAST_OPENED_FILES.append(path) if len(settings.LAST_OPENED_FILES) > settings.MAX_REMEMBER_TABS: self.__lastOpened = self.__lastOpened[1:] self.recentTabsModified.emit() def _editor_with_focus(self): if self._main_container.current_comboEditor is not self: self._main_container.current_comboEditor = self editor = self.stackedEditor.currentWidget() self._main_container.current_editor_changed( editor.neditable.file_path) self._load_symbols(editor.neditable) editor.neditable.update_checkers_display() def _ask_for_save(self, neditable): val = QMessageBox.No fileName = neditable.nfile.file_name val = QMessageBox.question( self, (self.tr('The file %s was not saved') % fileName), self.tr("Do you want to save before closing?"), QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel) if val == QMessageBox.No: neditable.nfile.close(force_close=True) elif val == QMessageBox.Yes: neditable.ignore_checkers = True self._main_container.save_file(neditable.editor) neditable.nfile.close() def _file_has_been_modified(self, neditable): val = QMessageBox.No fileName = neditable.file_path val = QMessageBox.question( self, translations.TR_FILE_HAS_BEEN_MODIFIED, "%s%s" % (fileName, translations.TR_FILE_MODIFIED_OUTSIDE), QMessageBox.Yes | QMessageBox.No) if val == QMessageBox.Yes: neditable.reload_file() def _run_file(self, path): self._main_container.run_file(path) def _add_to_project(self, path): self._main_container._add_to_project(path) def _show_file_in_explorer(self, path): '''Connected to ActionBar's showFileInExplorer(QString) signal, forwards the file path on to the main container.''' self._main_container._show_file_in_explorer(path) def set_current(self, neditable): if neditable: self.bar.set_current_file(neditable) def _set_current(self, neditable, index): if neditable: self.stackedEditor.setCurrentIndex(index) editor = self.stackedEditor.currentWidget() self._update_cursor_position(ignore_sender=True) editor.setFocus() self._main_container.current_editor_changed(neditable.file_path) self._load_symbols(neditable) self._show_file_in_explorer(neditable.file_path) neditable.update_checkers_display() def widget(self, index): return self.stackedEditor.widget(index) def countEditors(self): """Return the number of editors opened.""" return self.stackedEditor.count() def currentEditor(self): """ rtn -> Editor()# local QsciScintilla""" return self.stackedEditor.currentWidget() def _update_cursor_position(self, line=0, col=0, ignore_sender=False): obj = self.sender() editor = self.stackedEditor.currentWidget() # Check if it's current to avoid signals from other splits. if ignore_sender or editor == obj: line += 1 self.bar.update_line_col(line, col) def _set_current_symbol(self, line, ignore_sender=False): obj = self.sender() editor = self.stackedEditor.currentWidget() # Check if it's current to avoid signals from other splits. if ignore_sender or editor == obj: index = bisect.bisect(self._symbols_index, line) if (index >= len(self._symbols_index) or self._symbols_index[index] > (line + 1)): index -= 1 self.bar.set_current_symbol(index) def _editor_modified(self, value): obj = self.sender() neditable = obj.neditable if value: text = "\u2022 %s" % neditable.display_name self.bar.update_item_text(neditable, text) else: self.bar.update_item_text(neditable, neditable.display_name) def _go_to_symbol(self, index): print("_go_to_symbol in index:", index) line = self._symbols_index[index] editor = self.stackedEditor.currentWidget() editor.go_to_line(line) def _update_symbols(self, neditable): editor = self.stackedEditor.currentWidget() # Check if it's current to avoid signals from other splits. if editor == neditable.editor: self._load_symbols(neditable) def _update_combo_info(self, neditable): self.bar.update_item_text(neditable, neditable.display_name) self._main_container.current_editor_changed(neditable.file_path) def _load_symbols(self, neditable): symbols_handler = handlers.get_symbols_handler('py') source = neditable.editor.text() source = source.encode(neditable.editor.encoding) symbols, symbols_simplified = symbols_handler.obtain_symbols( source, simple=True) self._symbols_index = sorted(symbols_simplified.keys()) symbols_simplified = sorted(list(symbols_simplified.items()), key=lambda x: x[0]) self.bar.add_symbols(symbols_simplified) line, _ = neditable.editor.getCursorPosition() self._set_current_symbol(line, True) tree_symbols = IDE.get_service('symbols_explorer') tree_symbols.update_symbols_tree(symbols, neditable.file_path) def _show_notification_icon(self, neditable): checkers = neditable.sorted_checkers icon = QIcon() for items in checkers: checker, color, _ = items if checker.checks: if isinstance(checker.checker_icon, int): icon = self.style().standardIcon(checker.checker_icon) elif isinstance(checker.checker_icon, str): icon = QIcon(checker.checker_icon) break self.bar.update_item_icon(neditable, icon) def show_menu_navigation(self): self.bar.code_navigator.show_menu_navigation() def closeEvent(self, event): for comboeditor in self._single_undocked: print("has undocked", comboeditor) comboeditor.reject() comboeditor.deleteLater() # print("\n\ncloseEvent", self) if self.__original: self.bar._close_all_files() self.aboutToCloseComboEditor.emit() super(ComboEditor, self).closeEvent(event) def reject(self): if not self.__original: super(ComboEditor, self).reject()
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() # Call the inherited classes __init__ method self.core = Core.Core.get_core() def loadGui(self): ui_file = self.core.rsrc_dir + "mainWindow.ui" uic.loadUi(ui_file, self) # Load the .ui file self.optionsBox = self.findChild(QHBoxLayout, 'optionsBox') self.installersButton = self.findChild(QPushButton, 'installersButton') icn = QIcon.fromTheme( os.path.join(settings.ICONS_THEME, "view-list-details.svg")) self.installersButton.setIcon(icn) self.installersButton.setText(_("Installers")) self.installersButton.clicked.connect(lambda: self.changePanel("I")) self.configurationButton = self.findChild(QPushButton, "configurationButton") icn = QIcon.fromTheme( os.path.join(settings.ICONS_THEME, "configure.svg")) self.configurationButton.setIcon(icn) #self.configurationButton.setIconSize(QSize(16,16)) self.configurationButton.setText(_("Configuration Options")) self.configurationButton.clicked.connect(lambda: self.changePanel("C")) self.mainBox = self.findChild(QVBoxLayout, 'mainBox') self.bannerBox = self.findChild(QLabel, 'bannerLabel') self.bannerBox.setStyleSheet("background-color: #7f0907") self.messageBox = self.findChild(QVBoxLayout, 'messageBox') self.messageImg = self.findChild(QLabel, 'messageImg') self.messageLabel = self.findChild(QLabel, 'messageLabel') self.progressBar = self.findChild(QProgressBar, 'progressBar') self.controlsBox = self.findChild(QVBoxLayout, 'controlsBox') self.applyButton = self.findChild(QPushButton, 'applyButton') icn = QIcon.fromTheme(os.path.join(settings.ICONS_THEME, "gtk-ok.svg")) self.applyButton.setIcon(icn) self.applyButton.setText(_("Install")) self.applyButton.clicked.connect(self.applyButtonClicked) self.helpButton = self.findChild(QPushButton, 'helpButton') icn = QIcon.fromTheme( os.path.join(settings.ICONS_THEME, "help-whatsthis.svg")) self.helpButton.setIcon(icn) self.helpButton.setText(_("Help")) self.helpButton.clicked.connect(self.helpButtonClicked) self.loadingBox = self.core.loadingBox self.installersBox = self.core.installersBox self.configurationBox = self.core.configurationBox self.QtStack = QStackedLayout() self.QtStack.addWidget(self.loadingBox) self.QtStack.addWidget(self.installersBox) self.QtStack.addWidget(self.configurationBox) self.mainBox.addLayout(self.QtStack) self.gatherInfo = gatherInfo() self.installersButton.hide() self.configurationButton.hide() #self.messageLabel.hide() self._manageMsgBox(True, False) self.applyButton.hide() self.helpButton.hide() qtRectangle = self.frameGeometry() centerPoint = QDesktopWidget().availableGeometry().center() qtRectangle.moveCenter(centerPoint) self.move(qtRectangle.topLeft()) centerPoint = QDesktopWidget().availableGeometry().center() qtRectangle.moveCenter(centerPoint) self.move(qtRectangle.topLeft()) self.exitLocked = True self.gatherInfo.start() self.gatherInfo.finished.connect(self._finishProcess) #def loadGui def _finishProcess(self): self.loadingBox.spinner.stop() if len(self.core.javaPanelManager.java_list) > 0: self.installersBox.drawInstallerList() self.fader_widget = FaderWidget(self.QtStack.currentWidget(), self.QtStack.widget(1)) self.QtStack.setCurrentIndex(1) self.configurationButton.show() self._manageMsgBox(True, False) #self.messageLabel.show() self.applyButton.show() self.helpButton.show() else: #self.messageLabel.show() self._manageMsgBox(False, True) self.loadingBox.spinner.hide() self.messageLabel.setText( _("No Java version(s) availables detected")) self.exitLocked = False #def _finishProcess def applyButtonClicked(self): self.othersBox = [] self.javasToInstall = self.installersBox.javas_selected self.boxSelected = self.installersBox.box_selected #self.installersBox.scrollArea.setEnabled(False) self._manageMsgBox(True, False) self.messageLabel.setText("") if len(self.javasToInstall) > 0: self.applyButton.setEnabled(False) self.configurationButton.setEnabled(False) self.helpButton.setEnabled(False) #self.messageLabel.setText(_("Installing selected Java version(s). Wait a moment...")) for item in self.boxSelected: item.itemAt(0).widget().setEnabled(False) item.itemAt(3).widget().hide() item.itemAt(4).widget().show() item.itemAt(4).widget().start() for item in self.installersBox.boxInstallers.children(): if item.itemAt(0).widget().isEnabled(): item.itemAt(0).widget().setEnabled(False) self.othersBox.append(item) self.exitLocked = True ''' self.install=installProcess(self.javasToInstall) self.install.start() self.install.finished.connect(self._finishInstall) ''' self.getPackages = getPackages(self.javasToInstall) self._manageMsgBox(True, False) self.messageLabel.setText( _("1 of 5: Obtaining information about Java(s) to install...")) self.progressBar.show() self.getPackages.start() self.getPackages.finished.connect(self._finishGetPackages) else: self._manageMsgBox(False, True) self.messageLabel.setText( _("You must select a Java version to install")) #def applyButtonClicked def _finishGetPackages(self): self.messageLabel.setText(_("2 of 5: Downloading packages...")) self.progressBar.setValue(100) self.checkProgress = QThread() self.worker = Worker() self.worker.moveToThread(self.checkProgress) self.checkProgress.started.connect(self.worker.run) self.worker._finished.connect(self.checkProgress.quit) self.worker._progress.connect(self._updateMessage) self.install = installProcess(self.javasToInstall) self.install.start() self.install.finished.connect(self._finishInstall) self.worker.running = True self.checkProgress.start() #def _finishGetPackages def _updateMessage(self, step): if step == "unpack": self.messageLabel.setText( _("3 of 5: Unpacking packages: %s of %s packages") % (str(self.core.javaPanelManager.progressUnpacked), len(self.core.javaPanelManager.initialNumberPackages))) elif step == "install": self.messageLabel.setText( _("4 of 5: Configuring packages: %s of %s packages") % (str(self.core.javaPanelManager.progressInstallation), len(self.core.javaPanelManager.initialNumberPackages))) elif step == "end": self.messageLabel.setText( _("5 of 5: Finishing the installation...")) self._updateProgressBar(step) #def _updateMessage def _updateProgressBar(self, step): if step == "unpack": if self.core.javaPanelManager.progressUnpackedPercentage == 0.00: self.progressBar.setValue(200) else: p_value = 2 + float( self.core.javaPanelManager.progressUnpackedPercentage) self.progressBar.setValue(p_value * 100) elif step == "install": if self.core.javaPanelManager.progressInstallationPercentage == 0.00: self.progressBar.setValue(300) else: p_value = 3 + float( self.core.javaPanelManager.progressInstallationPercentage) self.progressBar.setValue(p_value * 100) elif step == "end": self.progressBar.setValue(400) #def _updateProgressBar def _finishInstall(self): self.progressBar.hide() self.worker.running = False result = self.core.javaPanelManager.result_install error = False for item in result: if result[item]: for element in self.boxSelected: if element.itemAt(4).widget().item == item: element.itemAt(4).widget().stop() element.itemAt(4).widget().hide() pixmap = QPixmap(self.core.rsrc_dir + "check.png") element.itemAt(3).widget().setPixmap(pixmap) element.itemAt(0).widget().setChecked(False) element.itemAt(3).widget().show() else: for element in self.boxSelected: if element.itemAt(4).widget().item == item: element.itemAt(4).widget().stop() element.itemAt(4).widget().hide() pixmap = QPixmap(self.core.rsrc_dir + "error.png") element.itemAt(3).widget().setPixmap(pixmap) element.itemAt(0).widget().setChecked(False) element.itemAt(0).widget().setEnabled(True) element.itemAt(3).widget().show() error = True self.applyButton.setEnabled(True) self.configurationButton.setEnabled(True) self.helpButton.setEnabled(True) for item in self.othersBox: item.itemAt(0).widget().setEnabled(True) if error: self._manageMsgBox(False, True) self.messageLabel.setText( _("Installing process has ending with errors")) else: self._manageMsgBox(False, False) self.messageLabel.setText( _("Installing process has ending successfully")) self.exitLocked = False #def _finishInstall def changePanel(self, panel): if panel == "C": self.configurationButton.hide() self.progressBar.hide() self._manageMsgBox(True, False) self.messageLabel.setText("") self.configurationBox.drawConfigurationList() self.fader_widget = FaderWidget(self.QtStack.currentWidget(), self.QtStack.widget(2)) self.QtStack.setCurrentIndex(2) self.installersButton.show() self.applyButton.setEnabled(False) elif panel == "I": self.installersButton.hide() self._manageMsgBox(True, False) self.messageLabel.setText("") self.fader_widget = FaderWidget(self.QtStack.currentWidget(), self.QtStack.widget(2)) self.QtStack.setCurrentIndex(1) self.configurationButton.show() self.applyButton.setEnabled(True) self.configurationBox.boxDelete() #def changePanel def helpButtonClicked(self): lang = os.environ["LANG"] language = os.environ["LANGUAGE"] run_pkexec = False if "PKEXEC_UID" in os.environ: run_pkexec = True exec_lang = "" app_lang = "" if language == "": app_lang = lang else: language = language.split(":")[0] app_lang = language if 'valencia' in app_lang: exec_lang = "LANG=ca_ES.UTF-8@valencia" cmd = exec_lang + ' xdg-open https://wiki.edu.gva.es/lliurex/tiki-index.php?page=LliureX+Java+Panel.' else: exec_lang = "LANG=es_ES.UTF-8" cmd = exec_lang + ' xdg-open https://wiki.edu.gva.es/lliurex/tiki-index.php?page=LliureX-Java-Panel' if not run_pkexec: self.fcmd = "su -c '%s &' $USER" % cmd else: user = pwd.getpwuid(int(os.environ["PKEXEC_UID"])).pw_name self.fcmd = "su -c '" + cmd + " &' " + user os.system(self.fcmd) #def helpButtonClicked def closeEvent(self, event): if self.exitLocked: event.ignore() else: event.accept() #def closeEvent def _manageMsgBox(self, hide, error): self.progressBar.hide() if hide: self.messageImg.setStyleSheet("background-color: transparent") self.messageLabel.setStyleSheet("background-color: transparent") self.messageImg.hide() self.messageLabel.setAlignment(Qt.AlignCenter | Qt.AlignVCenter) else: if error: self.messageImg.setStyleSheet( "border-bottom: 1px solid #da4453;border-left: 1px solid #da4453;border-top: 1px solid #da4453;background-color: #ebced2" ) self.messageLabel.setStyleSheet( "border-bottom: 1px solid #da4453;border-right: 1px solid #da4453;border-top: 1px solid #da4453;background-color: #ebced2" ) pixmap = QPixmap(self.core.rsrc_dir + "dialog-error.png") self.messageImg.setPixmap(pixmap) self.messageImg.show() self.messageLabel.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) self.messageLabel.show() else: self.messageImg.setStyleSheet( "border-bottom: 1px solid #27ae60;border-left: 1px solid #27ae60;border-top: 1px solid #27ae60;background-color: #c7e3d4" ) self.messageLabel.setStyleSheet( "border-bottom: 1px solid #27ae60;border-right: 1px solid #27ae60;border-top: 1px solid #27ae60;background-color: #c7e3d4" ) pixmap = QPixmap(self.core.rsrc_dir + "dialog-positive.png") self.messageImg.setPixmap(pixmap) self.messageImg.show() self.messageLabel.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) self.messageLabel.show()
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() # Call the inherited classes __init__ method self.core = Core.Core.get_core() def loadGui(self): ui_file = self.core.rsrc_dir + "mainWindow.ui" uic.loadUi(ui_file, self) # Load the .ui file self.optionsBox = self.findChild(QHBoxLayout, 'optionsBox') self.installersButton = self.findChild(QPushButton, 'installersButton') icn = QIcon.fromTheme( os.path.join(settings.ICONS_THEME, "view-list-details.svg")) self.installersButton.setIcon(icn) self.installersButton.setText(_("Installers")) self.installersButton.clicked.connect(lambda: self.changePanel("I")) self.configurationButton = self.findChild(QPushButton, "configurationButton") icn = QIcon.fromTheme( os.path.join(settings.ICONS_THEME, "configure.svg")) self.configurationButton.setIcon(icn) #self.configurationButton.setIconSize(QSize(16,16)) self.configurationButton.setText(_("Configuration Options")) self.configurationButton.clicked.connect(lambda: self.changePanel("C")) self.mainBox = self.findChild(QVBoxLayout, 'mainBox') self.bannerBox = self.findChild(QLabel, 'bannerLabel') self.bannerBox.setStyleSheet("background-color: #7f0907") self.messageBox = self.findChild(QVBoxLayout, 'messageBox') self.messageLabel = self.findChild(QLabel, 'messageLabel') self.controlsBox = self.findChild(QVBoxLayout, 'controlsBox') self.applyButton = self.findChild(QPushButton, 'applyButton') icn = QIcon.fromTheme(os.path.join(settings.ICONS_THEME, "gtk-ok.svg")) self.applyButton.setIcon(icn) self.applyButton.setText(_("Install")) self.applyButton.clicked.connect(self.applyButtonClicked) self.helpButton = self.findChild(QPushButton, 'helpButton') icn = QIcon.fromTheme( os.path.join(settings.ICONS_THEME, "help-whatsthis.svg")) self.helpButton.setIcon(icn) self.helpButton.setText(_("Help")) self.helpButton.clicked.connect(self.helpButtonClicked) self.loadingBox = self.core.loadingBox self.installersBox = self.core.installersBox self.configurationBox = self.core.configurationBox self.QtStack = QStackedLayout() self.QtStack.addWidget(self.loadingBox) self.QtStack.addWidget(self.installersBox) self.QtStack.addWidget(self.configurationBox) self.mainBox.addLayout(self.QtStack) self.gatherInfo = gatherInfo() self.installersButton.hide() self.configurationButton.hide() self.messageLabel.hide() self.applyButton.hide() qtRectangle = self.frameGeometry() centerPoint = QDesktopWidget().availableGeometry().center() qtRectangle.moveCenter(centerPoint) self.move(qtRectangle.topLeft()) centerPoint = QDesktopWidget().availableGeometry().center() qtRectangle.moveCenter(centerPoint) self.move(qtRectangle.topLeft()) self.gatherInfo.start() self.gatherInfo.finished.connect(self._finishProcess) #def loadGui def _finishProcess(self): self.loadingBox.spinner.stop() if len(self.core.javaPanelManager.java_list) > 0: self.installersBox.drawInstallerList() self.fader_widget = FaderWidget(self.QtStack.currentWidget(), self.QtStack.widget(1)) self.QtStack.setCurrentIndex(1) self.configurationButton.show() self.messageLabel.show() self.applyButton.show() else: self.messageLabel.show() self.loadingBox.spinner.hide() self.messageLabel.setText( _("No Java version(s) availables detected")) #def _finishProcess def applyButtonClicked(self): self.othersBox = [] self.javasToInstall = self.installersBox.javas_selected self.boxSelected = self.installersBox.box_selected #self.installersBox.scrollArea.setEnabled(False) self.messageLabel.setText("") if len(self.javasToInstall) > 0: self.applyButton.setEnabled(False) self.messageLabel.setText( _("Installing selected Java version(s). Wait a moment...")) for item in self.boxSelected: item.itemAt(0).widget().setEnabled(False) item.itemAt(3).widget().hide() item.itemAt(4).widget().show() item.itemAt(4).widget().start() for item in self.installersBox.boxInstallers.children(): if item.itemAt(0).widget().isEnabled(): item.itemAt(0).widget().setEnabled(False) self.othersBox.append(item) self.install = installProcess(self.javasToInstall) self.install.start() self.install.finished.connect(self._finishInstall) else: self.messageLabel.setText( _("You must select a Java version to install")) #def applyButtonClicked def _finishInstall(self): result = self.core.javaPanelManager.result_install error = False for item in result: if result[item]: for element in self.boxSelected: if element.itemAt(4).widget().item == item: element.itemAt(4).widget().stop() element.itemAt(4).widget().hide() pixmap = QPixmap(self.core.rsrc_dir + "check.png") element.itemAt(3).widget().setPixmap(pixmap) element.itemAt(0).widget().setChecked(False) element.itemAt(3).widget().show() else: for element in self.boxSelected: if element.itemAt(4).widget().item == item: element.itemAt(4).widget().stop() element.itemAt(4).widget().hide() pixmap = QPixmap(self.core.rsrc_dir + "error.png") element.itemAt(3).widget().setPixmap(pixmap) element.itemAt(0).widget().setChecked(False) element.itemAt(0).widget().setEnabled(True) element.itemAt(3).widget().show() error = True self.applyButton.setEnabled(True) for item in self.othersBox: item.itemAt(0).widget().setEnabled(True) if error: self.messageLabel.setText( _("Installing process has ending with errors")) else: self.messageLabel.setText( _("Installing process has ending successfully")) #def _finishInstall def changePanel(self, panel): if panel == "C": self.configurationButton.hide() self.messageLabel.setText("") self.configurationBox.drawConfigurationList() self.fader_widget = FaderWidget(self.QtStack.currentWidget(), self.QtStack.widget(2)) self.QtStack.setCurrentIndex(2) self.installersButton.show() self.applyButton.setEnabled(False) elif panel == "I": self.installersButton.hide() self.messageLabel.setText("") self.fader_widget = FaderWidget(self.QtStack.currentWidget(), self.QtStack.widget(2)) self.QtStack.setCurrentIndex(1) self.configurationButton.show() self.applyButton.setEnabled(True) self.configurationBox.boxDelete() #def changePanel def helpButtonClicked(self): lang = os.environ["LANG"] run_pkexec = False if "PKEXEC_UID" in os.environ: run_pkexec = True if 'ca_ES' in lang: cmd = 'xdg-open https://wiki.edu.gva.es/lliurex/tiki-index.php?page=LliureX-Java-Panel.' else: cmd = 'xdg-open https://wiki.edu.gva.es/lliurex/tiki-index.php?page=LliureX-Java-Panel' if not run_pkexec: self.fcmd = "su -c '%s' $USER" % cmd else: user = pwd.getpwuid(int(os.environ["PKEXEC_UID"])).pw_name self.fcmd = "su -c '" + cmd + "' " + user os.system(self.fcmd)
class RightPanel(QFrame): def __init__(self, app, parent=None): super().__init__(parent) self._app = app self._pixmap = None self._layout = QVBoxLayout(self) self._stacked_layout = QStackedLayout() self.scrollarea = ScrollArea(self._app, self) self.table_container = self.scrollarea.t # TODO: collection container will be removed self.collection_container = CollectionContainer(self._app, self) self.bottom_panel = BottomPanel(app, self) self._setup_ui() def _setup_ui(self): self.scrollarea.setMinimumHeight(100) self.collection_container.hide() self._layout.addWidget(self.bottom_panel) self._layout.addLayout(self._stacked_layout) self._stacked_layout.addWidget(self.scrollarea) self._stacked_layout.addWidget(self.collection_container) self._layout.setContentsMargins(0, 0, 0, 0) self._layout.setSpacing(0) def show_model(self, model): self.set_body(self.scrollarea) # TODO: use PreemptiveTask aio.create_task(self.table_container.show_model(model)) def show_songs(self, songs): self.collection_container.hide() self.set_body(self.scrollarea) self.table_container.show_songs(songs) def set_body(self, widget): """ .. versionadded:: 3.7.7 """ if widget is self.table_container: widget = self.scrollarea if widget is not self.scrollarea: self.show_background_image(None) # remove tmp widgets for i in range(self._stacked_layout.count()): w = self._stacked_layout.widget(i) if w not in (self.scrollarea, self.collection_container): self._stacked_layout.removeWidget(w) self._stacked_layout.addWidget(widget) self._stacked_layout.setCurrentWidget(widget) def show_collection(self, coll): def _show_pure_albums_coll(coll): self.set_body(self.scrollarea) reader = wrap(coll.models) self.table_container.show_albums_coll(reader) def _show_pure_songs_coll(coll): self.set_body(self.scrollarea) self.table_container.show_collection(coll) def _show_mixed_coll(coll): self.set_body(self.collection_container) self.collection_container.show_collection(coll) def _show_pure_videos_coll(coll): from feeluown.gui.page_containers.table import VideosRenderer self.set_body(self.scrollarea) reader = wrap(coll.models) renderer = VideosRenderer(reader) aio.create_task(self.table_container.set_renderer(renderer)) if coll.type is CollectionType.sys_library: self._app.browser.goto(page='/colls/library') return types = set() for model in coll.models: types.add(model.meta.model_type) if len(types) >= 2: break if len(types) == 1: type_ = types.pop() if type_ == ModelType.song: _show_pure_songs_coll(coll) elif type_ == ModelType.album: _show_pure_albums_coll(coll) elif type_ == ModelType.video: _show_pure_videos_coll(coll) else: _show_mixed_coll(coll) else: _show_mixed_coll(coll) def show_background_image(self, pixmap): self._pixmap = pixmap if pixmap is None: self.table_container.meta_widget.setMinimumHeight(0) else: height = (self._app.height() - self.bottom_panel.height() - self.table_container.toolbar.height()) // 2 self.table_container.meta_widget.setMinimumHeight(height) self.update() def paintEvent(self, e): """ draw pixmap as a the background with a dark overlay HELP: currently, this cost much CPU """ painter = QPainter(self) painter.setPen(Qt.NoPen) painter.setRenderHint(QPainter.Antialiasing) painter.setRenderHint(QPainter.SmoothPixmapTransform) # calculate available size draw_width = self.width() draw_height = 10 # spacing defined in table container draw_height += self.bottom_panel.height() if self.table_container.meta_widget.isVisible(): draw_height += self.table_container.meta_widget.height() extra = self.table_container.current_extra if extra is not None and extra.isVisible(): draw_height += extra.height() if self.table_container.toolbar.isVisible(): draw_height += self.table_container.toolbar.height() scrolled = self.scrollarea.verticalScrollBar().value() max_scroll_height = draw_height - self.bottom_panel.height() if scrolled >= max_scroll_height: painter.save() painter.setBrush(self.palette().brush(QPalette.Window)) painter.drawRect(self.bottom_panel.rect()) painter.restore() return if self._pixmap is not None: self._draw_pixmap(painter, draw_width, draw_height, scrolled) self._draw_pixmap_overlay(painter, draw_width, draw_height, scrolled) else: # draw gradient for widgets(bottom panel + meta_widget + ...) above table self._draw_overlay(painter, draw_width, draw_height, scrolled) # if scrolled height > 30, draw background to seperate bottom_panel and body if scrolled >= 30: painter.save() painter.setBrush(self.palette().brush(QPalette.Window)) painter.drawRect(self.bottom_panel.rect()) painter.restore() return # since the body's background color is palette(base), we use # the color to draw background for remain empty area painter.save() painter.setBrush(self.palette().brush(QPalette.Base)) painter.drawRect(0, draw_height, draw_width, self.height() - draw_height) painter.restore() painter.end() def _draw_pixmap_overlay(self, painter, draw_width, draw_height, scrolled): painter.save() rect = QRect(0, 0, draw_width, draw_height) painter.translate(0, -scrolled) gradient = QLinearGradient(rect.topLeft(), rect.bottomLeft()) color = self.palette().color(QPalette.Base) if draw_height == self.height(): gradient.setColorAt(0, add_alpha(color, 180)) gradient.setColorAt(1, add_alpha(color, 230)) else: if self._app.theme_mgr.theme == Light: gradient.setColorAt(0, add_alpha(color, 220)) gradient.setColorAt(0.1, add_alpha(color, 180)) gradient.setColorAt(0.2, add_alpha(color, 140)) gradient.setColorAt(0.6, add_alpha(color, 140)) gradient.setColorAt(0.8, add_alpha(color, 200)) gradient.setColorAt(0.9, add_alpha(color, 240)) gradient.setColorAt(1, color) else: gradient.setColorAt(0, add_alpha(color, 50)) gradient.setColorAt(0.6, add_alpha(color, 100)) gradient.setColorAt(0.8, add_alpha(color, 200)) gradient.setColorAt(0.9, add_alpha(color, 240)) gradient.setColorAt(1, color) painter.setBrush(gradient) painter.drawRect(rect) painter.restore() def _draw_overlay(self, painter, draw_width, draw_height, scrolled): painter.save() rect = QRect(0, 0, draw_width, draw_height) painter.translate(0, -scrolled) gradient = QLinearGradient(rect.topLeft(), rect.bottomLeft()) gradient.setColorAt(0, self.palette().color(QPalette.Window)) gradient.setColorAt(1, self.palette().color(QPalette.Base)) painter.setBrush(gradient) painter.drawRect(rect) painter.restore() def _draw_pixmap(self, painter, draw_width, draw_height, scrolled): # scale pixmap scaled_pixmap = self._pixmap.scaledToWidth( draw_width, mode=Qt.SmoothTransformation) pixmap_size = scaled_pixmap.size() # draw the center part of the pixmap on available rect painter.save() brush = QBrush(scaled_pixmap) painter.setBrush(brush) # note: in practice, most of the time, we can't show the # whole artist pixmap, as a result, the artist head will be cut, # which causes bad visual effect. So we render the top-center part # of the pixmap here. y = (pixmap_size.height() - draw_height) // 3 painter.translate(0, -y - scrolled) rect = QRect(0, y, draw_width, draw_height) painter.drawRect(rect) painter.restore() def sizeHint(self): size = super().sizeHint() return QSize(760, size.height())
class _MainContainer(QWidget): currentEditorChanged = pyqtSignal("QString") fileOpened = pyqtSignal("QString") fileSaved = pyqtSignal("QString") def __init__(self, parent=None): super().__init__(parent) self._vbox = QVBoxLayout(self) self._vbox.setContentsMargins(0, 0, 0, 0) self._vbox.setSpacing(0) self.stack = QStackedLayout() self.stack.setStackingMode(QStackedLayout.StackAll) self._vbox.addLayout(self.stack) self.splitter = dynamic_splitter.DynamicSplitter() self.setAcceptDrops(True) # QML UI self._add_file_folder = add_file_folder.AddFileFolderWidget(self) if settings.SHOW_START_PAGE: self.show_start_page() IDE.register_service("main_container", self) # Register signals connections connections = ({ "target": "main_container", "signal_name": "updateLocator", "slot": self._explore_code }, { "target": "filesystem", "signal_name": "projectOpened", "slot": self._explore_code }, { "target": "projects_explore", "signal_name": "updateLocator", "slot": self._explore_code }) IDE.register_signals("main_container", connections) esc_sort = QShortcut(QKeySequence(Qt.Key_Escape), self) esc_sort.activated.connect(self._set_focus_to_editor) def install(self): ninjaide = IDE.get_service("ide") ninjaide.place_me_on("main_container", self, "central", top=True) self.combo_area = combo_editor.ComboEditor(original=True) self.combo_area.allFilesClosed.connect(self._files_closed) self.splitter.add_widget(self.combo_area) self.add_widget(self.splitter) self.current_widget = self.combo_area # Code Locator self._code_locator = locator_widget.LocatorWidget(ninjaide) ui_tools.install_shortcuts(self, actions.ACTIONS, ninjaide) def _set_focus_to_editor(self): status_bar = IDE.get_service("status_bar") tools_doock = IDE.get_service("tools_dock") editor_widget = self.get_current_editor() if status_bar.isVisible() and tools_doock.isVisible(): status_bar.hide_status_bar() elif tools_doock.isVisible(): tools_doock._hide() elif status_bar.isVisible(): status_bar.hide_status_bar() if editor_widget is not None: editor_widget.clear_extra_selections('searchs') def split_assistance(self): split_widget = split_orientation.SplitOrientation(self) split_widget.show() def show_split(self, orientation_vertical=False): self.current_widget.split_editor(orientation_vertical) def show_locator(self): """Show the Locator Widget""" if not self._code_locator.isVisible(): self._code_locator.show() def _explore_code(self): """Update locator metadata for the current projects""" self._code_locator.explore_code() def current_editor_changed(self, filename): """Notify the new filename of the current editor""" if filename is None: filename = translations.TR_NEW_DOCUMENT self.currentEditorChanged.emit(filename) def get_current_editor(self): current_widget = self.current_widget.currentWidget() if isinstance(current_widget, editor.NEditor): return current_widget return None def open_file(self, filename='', line=-1, col=0): logger.debug("Will try to open %s" % filename) if not filename: logger.debug("Has no filename") if settings.WORKSPACE: directory = settings.WORKSPACE else: directory = os.path.expanduser("~") editor_widget = self.get_current_editor() ninjaide = IDE.get_service("ide") current_project = ninjaide.get_current_project() # TODO: handle current project in NProject if current_project is not None: directory = current_project.full_path elif editor_widget is not None and editor_widget.file_path: directory = file_manager.get_folder( editor_widget.file_path) extensions = ";;".join([ "{}(*{})".format(e.upper()[1:], e) for e in settings.SUPPORTED_EXTENSIONS + [".*", ""] ]) filenames = QFileDialog.getOpenFileNames( self, "Open File", # FIXME: translations directory, extensions)[0] else: logger.debug("Has filename") filenames = [filename] if not filenames: return for filename in filenames: logger.debug("Will try to open: %s" % filename) self.__open_file(filename, line, col) def __open_file(self, filename, line, col): try: editor_widget = self.add_editor(filename) if line != -1: editor_widget.go_to_line(line, col) self.currentEditorChanged.emit(filename) except file_manager.NinjaIOException as reason: QMessageBox.information( self, "The file couldn't be open", # FIXME: translations str(reason)) logger.error("The file %s couldn't be open" % filename) def save_file(self, editor_widget=None): if editor_widget is None: # This may return None if there is not editor present editor_widget = self.get_current_editor() if editor_widget is None: return False # Ok, we have an editor instance # Save to file only if editor really was modified if editor_widget.is_modified: try: if editor_widget.nfile.is_new_file or \ not editor_widget.nfile.has_write_permission(): return self.save_file_as(editor_widget) # FIXME: beforeFileSaved.emit if settings.REMOVE_TRAILING_SPACES: pass # FIXME: new line at end # Save content editor_widget.neditable.save_content() # FIXME: encoding # FIXME: translations self.fileSaved.emit("File Saved: %s" % editor_widget.file_path) return True except Exception as reason: logger.error("Save file error: %s" % reason) QMessageBox.information(self, "Save Error", "The file could't be saved!") return False def save_file_as(self, editor_widget=None): force = False if editor_widget is None: # We invoque from menu editor_widget = self.get_current_editor() if editor_widget is None: # We haven't editor in main container return False force = True try: filters = "(*.py);;(*.*)" if editor_widget.file_path is not None: # Existing file extension = file_manager.get_file_extension( editor_widget.file_path) if extension != 'py': filters = "(*.%s);;(*.py);;(*.*)" % extension save_folder = self._get_save_folder(editor_widget.file_path) filename = QFileDialog.getSaveFileName(self, "Save File", save_folder, filters)[0] if not filename: return False # FIXME: remove trailing spaces extension = file_manager.get_file_extension(filename) if not extension: filename = "%s.%s" % (filename, "py") editor_widget.neditable.save_content(path=filename, force=force) self.fileSaved.emit("File Saved: {}".format(filename)) self.currentEditorChanged.emit(filename) return True except file_manager.NinjaFileExistsException as reason: QMessageBox.information( self, "File Already Exists", "Invalid Path: the file '%s' already exists." % reason.filename) except Exception as reason: logger.error("save_file_as: %s", reason) QMessageBox.information(self, "Save Error", "The file couldn't be saved!") return False def _get_save_folder(self, filename): """Returns the root directory of the 'Main Project' or the home folder""" ninjaide = IDE.get_service("ide") current_project = ninjaide.get_current_project() if current_project is not None: return current_project.path return os.path.expanduser("~") def close_file(self): self.current_widget.close_current_file() def add_editor(self, filename=None): ninjaide = IDE.get_service("ide") editable = ninjaide.get_or_create_editable(filename) if editable.editor: # If already open logger.debug("%s is already open" % filename) self.current_widget.set_current(editable) return self.current_widget.currentWidget() else: pass editor_widget = self.create_editor_from_editable(editable) # editor_widget.set_language() # Add the tab keep_index = (self.splitter.count() > 1 and self.combo_area.stacked.count() > 0) self.combo_area.add_editor(editable, keep_index) # Emit a signal about the file open self.fileOpened.emit(filename) if not keep_index: self.current_widget.set_current(editable) self.stack.setCurrentWidget(self.splitter) editor_widget.setFocus() return editor_widget def create_editor_from_editable(self, editable): neditor = editor.create_editor(editable) neditor.zoomChanged.connect(self._show_zoom_indicator) neditor.destroyed.connect(self.__on_editor_destroyed) # editable.fileSaved.connect(self._editor_tab) return neditor def _show_zoom_indicator(self, zoom): neditor = self.get_current_editor() indicator.Indicator.show_text(neditor, "Zoom: {} %".format(str(zoom))) @pyqtSlot() def __on_editor_destroyed(self): indicator.Indicator.instance = None def add_widget(self, widget): self.stack.addWidget(widget) def show_start_page(self): """Show Start Page widget in main container""" startp = self.stack.widget(0) if isinstance(startp, start_page.StartPage): self.stack.setCurrentIndex(0) else: startp = start_page.StartPage(parent=self) startp.newFile.connect(self.add_editor) self.stack.insertWidget(0, startp) self.stack.setCurrentIndex(0) def _files_closed(self): if settings.SHOW_START_PAGE: self.show_start_page() def add_status_bar(self, status_bar): self._vbox.addWidget(status_bar) def create_file(self, base_path, project_path): self._add_file_folder.create_file(base_path, project_path) def create_folder(self, base_path, project_path): self._add_file_folder.create_folder(base_path, project_path) def zoom_in_editor(self): """Increase the font size in the current editor""" editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.zoom(1.) def zoom_out_editor(self): """Decrease the font size in the current editor""" editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.zoom(-1.) def reset_zoom_editor(self): """Reset the to original font size in the current editor""" editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.reset_zoom() def editor_move_up(self): editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.move_up_down(up=True) def editor_move_down(self): editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.move_up_down() def editor_duplicate_line(self): editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.duplicate_line() def editor_comment(self): editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.comment()
class ComboEditor(QWidget): # Signals closeSplit = pyqtSignal('PyQt_PyObject') splitEditor = pyqtSignal( 'PyQt_PyObject', 'PyQt_PyObject', Qt.Orientation) allFilesClosed = pyqtSignal() about_to_close_combo_editor = pyqtSignal() fileClosed = pyqtSignal("PyQt_PyObject") def __init__(self, original=False): super(ComboEditor, self).__init__(None) self.__original = original self.__undocked = [] self._symbols_index = [] vbox = QVBoxLayout(self) vbox.setContentsMargins(0, 0, 0, 0) vbox.setSpacing(0) self.bar = ActionBar(main_combo=original) vbox.addWidget(self.bar) # Info bar # self.info_bar = InfoBar(self) # self.info_bar.setVisible(False) # vbox.addWidget(self.info_bar) self.stacked = QStackedLayout() vbox.addLayout(self.stacked) self._main_container = IDE.get_service('main_container') if not self.__original: self._main_container.fileOpened['QString'].connect( self._file_opened_by_main) self.bar.combo_files.showComboSelector.connect( self._main_container.show_files_handler) self.bar.combo_files.hideComboSelector.connect( self._main_container.hide_files_handler) self.bar.change_current['PyQt_PyObject', int].connect(self._set_current) self.bar.splitEditor[bool].connect(self.split_editor) self.bar.runFile['QString'].connect(self._run_file) self.bar.closeSplit.connect(lambda: self.closeSplit.emit(self)) self.bar.addToProject['QString'].connect(self._add_to_project) self.bar.showFileInExplorer['QString'].connect( self._show_file_in_explorer) self.bar.goToSymbol[int].connect(self._go_to_symbol) self.bar.undockEditor.connect(self.undock_editor) self.bar.reopenTab['QString'].connect( lambda path: self._main_container.open_file(path)) self.bar.closeImageViewer.connect(self._close_image) self.bar.code_navigator.previousPressed.connect(self._navigate_code) self.bar.code_navigator.nextPressed.connect(self._navigate_code) # self.connect(self.bar, SIGNAL("recentTabsModified()"), # lambda: self._main_container.recent_files_changed()) # self.connect(self.bar.code_navigator.btnPrevious, # SIGNAL("clicked()"), # lambda: self._navigate_code(False)) # self.connect(self.bar.code_navigator.btnNext, SIGNAL("clicked()"), # lambda: self._navigate_code(True)) def _navigate_code(self, operation, forward=True): self._main_container.navigate_code_history(operation, forward) # op = self.bar.code_navigator.operation # self._main_container.navigate_code_history(val, op) def current_editor(self): return self.stacked.currentWidget() def setFocus(self): super(ComboEditor, self).setFocus() self.current_editor().setFocus() self._editor_with_focus() def _file_opened_by_main(self, path): index = self.stacked.currentIndex() ninjaide = IDE.get_service('ide') editable = ninjaide.get_or_create_editable(path) self.add_editor(editable) self.bar.set_current_by_index(index) if index == -1: self.bar.set_current_by_index(0) def add_image_viewer(self, viewer): """Add Image Viewer widget to the UI area""" self.stacked.addWidget(viewer) viewer.scaleFactorChanged.connect( self.bar.image_viewer_controls.update_scale_label) viewer.imageSizeChanged.connect( self.bar.image_viewer_controls.update_size_label) self.bar.add_item(viewer.display_name(), None) viewer.create_scene() if not self.bar.isVisible(): self.bar.setVisible(True) def add_editor(self, neditable, keep_index=False): """Add Editor Widget to the UI area.""" if neditable.editor: if self.__original: editor = neditable.editor else: # editor = neditable.editor.clone() editor = self._main_container.create_editor_from_editable( neditable) neditable.editor.link(editor) current_index = self.stacked.currentIndex() new_index = self.stacked.addWidget(editor) self.stacked.setCurrentIndex(new_index) self.bar.add_item(neditable.display_name, neditable) # Bar is not visible because all the files have been closed, # so if a new file is opened, show the bar if not self.bar.isVisible(): self.bar.setVisible(True) if keep_index: self.bar.set_current_by_index(current_index) # Connections neditable.fileClosing.connect(self._close_file) neditable.fileSaved.connect(self._update_symbols) editor.editorFocusObtained.connect(self._editor_with_focus) editor.modificationChanged.connect(self._editor_modified) editor.cursor_position_changed[int, int].connect( self._update_cursor_position) editor.current_line_changed[int].connect(self._set_current_symbol) if neditable._swap_file.dirty: self._editor_modified(True, sender=editor) neditable.checkersUpdated.connect(self._show_notification_icon) # Connect file system signals only in the original if self.__original: neditable.askForSaveFileClosing.connect(self._ask_for_save) neditable.fileChanged.connect(self._file_has_been_modified) # Load Symbols self._load_symbols(neditable) def show_combo_file(self): self.bar.combo.showPopup() def show_combo_symbol(self): self.bar.symbols_combo.showPopup() def show_combo_set_language(self): self.bar.set_language_combo.showPopup() def unlink_editors(self): for index in range(self.stacked.count()): widget = self.stacked.widget(index) # widget.setDocument(QsciDocument()) def clone(self): combo = ComboEditor() for neditable in self.bar.get_editables(): combo.add_editor(neditable) return combo def split_editor(self, orientation): new_combo = self.clone() self.splitEditor.emit(self, new_combo, orientation) def undock_editor(self): new_combo = ComboEditor() for neditable in self.bar.get_editables(): new_combo.add_editor(neditable) self.__undocked.append(new_combo) new_combo.setWindowTitle("NINJA-IDE") editor = self.current_editor() new_combo.set_current(editor.neditable) new_combo.resize(700, 500) new_combo.about_to_close_combo_editor.connect(self._remove_undock) new_combo.show() def _remove_undock(self): widget = self.sender() self.__undocked.remove(widget) def close_current_file(self): self.bar.about_to_close_file() def _close_image(self, index): layout_item = self.stacked.takeAt(index) layout_item.widget().deleteLater() if self.stacked.isEmpty(): self.bar.hide() self.allFilesClosed.emit() def _close_file(self, neditable): index = self.bar.close_file(neditable) layoutItem = self.stacked.takeAt(index) # neditable.editor.completer.cc.unload_module() self.fileClosed.emit(neditable.nfile) layoutItem.widget().deleteLater() if self.stacked.isEmpty(): self.bar.hide() self.allFilesClosed.emit() tree_symbols = IDE.get_service("symbols_explorer") if tree_symbols is not None: tree_symbols.clear() def _editor_with_focus(self): self._main_container.combo_area = self editor = self.current_editor() if editor is not None: self._main_container.current_editor_changed( editor.neditable.file_path) self._load_symbols(editor.neditable) editor.neditable.update_checkers_display() def _ask_for_save(self, neditable): val = QMessageBox.No fileName = neditable.nfile.file_name val = QMessageBox.question( self, (self.tr('The file %s was not saved') % fileName), self.tr("Do you want to save before closing?"), QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel) if val == QMessageBox.No: neditable.nfile.close(force_close=True) elif val == QMessageBox.Yes: neditable.ignore_checkers = True self._main_container.save_file(neditable.editor) neditable.nfile.close() @pyqtSlot("PyQt_PyObject") def _recovery(self, neditable): print("lalalal") def _file_has_been_modified(self, neditable): index = self.bar.combo_files.findData(neditable) self.stacked.setCurrentIndex(index) self.bar.combo_files.setCurrentIndex(index) msg_box = QMessageBox(self) msg_box.setIcon(QMessageBox.Information) msg_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No) msg_box.setDefaultButton(QMessageBox.Yes) msg_box.setWindowTitle(translations.TR_FILE_HAS_BEEN_MODIFIED) msg_box.setText( translations.TR_FILE_MODIFIED_OUTSIDE % neditable.display_name) result = msg_box.exec_() if result == QMessageBox.Yes: neditable.reload_file() return def _run_file(self, path): self._main_container.run_file(path) def _add_to_project(self, path): self._main_container._add_to_project(path) def _show_file_in_explorer(self, path): '''Connected to ActionBar's showFileInExplorer(QString) signal, forwards the file path on to the main container.''' self._main_container._show_file_in_explorer(path) def set_current(self, neditable): if neditable: self.bar.set_current_file(neditable) def _set_current(self, neditable, index): self.stacked.setCurrentIndex(index) if neditable: self.bar.image_viewer_controls.setVisible(False) self.bar.code_navigator.setVisible(True) self.bar.symbols_combo.setVisible(True) self.bar.lbl_position.setVisible(True) editor = self.current_editor() self._update_cursor_position(ignore_sender=True) editor.setFocus() self._main_container.current_editor_changed( neditable.file_path) self._load_symbols(neditable) # self._show_file_in_explorer(neditable.file_path) neditable.update_checkers_display() else: self.bar.combo_files.setCurrentIndex(index) viewer_widget = self.stacked.widget(index) self._main_container.current_editor_changed( viewer_widget.image_filename) self.bar.image_viewer_controls.setVisible(True) self.bar.code_navigator.setVisible(False) self.bar.symbols_combo.setVisible(False) self.bar.lbl_position.setVisible(False) def widget(self, index): return self.stacked.widget(index) def count(self): """Return the number of editors opened.""" return self.stacked.count() def _update_cursor_position(self, line=0, col=0, ignore_sender=False): obj = self.sender() editor = self.current_editor() # Check if it's current to avoid signals from other splits. if ignore_sender or editor == obj: line += 1 self.bar.update_line_col(line, col) def _set_current_symbol(self, line, ignore_sender=False): obj = self.sender() editor = self.current_editor() # Check if it's current to avoid signals from other splits. if ignore_sender or editor == obj: index = bisect.bisect(self._symbols_index, line) if (index >= len(self._symbols_index) or self._symbols_index[index] > (line + 1)): index -= 1 self.bar.set_current_symbol(index) def _editor_modified(self, value, sender=None): if sender is None: sender = self.sender() neditable = sender.neditable if value: text = "\u2022 %s" % neditable.display_name self.bar.update_item_text(neditable, text) else: self.bar.update_item_text(neditable, neditable.display_name) def _go_to_symbol(self, index): line = self._symbols_index[index] editor = self.current_editor() editor.go_to_line(line, center=True) editor.setFocus() def _update_symbols(self, neditable): editor = self.current_editor() # Check if it's current to avoid signals from other splits. if editor.neditable == neditable: self._load_symbols(neditable) def _update_combo_info(self, neditable): self.bar.update_item_text(neditable, neditable.display_name) self._main_container.current_editor_changed(neditable.file_path) def _load_symbols(self, neditable): # Get symbols handler by language symbols_handler = handlers.get_symbols_handler(neditable.language()) if symbols_handler is None: return source = neditable.editor.text source = source.encode(neditable.editor.encoding) symbols, symbols_simplified = symbols_handler.obtain_symbols( source, simple=True) self._symbols_index = sorted(symbols_simplified.keys()) symbols_simplified = sorted( list(symbols_simplified.items()), key=lambda x: x[0]) self.bar.add_symbols(symbols_simplified) line, _ = neditable.editor.cursor_position self._set_current_symbol(line, True) tree_symbols = IDE.get_service('symbols_explorer') if tree_symbols is not None: tree_symbols.update_symbols_tree(symbols, neditable.file_path) def _show_notification_icon(self, neditable): checkers = neditable.sorted_checkers icon = QIcon() for items in checkers: checker, color, _ = items if checker.checks: if isinstance(checker.checker_icon, int): icon = self.style().standardIcon(checker.checker_icon) elif isinstance(checker.checker_icon, str): icon = QIcon(checker.checker_icon) # FIXME: sucks else: icon = QIcon(checker.checker_icon) break self.bar.update_item_icon(neditable, icon) def show_menu_navigation(self): self.bar.code_navigator.show_menu_navigation() def closeEvent(self, event): self.about_to_close_combo_editor.emit() # self.emit(SIGNAL("aboutToCloseComboEditor()")) super(ComboEditor, self).closeEvent(event) def reject(self): if not self.__original: super(ComboEditor, self).reject()
class _MainContainer(QWidget): currentEditorChanged = pyqtSignal(str) fileOpened = pyqtSignal(str) beforeFileSaved = pyqtSignal(str) fileSaved = pyqtSignal(str) runFile = pyqtSignal(str) showFileInExplorer = pyqtSignal(str) addToProject = pyqtSignal(str) allFilesClosed = pyqtSignal() def __init__(self, parent=None): super().__init__(parent) self.setAcceptDrops(True) self._vbox = QVBoxLayout(self) self._vbox.setContentsMargins(0, 0, 0, 0) self._vbox.setSpacing(0) self.stack = QStackedLayout() self.stack.setStackingMode(QStackedLayout.StackAll) self._vbox.addLayout(self.stack) self.splitter = dynamic_splitter.DynamicSplitter() self._files_handler = files_handler.FilesHandler(self) # Code Navigation self.__code_back = [] self.__code_forward = [] self.__operations = { 0: self._navigate_code_jumps, 1: self._navigate_bookmarks } # Recent files list self.__last_opened_files = [] # QML UI self._add_file_folder = add_file_folder.AddFileFolderWidget(self) if settings.SHOW_START_PAGE: self.show_start_page() IDE.register_service("main_container", self) # Register signals connections connections = ( # { # "target": "main_container", # "signal_name": "updateLocator", # "slot": self._explore_code # }, { "target": "filesystem", "signal_name": "projectOpened", "slot": self._explore_code }, # { # "target": "projects_explore", # "signal_name": "updateLocator", # "slot": self._explore_code # } { "target": "filesystem", "signal_name": "projectClosed", "slot": self._explore_code } ) IDE.register_signals("main_container", connections) fhandler_short = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_Tab), self) fhandler_short.activated.connect(self.show_files_handler) # Added for set language # self._setter_language = set_language.SetLanguageFile() def install(self): ninjaide = IDE.get_service("ide") ninjaide.place_me_on("main_container", self, "central", top=True) self.combo_area = combo_editor.ComboEditor(original=True) self.combo_area.allFilesClosed.connect(self._files_closed) self.combo_area.allFilesClosed.connect( lambda: self.allFilesClosed.emit()) self.combo_area.fileClosed.connect(self._add_to_last_opened) self.splitter.add_widget(self.combo_area) self.add_widget(self.splitter) # self.current_widget = self.combo_area # Code Locator self._code_locator = locator_widget.LocatorWidget(ninjaide) data_settings = IDE.data_settings() recent_files = data_settings.value("lastSession/recentFiles") if recent_files is not None: self.__last_opened_files = recent_files ui_tools.install_shortcuts(self, actions.ACTIONS, ninjaide) # self.fileSaved.connect(self._show_message_about_saved) def run_file(self, filepath): self.runFile.emit(filepath) def _show_file_in_explorer(self, filepath): self.showFileInExplorer.emit(filepath) def _add_to_project(self, filepath): self.addToProject.emit(filepath) def show_files_handler(self): self._files_handler.next_item() def hide_files_handler(self): self._files_handler.hide() def import_from_everywhere(self): """Insert an import line from any place in the editor.""" editorWidget = self.get_current_editor() if editorWidget: dialog = from_import_dialog.FromImportDialog(editorWidget, self) dialog.show() def navigate_code_history(self, operation, forward): self.__operations[operation](forward) def _navigate_code_jumps(self, forward=False): """Navigate between the jump points""" node = None if not forward and self.__code_back: if len(self.__code_back) == 1: return node = self.__code_back.pop() self.__code_forward.append(node) node = self.__code_back[-1] elif forward and self.__code_forward: node = self.__code_forward.pop() self.__code_back.append(node) if node is not None: filename = node[0] line, col = node[1] self.open_file(filename, line, col) def _navigate_bookmarks(self, forward=True): """Navigate between the bookmarks""" current_editor = self.get_current_editor() current_editor.navigate_bookmarks(forward=forward) def _set_focus_to_editor(self): status_bar = IDE.get_service("status_bar") tools_doock = IDE.get_service("tools_dock") editor_widget = self.get_current_editor() if status_bar.isVisible() and tools_doock.isVisible(): status_bar.hide_status_bar() elif tools_doock.isVisible(): tools_doock._hide() elif status_bar.isVisible(): status_bar.hide_status_bar() if editor_widget is not None: editor_widget.extra_selections.remove("find") editor_widget.scrollbar().remove_marker("find") def split_assistance(self): editor_widget = self.get_current_editor() if editor_widget is not None: split_widget = split_orientation.SplitOrientation(self) split_widget.show() def show_dialog(self, widget): self.add_widget(widget) self.stack.setCurrentWidget(widget) def show_split(self, orientation_vertical=False): orientation = Qt.Horizontal if orientation_vertical: orientation = Qt.Vertical self.combo_area.split_editor(orientation) def show_locator(self): """Show the Locator Widget""" if not self._code_locator.isVisible(): self._code_locator.show() def _explore_code(self): """Update locator metadata for the current projects""" self._code_locator.explore_code() def _explore_file_code(self, path): """Update locator metadata for the file in path""" self._code_locator.explore_file_code(path) def current_editor_changed(self, filename): """Notify the new filename of the current editor""" if filename is None: filename = translations.TR_NEW_DOCUMENT self.currentEditorChanged.emit(filename) def get_current_editor(self): current_widget = self.combo_area.current_editor() if isinstance(current_widget, editor.NEditor): return current_widget return None @property def last_opened_files(self): return self.__last_opened_files def _add_to_last_opened(self, nfile): MAX_RECENT_FILES = 10 # FIXME: configuration if nfile.is_new_file: return file_path = nfile.file_path if file_path in self.__last_opened_files: self.__last_opened_files.remove(file_path) self.__last_opened_files.insert(0, file_path) if len(self.__last_opened_files) > MAX_RECENT_FILES: self.__last_opened_files.pop(-1) def clear_last_opened_files(self): self.__last_opened_files.clear() def open_file(self, filename='', line=-1, col=0, ignore_checkers=False): if not filename: logger.debug("Has no filename") if settings.WORKSPACE: directory = settings.WORKSPACE else: directory = os.path.expanduser("~") editor_widget = self.get_current_editor() ninjaide = IDE.get_service("ide") current_project = ninjaide.get_current_project() # TODO: handle current project in NProject if current_project is not None: directory = current_project.full_path elif editor_widget is not None and editor_widget.file_path: directory = file_manager.get_folder( editor_widget.file_path) filenames = QFileDialog.getOpenFileNames( self, translations.TR_OPEN_A_FILE, directory, settings.get_supported_extensions_filter(), initialFilter="Python files (*.py *.pyw)" )[0] else: logger.debug("Has filename") filenames = [filename] if not filenames: return for filename in filenames: image_extensions = ("png", "jpg", "jpeg", "bmp", "gif") if file_manager.get_file_extension(filename) in image_extensions: logger.debug("Will open as image") self.open_image(filename) else: logger.debug("Will try to open: %s" % filename) self.__open_file( filename, line, col, ignore_checkers=ignore_checkers) def __open_file(self, filename, line, col, ignore_checkers=False): try: self.add_editor(filename) if line != -1: self.editor_go_to_line(line, col) self.currentEditorChanged.emit(filename) except file_manager.NinjaIOException as reason: QMessageBox.information( self, translations.TR_OPEN_FILE_ERROR, str(reason)) logger.error("The file %s couldn't be open" % filename) def open_image(self, filename): for index in range(self.combo_area.stacked.count()): widget = self.combo_area.stacked.widget(index) if isinstance(widget, image_viewer.ImageViewer): if widget.image_filename == filename: logger.debug("Image already open") self.combo_area._set_current(neditable=None, index=index) return viewer = image_viewer.ImageViewer(filename) self.combo_area.add_image_viewer(viewer) self.stack.setCurrentWidget(self.splitter) def autosave_file(self): for neditable in self.combo_area.bar.get_editables(): neditable.autosave_file() def save_file(self, editor_widget=None): if editor_widget is None: # This may return None if there is not editor present editor_widget = self.get_current_editor() if editor_widget is None: return False # Ok, we have an editor instance # Save to file only if editor really was modified if editor_widget.is_modified: try: if editor_widget.nfile.is_new_file or \ not editor_widget.nfile.has_write_permission(): return self.save_file_as(editor_widget) file_path = editor_widget.file_path # Emit signal before save self.beforeFileSaved.emit(file_path) if settings.REMOVE_TRAILING_SPACES: editor_widget.remove_trailing_spaces() if settings.ADD_NEW_LINE_AT_EOF: editor_widget.insert_block_at_end() # Save content editor_widget.neditable.save_content() # FIXME: encoding message = translations.TR_FILE_SAVED.format(file_path) self.fileSaved.emit(message) return True except Exception as reason: logger.error("Save file error: %s" % reason) QMessageBox.information( self, translations.TR_SAVE_FILE_ERROR_TITLE, translations.TR_SAVE_FILE_ERROR_BODY ) return False def save_file_as(self, editor_widget=None): force = False if editor_widget is None: # We invoque from menu editor_widget = self.get_current_editor() if editor_widget is None: # We haven't editor in main container return False force = True try: filters = "(*.py);;(*.*)" if editor_widget.file_path is not None: # Existing file extension = file_manager.get_file_extension( editor_widget.file_path) if extension != 'py': filters = "(*.%s);;(*.py);;(*.*)" % extension save_folder = self._get_save_folder(editor_widget.file_path) else: save_folder = settings.WORKSPACE filename = QFileDialog.getSaveFileName( self, translations.TR_SAVE_FILE_DIALOG, save_folder, filters )[0] if not filename: return False # FIXME: remove trailing spaces extension = file_manager.get_file_extension(filename) if not extension: filename = "%s.%s" % (filename, "py") editor_widget.neditable.save_content(path=filename, force=force) # self._setter_language.set_language_from_extension(extension) self.fileSaved.emit(translations.TR_FILE_SAVED.format(filename)) self.currentEditorChanged.emit(filename) return True except file_manager.NinjaFileExistsException as reason: QMessageBox.information( self, translations.TR_FILE_ALREADY_EXISTS_TITLE, translations.TR_FILE_ALREADY_EXISTS_BODY.format( reason.filename) ) except Exception as reason: logger.error("Save file as: %s", reason) QMessageBox.information( self, translations.TR_SAVE_FILE_ERROR_TITLE, translations.TR_SAVE_FILE_ERROR_BODY ) return False def save_project(self, project_path): """Save all files in the project path""" for neditable in self.combo_area.bar.get_editables(): file_path = neditable.file_path if file_path is None: # FIXME: New edited files will not be saved, its ok? continue if file_manager.belongs_to_folder(project_path, file_path): neditable.save_content() def _get_save_folder(self, filename): """Returns the root directory of the 'Main Project' or the home folder""" ninjaide = IDE.get_service("ide") current_project = ninjaide.get_current_project() if current_project is not None: return current_project.path return os.path.expanduser("~") def close_file(self): self.combo_area.close_current_file() def add_editor(self, filename=None): ninjaide = IDE.get_service("ide") editable = ninjaide.get_or_create_editable(filename) if editable.editor: # If already open logger.debug("%s is already open" % filename) self.combo_area.set_current(editable) return self.combo_area.current_editor() else: pass editor_widget = self.create_editor_from_editable(editable) # editor_widget.set_language() # Add the tab keep_index = (self.splitter.count() > 1 and self.combo_area.stacked.count() > 0) self.combo_area.add_editor(editable, keep_index) # Emit a signal about the file open self.fileOpened.emit(filename) if keep_index: self.combo_area.set_current(editable) self.stack.setCurrentWidget(self.splitter) editor_widget.setFocus() return editor_widget def create_editor_from_editable(self, editable): neditor = editor.create_editor(editable) neditor.zoomChanged.connect(self._on_zoom_changed) neditor.addBackItemNavigation.connect(self.add_back_item_navigation) editable.fileSaved.connect( lambda neditable: self._explore_file_code(neditable.file_path)) return neditor def add_back_item_navigation(self): editor_widget = self.get_current_editor() if editor_widget is not None: item = (editor_widget.file_path, editor_widget.cursor_position) if item not in self.__code_back: self.__code_back.append(item) # self.__code_forward.clear() def _on_zoom_changed(self, zoom): text = "Zoom: {}%".format(str(zoom)) ide = IDE.get_service("ide") ide.show_message(text) def add_widget(self, widget): self.stack.addWidget(widget) def show_start_page(self): """Show Start Page widget in main container""" startp = self.stack.widget(0) if isinstance(startp, start_page.StartPage): self.stack.setCurrentIndex(0) else: startp = start_page.StartPage(parent=self) startp.newFile.connect(self.add_editor) self.stack.insertWidget(0, startp) self.stack.setCurrentIndex(0) def _files_closed(self): if settings.SHOW_START_PAGE: self.show_start_page() def add_status_bar(self, status_bar): self._vbox.addWidget(status_bar) def create_file(self, base_path, project_path): self._add_file_folder.create_file(base_path, project_path) def create_folder(self, base_path, project_path): self._add_file_folder.create_folder(base_path, project_path) def restyle_editor(self): neditables = self.combo_area.bar.get_editables() for neditable in neditables: neditable.editor.restyle() def zoom_in_editor(self): """Increase the font size in the current editor""" editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.zoom(1.) def zoom_out_editor(self): """Decrease the font size in the current editor""" editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.zoom(-1.) def reset_zoom_editor(self): """Reset the to original font size in the current editor""" editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.reset_zoom() def editor_move_up(self): editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.move_up_down(up=True) def editor_move_down(self): editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.move_up_down() def editor_duplicate_line(self): editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.duplicate_line() def editor_toggle_comment(self): """Mark the current line or selection as a comment.""" editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.comment_or_uncomment() def editor_go_to_line(self, line, column=0, center=True): editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.go_to_line(line, column, center) editor_widget.setFocus() def _editor_settings_changed(self, key, value): key = key.split("/")[-1] editor_widget = self.get_current_editor() if editor_widget is not None: callback = getattr(editor.NEditor, key, False) if callback: callback = callback if not hasattr(callback, "__call__"): # Property! callback = callback.fset callback(editor_widget, value) def toggle_tabs_and_spaces(self): """Toggle Show/Hide Tabs and Spaces""" settings.SHOW_TABS_AND_SPACES = not settings.SHOW_TABS_AND_SPACES qsettings = IDE.ninja_settings() qsettings.setValue('preferences/editor/showTabsAndSpaces', settings.SHOW_TABS_AND_SPACES) neditor = self.get_current_editor() if neditor is not None: neditor.show_whitespaces = settings.SHOW_TABS_AND_SPACES def __navigate_with_keyboard(self, forward): """Navigate between the positions in the jump history stack.""" operation = self.combo_area.bar.code_navigator.operation self.navigate_code_history(operation, forward) def navigate_back(self): self.__navigate_with_keyboard(forward=False) def navigate_forward(self): self.__navigate_with_keyboard(forward=True)
class Main(QWidget): def __init__(self): QWidget.__init__(self) self.magneto = magnetoGauge() self.magneto.initialize({'mag': {'value': 0}}) self.switch = switchPanel() self.light = lightPanel() self.warn = warnPanel() self.radio = radioPanel() self.radio.initialize({}) self.airspeed = airspeedGauge() self.accelerometer = accelerometerGauge() self.accelerometer.initialize({'load': {'value': 0}}) self.attitude = attitudeGauge() self.attitude.initialize({'pitch': {'value': 0}, 'roll': {'value': 0}}) self.altitude = altitudeGauge() self.altitude.initialize({'alt': {'value': 0}, 'baro': {'value': 0}}) self.turnslip = turnslipGauge() self.turnslip.initialize({'turn': {'value': 0}, 'slip': {'value': 0}}) self.dg = dgGauge() self.dg.initialize({'cap': {'value': 0}}) self.vario = varioGauge() self.vario.initialize({'vvi': {'value': 0}}) self.fuel = fuelGauge() self.fuel.initialize({'fuel': {'value': 0}}) self.manifold = manifoldGauge() self.manifold.initialize({'man': {'value': 0}, 'flow': {'value': 0}}) self.vacuum = vacuumGauge() self.vacuum.initialize({'vacuum': {'value': 0}}) self.oil = oilGauge() self.oil.initialize({ 'heat': { 'value': 0, 'max': 250 }, 'psi': { 'value': 0, 'max': 25 } }) self.vor = vorGauge() self.vor.initialize({ 'obs': { 'value': 0 }, 'tofr': { 'value': 1 }, 'dme': { 'value': 0 }, 'hdef': { 'value': 0 }, 'vdef': { 'value': 0 } }) self.adf = adfGauge() self.adf.initialize({ 'frq': { 'value': 0 }, 'card': { 'value': 0 }, 'brg': { 'value': 0 } }) self.engine = engineGauge() self.engine.initialize({'rpm': {'value': 0}}) self.trim = trimGauge() self.trim.initialize({'pitch': {'value': 0}}) self.ident = identPanel() self.debug = fsDebug(self) self.debug.keyPressEvent = self.keyPressEvent self.debug.appendText('debug initiated', 'info') self.debug.appendText('error test', 'error') self.stack = QStackedLayout(self) #print (self.stack.parent.vor.param) for i in range(NUM_LAYOUT): page = QWidget() layout = QGridLayout() page.setLayout(layout) self.stack.addWidget(page) self.setFSLayout(DEFAULT_LAYOUT) self.b = 0 def keyPressEvent(self, event): key = event.key() if (key == Qt.Key_1): self.setFSLayout(1) elif (key == Qt.Key_2): self.setFSLayout(2) elif (key == Qt.Key_3): self.setFSLayout(3) elif (key == Qt.Key_4): self.setFSLayout(4) elif (key == Qt.Key_5): self.b = (self.b + 1) % 2 self.switch.setValue({'power': self.b}) self.light.setValue({'power': self.b}) #self.warn.setValue({'power':self.b,'gene':1,'oil':1,'fuel':1,'gear':1}) elif (key == Qt.Key_D): self.setFSLayout(0) elif (key == Qt.Key_Space): self.setWindowState(self.windowState() ^ Qt.WindowFullScreen) elif (key == Qt.Key_Q): self.close() elif (key == Qt.Key_7): self.setPanel(-1) elif (key == Qt.Key_9): self.setPanel(1) elif (key == Qt.Key_B): self.airspeed.setup({'unit': 'kt'}) elif (key == Qt.Key_N): self.airspeed.setup({'unit': 'kmh'}) elif (key == Qt.Key_C): self.light.setValue({'strobe': 1}) elif (key == Qt.Key_U): self.socket.send("com", "outer", -1) elif (key == Qt.Key_I): self.socket.send("com", "outer", 1) elif (key == Qt.Key_O): self.socket.send("com", "inner", -1) elif (key == Qt.Key_P): self.socket.send("com", "inner", 1) elif (key == Qt.Key_K): self.socket.send("com", "button", 1) elif (key == Qt.Key_L): self.socket.send("nav", "coder", -1) elif (key == Qt.Key_M): self.socket.send("nav", "coder", 1) def setBackground(self, pic): palette = QPalette() pixmap = QPixmap(pic) brush = QBrush(pixmap) palette.setBrush(QPalette.Background, brush) self.setPalette(palette) def setPanel(self, direction): index = (self.activeLayout + direction) % NUM_LAYOUT if (index == 0): index = (index + direction) % NUM_LAYOUT self.setFSLayout(index) def setFSLayout(self, index): self.activeLayout = index #self.stack.setCurrentIndex(index) layout = self.stack.widget(index).layout() populateLayout(self, layout, index) self.stack.setCurrentIndex(index) def setUDPSocket(self, socket): self.socket = socket socket.switch.connect(self.switch.setValue) socket.light.connect(self.light.setValue) socket.warn.connect(self.warn.setValue) socket.radio.connect(self.radio.setValue) socket.airspeed.connect(self.airspeed.setValue) socket.load.connect(self.accelerometer.setValue) socket.attitude.connect(self.attitude.setValue) socket.altitude.connect(self.altitude.setValue) socket.turnslip.connect(self.turnslip.setValue) socket.dg.connect(self.dg.setValue) socket.vario.connect(self.vario.setValue) socket.vacuum.connect(self.vacuum.setValue) socket.flow.connect(self.manifold.setValue) socket.fuel.connect(self.fuel.setValue) socket.oil.connect(self.oil.setValue) socket.vor.connect(self.vor.setValue) socket.adf.connect(self.adf.setValue) socket.engine.connect(self.engine.setValue) socket.trim.connect(self.trim.setValue) socket.magneto.connect(self.magneto.setValue) socket.panel.connect(self.setPanel) socket.debug.connect(self.debug.appendText)
class _MainContainer(QWidget): currentEditorChanged = pyqtSignal("QString") fileOpened = pyqtSignal("QString") fileSaved = pyqtSignal("QString") def __init__(self, parent=None): super().__init__(parent) self.setAcceptDrops(True) self._vbox = QVBoxLayout(self) self._vbox.setContentsMargins(0, 0, 0, 0) self._vbox.setSpacing(0) self.stack = QStackedLayout() self.stack.setStackingMode(QStackedLayout.StackAll) self._vbox.addLayout(self.stack) self.splitter = dynamic_splitter.DynamicSplitter() self._files_handler = files_handler.FilesHandler(self) # Code Navigation self.__operations = { 0: self._navigate_bookmarks } # QML UI self._add_file_folder = add_file_folder.AddFileFolderWidget(self) if settings.SHOW_START_PAGE: self.show_start_page() IDE.register_service("main_container", self) # Register signals connections connections = ( { "target": "main_container", "signal_name": "updateLocator", "slot": self._explore_code }, { "target": "filesystem", "signal_name": "projectOpened", "slot": self._explore_code }, { "target": "projects_explore", "signal_name": "updateLocator", "slot": self._explore_code } ) IDE.register_signals("main_container", connections) esc_sort = QShortcut(QKeySequence(Qt.Key_Escape), self) esc_sort.activated.connect(self._set_focus_to_editor) # Added for set language self._setter_language = set_language.SetLanguageFile() def install(self): ninjaide = IDE.get_service("ide") ninjaide.place_me_on("main_container", self, "central", top=True) self.combo_area = combo_editor.ComboEditor(original=True) self.combo_area.allFilesClosed.connect(self._files_closed) self.splitter.add_widget(self.combo_area) self.add_widget(self.splitter) # self.current_widget = self.combo_area # Code Locator self._code_locator = locator_widget.LocatorWidget(ninjaide) ui_tools.install_shortcuts(self, actions.ACTIONS, ninjaide) def show_files_handler(self): self._files_handler.next_item() def navigate_code_history(self, operation, forward): self.__operations[operation](forward) def _navigate_bookmarks(self, forward=True): current_editor = self.get_current_editor() current_editor.navigate_bookmarks(forward=forward) def _set_focus_to_editor(self): status_bar = IDE.get_service("status_bar") tools_doock = IDE.get_service("tools_dock") editor_widget = self.get_current_editor() if status_bar.isVisible() and tools_doock.isVisible(): status_bar.hide_status_bar() elif tools_doock.isVisible(): tools_doock._hide() elif status_bar.isVisible(): status_bar.hide_status_bar() if editor_widget is not None: editor_widget.clear_extra_selections('searchs') def split_assistance(self): split_widget = split_orientation.SplitOrientation(self) split_widget.show() def show_dialog(self, widget): self.add_widget(widget) self.stack.setCurrentWidget(widget) def show_split(self, orientation_vertical=False): orientation = Qt.Horizontal if orientation_vertical: orientation = Qt.Vertical self.combo_area.split_editor(orientation) def show_locator(self): """Show the Locator Widget""" if not self._code_locator.isVisible(): self._code_locator.show() def _explore_code(self): """Update locator metadata for the current projects""" self._code_locator.explore_code() def current_editor_changed(self, filename): """Notify the new filename of the current editor""" if filename is None: filename = translations.TR_NEW_DOCUMENT self.currentEditorChanged.emit(filename) def get_current_editor(self): current_widget = self.combo_area.current_editor() if isinstance(current_widget, editor.NEditor): return current_widget return None def open_file(self, filename='', line=-1, col=0, ignore_checkers=False): logger.debug("Will try to open %s" % filename) if not filename: logger.debug("Has no filename") if settings.WORKSPACE: directory = settings.WORKSPACE else: directory = os.path.expanduser("~") editor_widget = self.get_current_editor() ninjaide = IDE.get_service("ide") current_project = ninjaide.get_current_project() # TODO: handle current project in NProject if current_project is not None: directory = current_project.full_path elif editor_widget is not None and editor_widget.file_path: directory = file_manager.get_folder( editor_widget.file_path) filenames = QFileDialog.getOpenFileNames( self, "Open File", # FIXME: translations directory, settings.get_supported_extensions_filter() )[0] else: logger.debug("Has filename") filenames = [filename] if not filenames: return for filename in filenames: image_extensions = ("png", "jpg", "jpeg", "bmp", "gif") if file_manager.get_file_extension(filename) in image_extensions: logger.debug("Will open as image") self.open_image(filename) else: logger.debug("Will try to open: %s" % filename) self.__open_file( filename, line, col, ignore_checkers=ignore_checkers) def __open_file(self, filename, line, col, ignore_checkers=False): try: editor_widget = self.add_editor(filename) if line != -1: editor_widget.go_to_line(line, col) self.currentEditorChanged.emit(filename) except file_manager.NinjaIOException as reason: QMessageBox.information( self, "The file couldn't be open", # FIXME: translations str(reason)) logger.error("The file %s couldn't be open" % filename) def open_image(self, filename): for index in range(self.combo_area.stacked.count()): widget = self.combo_area.stacked.widget(index) if isinstance(widget, image_viewer.ImageViewer): if widget.image_filename == filename: logger.debug("Image already open") self.combo_area._set_current(neditable=None, index=index) return viewer = image_viewer.ImageViewer(filename) self.combo_area.add_image_viewer(viewer) self.stack.setCurrentWidget(self.splitter) def save_file(self, editor_widget=None): if editor_widget is None: # This may return None if there is not editor present editor_widget = self.get_current_editor() if editor_widget is None: return False # Ok, we have an editor instance # Save to file only if editor really was modified if editor_widget.is_modified: try: if editor_widget.nfile.is_new_file or \ not editor_widget.nfile.has_write_permission(): return self.save_file_as(editor_widget) # FIXME: beforeFileSaved.emit if settings.REMOVE_TRAILING_SPACES: helpers.remove_trailing_spaces(editor_widget) # FIXME: new line at end if settings.ADD_NEW_LINE_AT_EOF: helpers.insert_block_at_end(editor_widget) # Save content editor_widget.neditable.save_content() # FIXME: encoding # FIXME: translations self.fileSaved.emit("File Saved: %s" % editor_widget.file_path) return True except Exception as reason: logger.error("Save file error: %s" % reason) QMessageBox.information( self, "Save Error", "The file could't be saved!" ) return False def save_file_as(self, editor_widget=None): force = False if editor_widget is None: # We invoque from menu editor_widget = self.get_current_editor() if editor_widget is None: # We haven't editor in main container return False force = True try: filters = "(*.py);;(*.*)" if editor_widget.file_path is not None: # Existing file extension = file_manager.get_file_extension( editor_widget.file_path) if extension != 'py': filters = "(*.%s);;(*.py);;(*.*)" % extension save_folder = self._get_save_folder(editor_widget.file_path) filename = QFileDialog.getSaveFileName( self, "Save File", save_folder, filters )[0] if not filename: return False # FIXME: remove trailing spaces extension = file_manager.get_file_extension(filename) if not extension: filename = "%s.%s" % (filename, "py") editor_widget.neditable.save_content(path=filename, force=force) self._setter_language.set_language_from_extension(extension) self.fileSaved.emit("File Saved: {}".format(filename)) self.currentEditorChanged.emit(filename) return True except file_manager.NinjaFileExistsException as reason: QMessageBox.information( self, "File Already Exists", "Invalid Path: the file '%s' already exists." % reason.filename ) except Exception as reason: logger.error("save_file_as: %s", reason) QMessageBox.information( self, "Save Error", "The file couldn't be saved!" ) return False def save_project(self, project_path): """Save all files in the project path""" for neditable in self.combo_area.bar.get_editables(): file_path = neditable.file_path if file_manager.belongs_to_folder(project_path, file_path): neditable.save_content() def _get_save_folder(self, filename): """Returns the root directory of the 'Main Project' or the home folder""" ninjaide = IDE.get_service("ide") current_project = ninjaide.get_current_project() if current_project is not None: return current_project.path return os.path.expanduser("~") def close_file(self): self.combo_area.close_current_file() def add_editor(self, filename=None): ninjaide = IDE.get_service("ide") editable = ninjaide.get_or_create_editable(filename) if editable.editor: # If already open logger.debug("%s is already open" % filename) self.combo_area.set_current(editable) return self.combo_area.current_editor() else: pass editor_widget = self.create_editor_from_editable(editable) # editor_widget.set_language() # Add the tab keep_index = (self.splitter.count() > 1 and self.combo_area.stacked.count() > 0) self.combo_area.add_editor(editable, keep_index) # Emit a signal about the file open self.fileOpened.emit(filename) if not keep_index: self.combo_area.set_current(editable) self.stack.setCurrentWidget(self.splitter) editor_widget.setFocus() return editor_widget def create_editor_from_editable(self, editable): neditor = editor.create_editor(editable) neditor.zoomChanged.connect(self._show_zoom_indicator) neditor.destroyed.connect(self.__on_editor_destroyed) # editable.fileSaved.connect(self._editor_tab) return neditor def _show_zoom_indicator(self, zoom): neditor = self.get_current_editor() indicator.Indicator.show_text( neditor, "Zoom: {} %".format(str(zoom))) @pyqtSlot() def __on_editor_destroyed(self): indicator.Indicator.instance = None def add_widget(self, widget): self.stack.addWidget(widget) def show_start_page(self): """Show Start Page widget in main container""" startp = self.stack.widget(0) if isinstance(startp, start_page.StartPage): self.stack.setCurrentIndex(0) else: startp = start_page.StartPage(parent=self) startp.newFile.connect(self.add_editor) self.stack.insertWidget(0, startp) self.stack.setCurrentIndex(0) def _files_closed(self): if settings.SHOW_START_PAGE: self.show_start_page() def add_status_bar(self, status_bar): self._vbox.addWidget(status_bar) def create_file(self, base_path, project_path): self._add_file_folder.create_file(base_path, project_path) def create_folder(self, base_path, project_path): self._add_file_folder.create_folder(base_path, project_path) def zoom_in_editor(self): """Increase the font size in the current editor""" editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.zoom(1.) def zoom_out_editor(self): """Decrease the font size in the current editor""" editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.zoom(-1.) def reset_zoom_editor(self): """Reset the to original font size in the current editor""" editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.reset_zoom() def editor_move_up(self): editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.move_up_down(up=True) def editor_move_down(self): editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.move_up_down() def editor_duplicate_line(self): editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.duplicate_line() def editor_comment(self): """Mark the current line or selection as a comment.""" editor_widget = self.get_current_editor() if editor_widget is not None: helpers.comment_or_uncomment(editor_widget) def editor_go_to_line(self, line): editor_widget = self.get_current_editor() if editor_widget is not None: editor_widget.go_to_line(line) editor_widget.setFocus() def _editor_settings_changed(self, key, value): key = key.split("/")[-1] editor_widget = self.get_current_editor() if editor_widget is not None: callback = getattr(editor.NEditor, key, False) if callback: callback = callback if not hasattr(callback, "__call__"): # Property! callback = callback.fset callback(editor_widget, value) def toggle_tabs_and_spaces(self): """Toggle Show/Hide Tabs and Spaces""" settings.SHOW_TABS_AND_SPACES = not settings.SHOW_TABS_AND_SPACES qsettings = IDE.ninja_settings() qsettings.setValue('preferences/editor/showTabsAndSpaces', settings.SHOW_TABS_AND_SPACES) neditor = self.get_current_editor() if neditor is not None: neditor.show_whitespaces = settings.SHOW_TABS_AND_SPACES
class ComboEditor(ui_tools.StyledBar): # Signals closeSplit = pyqtSignal('PyQt_PyObject') splitEditor = pyqtSignal('PyQt_PyObject', 'PyQt_PyObject', bool) allFilesClosed = pyqtSignal() about_to_close_combo_editor = pyqtSignal() def __init__(self, original=False): super(ComboEditor, self).__init__(None) self.__original = original self.__undocked = [] self._symbols_index = [] vbox = QVBoxLayout(self) vbox.setContentsMargins(0, 0, 0, 0) vbox.setSpacing(0) self.bar = ActionBar(main_combo=original) vbox.addWidget(self.bar) # Info bar self.info_bar = InfoBar(self) self.info_bar.setVisible(False) vbox.addWidget(self.info_bar) self.stacked = QStackedLayout() vbox.addLayout(self.stacked) self._main_container = IDE.get_service('main_container') if not self.__original: self._main_container.fileOpened['QString'].connect( self._file_opened_by_main) # self.bar.combo.showComboSelector.connect( # lambda: self._main_container.change_tab()) self.bar.change_current['PyQt_PyObject', int].connect(self._set_current) self.bar.splitEditor[bool].connect(self.split_editor) self.bar.runFile['QString'].connect(self._run_file) self.bar.closeSplit.connect(lambda: self.closeSplit.emit(self)) self.bar.addToProject['QString'].connect(self._add_to_project) self.bar.showFileInExplorer['QString'].connect( self._show_file_in_explorer) self.bar.goToSymbol[int].connect(self._go_to_symbol) self.bar.undockEditor.connect(self.undock_editor) self.bar.reopenTab['QString'].connect( lambda path: self._main_container.open_file(path)) # self.connect(self.bar, SIGNAL("recentTabsModified()"), # lambda: self._main_container.recent_files_changed()) # self.connect(self.bar.code_navigator.btnPrevious, SIGNAL("clicked()"), # lambda: self._navigate_code(False)) # self.connect(self.bar.code_navigator.btnNext, SIGNAL("clicked()"), # lambda: self._navigate_code(True)) # def _navigate_code(self, val): # op = self.bar.code_navigator.operation # self._main_container.navigate_code_history(val, op) def currentWidget(self): return self.stacked.currentWidget() def setFocus(self): super(ComboEditor, self).setFocus() self.stacked.currentWidget().setFocus() self._editor_with_focus() def _file_opened_by_main(self, path): index = self.stacked.currentIndex() ninjaide = IDE.get_service('ide') editable = ninjaide.get_or_create_editable(path) self.add_editor(editable) self.bar.set_current_by_index(index) if index == -1: self.bar.set_current_by_index(0) def add_editor(self, neditable, keep_index=False): """Add Editor Widget to the UI area.""" if neditable.editor: if self.__original: editor = neditable.editor else: # editor = neditable.editor.clone() editor = self._main_container.create_editor_from_editable( neditable) current_index = self.stacked.currentIndex() new_index = self.stacked.addWidget(editor) self.stacked.setCurrentIndex(new_index) self.bar.add_item(neditable.display_name, neditable) # Bar is not visible because all the files have been closed, # so if a new file is opened, show the bar if not self.bar.isVisible(): self.bar.setVisible(True) if keep_index: self.bar.set_current_by_index(current_index) # Connections neditable.fileClosing.connect(self._close_file) editor.editorFocusObtained.connect(self._editor_with_focus) editor.modificationChanged.connect(self._editor_modified) neditable.checkersUpdated.connect(self._show_notification_icon) # Connect file system signals only in the original if self.__original: neditable.askForSaveFileClosing.connect(self._ask_for_save) neditable.fileChanged.connect(self._file_has_been_modified) # Editor Signals editor.cursor_position_changed[int, int].connect( self._update_cursor_position) editor.current_line_changed[int].connect(self._set_current_symbol) """ # self.connect(editor, SIGNAL("editorFocusObtained()"), # self._editor_with_focus) editor.editorFocusObtained.connect(self._editor_with_focus) neditable.fileSaved['PyQt_PyObject'].connect( self._update_combo_info) neditable.fileSaved['PyQt_PyObject'].connect( self._update_symbols) editor.modificationChanged[bool].connect(self._editor_modified) neditable.checkersUpdated.connect(self._show_notification_icon) # Connect file system signals only in the original neditable.fileClosing['PyQt_PyObject'].connect(self._close_file) if self.__original: neditable.askForSaveFileClosing['PyQt_PyObject'].connect( self._ask_for_save) neditable.fileChanged['PyQt_PyObject'].connect( self._file_has_been_modified) self.info_bar.reloadClicked.connect(neditable.reload_file) # Load Symbols self._load_symbols(neditable) """ def show_combo_file(self): self.bar.combo.showPopup() def show_combo_symbol(self): self.bar.symbols_combo.showPopup() def unlink_editors(self): for index in range(self.stacked.count()): widget = self.stacked.widget(index) # widget.setDocument(QsciDocument()) def split_editor(self, orientation_vertical): new_widget = ComboEditor() for neditable in self.bar.get_editables(): new_widget.add_editor(neditable) self.splitEditor.emit(self, new_widget, orientation_vertical) # for neditable in self.bar.get_editables(): # new_widget.add_editor(neditable) # self.splitEditor.emit(self, new_widget, orientationVertical) # self.emit(SIGNAL("splitEditor(PyQt_PyObject, PyQt_PyObject, bool)"), # self, new_widget, orientationVertical) def undock_editor(self): new_combo = ComboEditor() new_combo.setWindowTitle("NINJA-IDE") editor = self.currentWidget() new_combo.add_editor(editor.neditable) new_combo.show() """ for neditable in self.bar.get_editables(): new_combo.add_editor(neditable) neditor = self.currentWidget().clone() new_combo.set_current(neditor.neditable) new_combo.resize(700, 500) new_combo.about_to_close_combo_editor.connect(self._remove_undock) new_combo.show() """ def _remove_undock(self): widget = self.sender() self.__undocked.remove(widget) def close_current_file(self): self.bar.about_to_close_file() def _close_file(self, neditable): index = self.bar.close_file(neditable) print(index) layoutItem = self.stacked.takeAt(index) # neditable.editor.completer.cc.unload_module() self._add_to_last_opened(neditable.file_path) layoutItem.widget().deleteLater() if self.stacked.isEmpty(): self.bar.hide() self.allFilesClosed.emit() def _add_to_last_opened(self, path): if path not in settings.LAST_OPENED_FILES: settings.LAST_OPENED_FILES.append(path) if len(settings.LAST_OPENED_FILES) > settings.MAX_REMEMBER_TABS: self.__lastOpened = self.__lastOpened[1:] print("RecentTabsModified") # self.emit(SIGNAL("recentTabsModified()")) def _editor_with_focus(self): if self._main_container.current_widget is not self: self._main_container.current_widget = self editor = self.stacked.currentWidget() self._main_container.current_editor_changed( editor.neditable.file_path) self._load_symbols(editor.neditable) editor.neditable.update_checkers_display() def _ask_for_save(self, neditable): val = QMessageBox.No fileName = neditable.nfile.file_name val = QMessageBox.question( self, (self.tr('The file %s was not saved') % fileName), self.tr("Do you want to save before closing?"), QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel) if val == QMessageBox.No: neditable.nfile.close(force_close=True) elif val == QMessageBox.Yes: neditable.ignore_checkers = True self._main_container.save_file(neditable.editor) neditable.nfile.close() def _file_has_been_modified(self, neditable): self.info_bar.show_message(translations.TR_FILE_MODIFIED_OUTSIDE) # val = QMessageBox.No # fileName = neditable.file_path # val = QMessageBox.question( # self, translations.TR_FILE_HAS_BEEN_MODIFIED, # "%s%s" % (fileName, translations.TR_FILE_MODIFIED_OUTSIDE), # QMessageBox.Yes | QMessageBox.No) # if val == QMessageBox.Yes: # neditable.reload_file() def _run_file(self, path): self._main_container.run_file(path) def _add_to_project(self, path): self._main_container._add_to_project(path) def _show_file_in_explorer(self, path): '''Connected to ActionBar's showFileInExplorer(QString) signal, forwards the file path on to the main container.''' self._main_container._show_file_in_explorer(path) def set_current(self, neditable): if neditable: self.bar.set_current_file(neditable) def _set_current(self, neditable, index): if neditable: self.stacked.setCurrentIndex(index) editor = self.stacked.currentWidget() self._update_cursor_position(ignore_sender=True) editor.setFocus() self._main_container.current_editor_changed(neditable.file_path) self._load_symbols(neditable) # self._show_file_in_explorer(neditable.file_path) neditable.update_checkers_display() def widget(self, index): return self.stacked.widget(index) def count(self): """Return the number of editors opened.""" return self.stacked.count() def _update_cursor_position(self, line=0, col=0, ignore_sender=False): obj = self.sender() editor = self.stacked.currentWidget() # Check if it's current to avoid signals from other splits. if ignore_sender or editor == obj: line += 1 self.bar.update_line_col(line, col) def _set_current_symbol(self, line, ignore_sender=False): obj = self.sender() editor = self.stacked.currentWidget() # Check if it's current to avoid signals from other splits. if ignore_sender or editor == obj: index = bisect.bisect(self._symbols_index, line) if (index >= len(self._symbols_index) or self._symbols_index[index] > (line + 1)): index -= 1 self.bar.set_current_symbol(index) def _editor_modified(self, value): obj = self.sender() neditable = obj.neditable if value: text = "\u2022 %s" % neditable.display_name self.bar.update_item_text(neditable, text) else: self.bar.update_item_text(neditable, neditable.display_name) def _go_to_symbol(self, index): # FIXME: index 0 invalid line = self._symbols_index[index] editor = self.stacked.currentWidget() editor.go_to_line(line) def _update_symbols(self, neditable): editor = self.stacked.currentWidget() # Check if it's current to avoid signals from other splits. if editor == neditable.editor: self._load_symbols(neditable) def _update_combo_info(self, neditable): self.bar.update_item_text(neditable, neditable.display_name) self._main_container.current_editor_changed(neditable.file_path) def _load_symbols(self, neditable): symbols_handler = handlers.get_symbols_handler('py') source = neditable.editor.text source = source.encode(neditable.editor.encoding) symbols, symbols_simplified = symbols_handler.obtain_symbols( source, simple=True) self._symbols_index = sorted(symbols_simplified.keys()) symbols_simplified = sorted(list(symbols_simplified.items()), key=lambda x: x[0]) self.bar.add_symbols(symbols_simplified) line, _ = neditable.editor.cursor_position self._set_current_symbol(line, True) tree_symbols = IDE.get_service('symbols_explorer') tree_symbols.update_symbols_tree(symbols, neditable.file_path) def _show_notification_icon(self, neditable): checkers = neditable.sorted_checkers icon = QIcon() for items in checkers: checker, color, _ = items if checker.checks: if isinstance(checker.checker_icon, int): icon = self.style().standardIcon(checker.checker_icon) elif isinstance(checker.checker_icon, str): icon = QIcon(checker.checker_icon) # FIXME: sucks else: icon = QIcon(checker.checker_icon) break self.bar.update_item_icon(neditable, icon) def show_menu_navigation(self): self.bar.code_navigator.show_menu_navigation() def closeEvent(self, event): self.about_to_close_combo_editor.emit() # self.emit(SIGNAL("aboutToCloseComboEditor()")) super(ComboEditor, self).closeEvent(event) def reject(self): if not self.__original: super(ComboEditor, self).reject()
class SelectorWindow(CommonWindow): """Selector window""" statustext = '' timer = QTimer() def __init__(self): super().__init__() self.setWindowTitle("Selector") self.globalfont = QFont() self.fontcolor = settings.config['font.color'] self.fontstylesheet = 'color: ' + self.fontcolor + ';' self.nosingerimage = QPixmap(settings.themeDir + 'default_singer.jpg') self.timer.timeout.connect(self.setOldStatusText) self.createLayout() geo = list(map(int, settings.config['selector.window'].split(','))) if settings.config.getboolean('selector.frameless'): self.setWindowFlag(Qt.FramelessWindowHint) self.move(geo[0], geo[1]) self.show() self.resize(geo[2], geo[3]) if settings.config.getboolean('selector.fullscreen'): self.setWindowState(Qt.WindowFullScreen) def createLayout(self): # background image self.bglabel = QLabel() self.bglabel.setScaledContents(True) self.bglabel.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) self.bglabel.setPixmap(QPixmap(settings.themeDir + 'selector.jpg')) self.bglayout = setZeroMargins(QHBoxLayout(self)) self.bglayout.addWidget(self.bglabel) # create the vertical frame self.vlayout = setZeroMargins(QVBoxLayout(self.bglabel)) # create the header toolbar self.headerlayout = setZeroMargins(QHBoxLayout()) self.headeroption = [] self.homeoption = QLabelButton() self.homeoption.clicked.connect(screen.startHomeScreen) self.homeoption.setScaledContents(True) self.homeoption.setPixmap( QPixmap(settings.themeDir + 'buttons/home.png')) self.headeroption.append(self.homeoption) self.backoption = QLabelButton() self.backoption.setScaledContents(True) self.backoption.setPixmap( QPixmap(settings.themeDir + 'buttons/arrow-left.png')) self.headeroption.append(self.backoption) self.switchchannel = QLabelButton() self.switchchannel.clicked.connect(playlist.switchChannel) self.switchchannel.setScaledContents(True) self.switchchannel.setPixmap( QPixmap(settings.themeDir + 'buttons/music.png')) self.headeroption.append(self.switchchannel) self.playnextsong = QLabelButton() self.playnextsong.clicked.connect(playlist.playNextSong) self.playnextsong.setScaledContents(True) self.playnextsong.setPixmap( QPixmap(settings.themeDir + 'buttons/step-forward.png')) self.headeroption.append(self.playnextsong) self.pitchup = QLabelButton() self.pitchup.clicked.connect(playlist.setPitchUp) self.pitchup.setText('♭') self.headeroption.append(self.pitchup) self.pitchflat = QLabelButton() self.pitchflat.clicked.connect(playlist.setPitchFlat) self.pitchflat.setText('♮') self.headeroption.append(self.pitchflat) self.pitchdown = QLabelButton() self.pitchdown.clicked.connect(playlist.setPitchDown) self.pitchdown.setText('♯') self.headeroption.append(self.pitchdown) for opt in self.headeroption: opt.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) opt.setAlignment(Qt.AlignCenter) opt.setStyleSheet( 'color: white; font-weight: 800; border-radius: 3px; background-color: rgba(120, 120, 120, 40);' ) self.headerlayout.addStretch(2) self.headerlayout.addWidget(self.homeoption, 4) self.headerlayout.addStretch(2) self.headerlayout.addWidget(self.backoption, 4) self.headerlayout.addStretch(100) self.headerlayout.addWidget(self.playnextsong, 4) self.headerlayout.addStretch(2) self.headerlayout.addWidget(self.switchchannel, 4) self.headerlayout.addStretch(5) self.headerlayout.addWidget(self.pitchup, 4) self.headerlayout.addStretch(2) self.headerlayout.addWidget(self.pitchflat, 4) self.headerlayout.addStretch(2) self.headerlayout.addWidget(self.pitchdown, 4) self.headerlayout.addStretch(2) # create the function buttons self.functionlayout = setZeroMargins(QHBoxLayout()) self.functionoption = [] self.functionlayout.addStretch(30) for i in range(4): self.functionoption.append(QLabelListButton()) self.functionoption[i].setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) self.functionoption[i].setLabelText('F' + str(i + 1)) self.functionoption[i].index = "F" + str(i + 1) self.functionlayout.addWidget(self.functionoption[i], 100) self.functionlayout.addStretch(20) self.functionlayout.addStretch(10) # create the content area, with 2 stacks self.contentoption = [[], []] self.contentlayout = [] self.stackedlayout = QStackedLayout() for i in range(2): self.stackedlayout.addWidget(QLabel()) # create 1st page of content (10 options vertically align) self.vcontentlayout1 = setZeroMargins( QHBoxLayout(self.stackedlayout.widget(0))) self.contentlayout.append(setZeroMargins(QVBoxLayout())) for i in range(10): btn = QLabelListButton() self.contentoption[0].append(btn) btn.setLabelText(str((i + 1) % 10)) btn.index = i self.contentlayout[0].addWidget(btn) self.vcontentlayout1.addStretch(1) self.vcontentlayout1.addLayout(self.contentlayout[0], 10) self.vcontentlayout1.addStretch(1) # create 2nd page of content (10 image options in 5x2) self.vcontentlayout2 = setZeroMargins( QHBoxLayout(self.stackedlayout.widget(1))) self.contentlayout.append( setZeroMargins(QGridLayout(self.stackedlayout.widget(1)))) for i in range(10): btn = QLabeImageButton() self.contentoption[1].append(btn) btn.setLabelText(str((i + 1) % 10)) btn.index = i self.contentlayout[1].addWidget(btn, i / 5, i % 5) self.vcontentlayout2.addStretch(1) self.vcontentlayout2.addLayout(self.contentlayout[1], 15) self.vcontentlayout2.addStretch(1) self.stackedlayout.setCurrentIndex(1) # create footer self.footerlayout = setZeroMargins(QHBoxLayout()) self.pageroption = QLabel() self.pageroption.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) self.pageroption.setStyleSheet(self.fontstylesheet) self.pageroption.setAlignment(Qt.AlignCenter) #pageup/pagedown self.footeroption = [QLabelButton(), QLabelButton()] for opt in self.footeroption: opt.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) opt.setAlignment(Qt.AlignCenter) opt.setStyleSheet(self.fontstylesheet) self.footerlayout.addStretch(50) self.footerlayout.addWidget(self.footeroption[0], 10) self.footerlayout.addStretch(10) self.footerlayout.addWidget(self.pageroption, 20) self.footerlayout.addStretch(10) self.footerlayout.addWidget(self.footeroption[1], 10) self.footerlayout.addStretch(50) # status bar self.statusframe = QMarquee() self.statusframe.setFontColor(self.fontcolor) # add contents to vlayout self.vlayout.addStretch(3) self.vlayout.addLayout(self.headerlayout, 12) self.vlayout.addStretch(10) self.vlayout.addLayout(self.functionlayout, 15) self.vlayout.addStretch(5) self.vlayout.addLayout(self.stackedlayout, 200) self.vlayout.addStretch(5) self.vlayout.addLayout(self.footerlayout, 15) self.vlayout.addStretch(10) self.vlayout.addWidget(self.statusframe, 20) # done self.createSearchLayout() def setTextSize(self): """resize text size to label height""" self.globalfont.setPixelSize(self.headeroption[0].size().height()) for option in self.headeroption: option.setFont(self.globalfont) self.globalfont.setPixelSize(self.functionoption[0].size().height() * 0.7) for option in self.functionoption: option.setFont(self.globalfont) self.contentlayout[0].setSpacing(self.size().height() * 0.01) self.contentlayout[1].setSpacing(self.size().height() * 0.03) self.globalfont.setPixelSize(self.contentoption[0][0].size().height() * 0.4) for option in self.contentoption[0]: option.setFont(self.globalfont) self.globalfont.setPixelSize(self.pageroption.size().height() * 0.7) self.pageroption.setFont(self.globalfont) for option in self.footeroption: option.setFont(self.globalfont) self.statusframe.setPixelSize(self.statusframe.size().height() * 0.7) if self.searchbg.isVisible(): self.setSearchTextSize() """ search functions """ insearch = False numstylesheet = '<span style="color:#999999">' search_display = { 0: [[ 'EN', ('1', 'ABC2', 'DEF3', 'GHI4', 'JKL5', 'MNO6', 'PQRS7', 'TUV8', 'WXYZ9', '0') ], [ 'JP', (numstylesheet + '1:</span> あ', numstylesheet + '2:</span> か', numstylesheet + '3:</span> さ', numstylesheet + '4:</span> た', numstylesheet + '5:</span> な', numstylesheet + '6:</span> は', numstylesheet + '7:</span> ま', numstylesheet + '8:</span> や', numstylesheet + '9:</span> ら', numstylesheet + '0:</span> わ') ], [ 'KR', (numstylesheet + '1:</span> ㅣ', numstylesheet + '2:</span> ㆍ', numstylesheet + '3:</span> ㅡ', numstylesheet + '4:</span> ㄱㅋ', numstylesheet + '5:</span> ㄴㄹ', numstylesheet + '6:</span> ㄷㅌ', numstylesheet + '7:</span> ㅂㅍ', numstylesheet + '8:</span> ㅅㅎ', numstylesheet + '9:</span> ㅈㅊ', numstylesheet + '0:</span> ㅇㅁ') ]], 1: [['NUM', ('1', '2', '3', '4', '5', '6', '7', '8', '9', '0')]] } search_keyboard = { 0: [[ 'EN', ('1', 'ABC2', 'DEF3', 'GHI4', 'JKL5', 'MNO6', 'PQRS7', 'TUV8', 'WXYZ9', '0') ], [ 'JP', ('あいうえおぁぃぅぇぉ', 'かきくけこ', 'さしすせそ', 'たちつてとっ', 'なにぬねの', 'はひふへほ', 'まみむめも', 'やゆよゃゅょ', 'らりるれろ', 'わゐゑを') ], ['KR', ('', '', '', 'ㄱㅋㄲ', 'ㄴㄹ', 'ㄷㅌㄸ', 'ㅂㅍㅃ', 'ㅅㅎㅆ', 'ㅈㅊㅉ', 'ㅇㅁ')]], 1: [['NUM', ('1', '2', '3', '4', '5', '6', '7', '8', '9', '0')]] } searchtype = 0 searchindex = 0 searchlastkey = [-1, 0] searchstring = '' searchthreshold = 2 searchtimer = QTimer() searchcallback = None search_hangul = Hangul() def createSearchLayout(self): fontstylesheet = self.fontstylesheet btnstylesheet='color: white; border-radius: 5px;' + \ 'background-color: qradialgradient(spread:pad, cx:0.272, cy:0.354515, radius:0.848, fx:0.071, fy:0.199045, stop:0 rgba(130, 130, 130, 255), stop:0.2 rgba(101, 101, 101, 255), stop:1 rgba(27, 27, 27, 170));' + \ 'border: 1px solid #858585;border-right: 1px solid #414141;border-bottom: solid 3px #414141;' self.searchbg = QLabel(self) self.searchbg.setCursor(Qt.WaitCursor) self.searchbglayout = setZeroMargins(QGridLayout(self.searchbg)) self.searchframe = QLabel() self.searchframe.setScaledContents(True) self.searchframe.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) self.searchimage = QPixmap(settings.themeDir + "search.jpg") self.searchframe.setCursor(Qt.ArrowCursor) self.searchframe.setPixmap(self.searchimage) self.searchbglayout.addWidget(QWidget(), 0, 1) self.searchbglayout.addWidget(QWidget(), 1, 0) self.searchbglayout.addWidget(QWidget(), 2, 1) self.searchbglayout.addWidget(QWidget(), 3, 0) self.searchbglayout.addWidget(self.searchframe, 1, 1) self.searchbglayout.setColumnStretch(0, 70) self.searchbglayout.setColumnStretch(1, 40) self.searchbglayout.setColumnStretch(2, 1) self.searchbglayout.setRowStretch(0, 3) self.searchbglayout.setRowStretch(1, 4) self.searchbglayout.setRowStretch(2, 1) self.searchlayout = QGridLayout(self.searchframe) self.searchlayout.setSpacing(10) # title self.searchtitle = QLabel() self.searchtitle.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) self.searchtitle.setStyleSheet(fontstylesheet + ';font:bold;') self.searchtitle.setText(_("Search character:")) self.searchlayout.addWidget(self.searchtitle, 0, 0, 1, 2) # F1 to F4 f_text = (_('F1: Ok'), _('F2: Del'), _('F3: Cancel'), _('F4: 🌐')) self.searchfunctionoption = [] #create a filler "F4" for i in range(4): self.searchfunctionoption.append(QLabelButton()) self.searchfunctionoption[i].setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) self.searchfunctionoption[i].setText(f_text[i]) self.searchfunctionoption[i].setStyleSheet(btnstylesheet) self.searchfunctionoption[i].setAlignment(Qt.AlignCenter) self.searchfunctionoption[i].index = "F" + str(i + 1) self.searchfunctionoption[i].clicked.connect( self.searchButtonPressedFunction) for i in range(3): self.searchlayout.addWidget(self.searchfunctionoption[i], 1, i) self.searchlayout.addWidget(self.searchfunctionoption[3], 0, 2) # display text self.searchlabel = QLabel() self.searchlabel.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) self.searchlabel.setStyleSheet( fontstylesheet + "; padding: 0 10%; border: 1px solid blue;") self.searchlabel.setStyleSheet( self.fontstylesheet + 'border: 3px solid black; border-radius: 5px; background-color: qlineargradient(spread:pad, x1:0, x2:1, stop:0 rgba(0, 0, 0, 200), stop:1 rgba(120, 120, 120, 100));padding: 0px 10%;' ) self.searchlayout.addWidget(self.searchlabel, 2, 0, 1, 3) # 0 -9 self.searchcontentoption = [] for i in range(10): self.searchcontentoption.append(QLabelButton()) self.searchcontentoption[i].setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) self.searchcontentoption[i].setStyleSheet(btnstylesheet) self.searchcontentoption[i].setAlignment(Qt.AlignCenter) self.searchcontentoption[i].index = i self.searchcontentoption[i].clicked.connect( self.searchButtonPressedNumber) for i in range(9): self.searchlayout.addWidget(self.searchcontentoption[i], 3 + i / 3, i % 3) self.searchlayout.addWidget(self.searchcontentoption[9], 6, 1) # backspace self.searchbackspaceoption = QLabelButton() self.searchbackspaceoption.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) self.searchbackspaceoption.setStyleSheet(btnstylesheet) self.searchbackspaceoption.setAlignment(Qt.AlignCenter) self.searchbackspaceoption.setText("🡄") self.searchbackspaceoption.clicked.connect( self.searchButtonPressedBackspace) # self.searchlayout.addWidget(self.searchbackspaceoption, 6, 0) # enter self.searchenteroption = QLabelButton() self.searchenteroption.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) self.searchenteroption.setStyleSheet(btnstylesheet) self.searchenteroption.setAlignment(Qt.AlignCenter) self.searchenteroption.setText("[Enter]") self.searchenteroption.clicked.connect(self.searchButtonPressedEnter) # self.searchlayout.addWidget(self.searchenteroption, 6, 2) self.searchbg.hide() self.searchtimer.setSingleShot(True) self.searchtimer.setInterval(self.searchthreshold * 1000) self.searchtimer.timeout.connect(self.searchButtonPressedTimeout) def setSearchTextSize(self): self.globalfont.setPixelSize( self.searchfunctionoption[0].size().height() * 0.7) for option in self.searchfunctionoption: option.setFont(self.globalfont) self.globalfont.setPixelSize( self.searchcontentoption[0].size().height() * 0.7) for option in self.searchcontentoption: option.setFont(self.globalfont) self.searchbackspaceoption.setFont(self.globalfont) self.searchenteroption.setFont(self.globalfont) self.globalfont.setPixelSize(self.searchtitle.size().height() * 0.9) self.searchtitle.setFont(self.globalfont) self.globalfont.setPixelSize(self.searchlabel.size().height() * 0.7) self.searchlabel.setFont(self.globalfont) def setSearchPos(self): if self.searchbg.isVisible(): self.searchbg.setFixedSize(self.width(), self.height()) def displaySearchNumbers(self): for i in range(10): self.searchcontentoption[i].setText( self.search_display[self.searchtype][self.searchindex][1][i]) def startSearch(self, searchtype=0): """display the search bar searchtype: 0=alphanumeric 1=numbers only """ self.insearch = True self.searchstring = '' self.searchtype = searchtype self.searchindex = 0 self.search_hangul = Hangul() if len(self.search_keyboard[self.searchtype]) > 1: self.searchfunctionoption[3].show() else: self.searchfunctionoption[3].hide() self.displaySearchNumbers() self.searchbg.show() self.setSearchPos() self.setSearchTextSize() self.searchTextDisplay() self.callSearchCallback() def stopSearch(self): self.insearch = False self.searchbg.hide() def searchGetFinalString(self): searchstring = self.searchstring if self.searchlastkey[0] == -2: searchstring += self.search_hangul.getHangul() elif 0 <= self.searchlastkey[0] < 10: searchstring += self.search_keyboard[self.searchtype][ self.searchindex][1][self.searchlastkey[0]][ self.searchlastkey[1]] return searchstring def setSearchCallback(self, callback): self.searchcallback = callback def callSearchCallback(self): if callable(self.searchcallback): self.searchcallback(self.searchGetFinalString()) def searchTextDisplay(self): searchstring = ' '.join(self.searchGetFinalString()) if self.searchlastkey[0] != -1: searchstring = searchstring[: -1] + '<font color="cyan">' + searchstring[ -1] + '</font>' self.searchlabel.setText(searchstring) @pyqtSlot(object) def searchKeyPressedAlpha(self, char): #A to Z only if 65 <= ord(char[0]) <= 90: self.searchButtonPressedTimeout() self.searchstring += char[0] self.searchTextDisplay() self.callSearchCallback() def searchKoreanNumber(self, index): self.searchlastkey = [-2, 0] if 0 <= index <= 2: # Vowels if self.search_hangul.step == 2: self.searchstring += self.search_hangul.getHangul(1) self.search_hangul.chosung = self.search_hangul.jongsung self.search_hangul.jungsung = self.search_hangul.jongsung = self.search_hangul.jongsung2 = "" elif self.search_hangul.step == 3: self.searchstring += self.search_hangul.getHangul(2) self.search_hangul.chosung = self.search_hangul.jongsung2 self.search_hangul.jungsung = self.search_hangul.jongsung = self.search_hangul.jongsung2 = "" beforedata = self.search_hangul.jungsung self.search_hangul.step = 1 self.search_hangul.searchlastkey = [-1, 0] if index == 0: # ㅣ ㅓ ㅕ ㅐ ㅔ ㅖ ㅒ ㅚ ㅟ ㅙ ㅝ ㅞ ㅢ if beforedata == "ㆍ": nowdata = "ㅓ" elif beforedata == ":": nowdata = "ㅕ" elif beforedata == "ㅏ": nowdata = "ㅐ" elif beforedata == "ㅑ": nowdata = "ㅒ" elif beforedata == "ㅓ": nowdata = "ㅔ" elif beforedata == "ㅕ": nowdata = "ㅖ" elif beforedata == "ㅗ": nowdata = "ㅚ" elif beforedata == "ㅜ": nowdata = "ㅟ" elif beforedata == "ㅠ": nowdata = "ㅝ" elif beforedata == "ㅘ": nowdata = "ㅙ" elif beforedata == "ㅝ": nowdata = "ㅞ" elif beforedata == "ㅡ": nowdata = "ㅢ" else: nowdata = "ㅣ" elif index == 1: # ㆍ : ㅏ ㅑ ㅜ ㅠ ㅘ if beforedata == "ㆍ": nowdata = ":" elif beforedata == ":": nowdata = "ㆍ" elif beforedata == "ㅣ": nowdata = "ㅏ" elif beforedata == "ㅏ": nowdata = "ㅑ" elif beforedata == "ㅡ": nowdata = "ㅜ" elif beforedata == "ㅜ": nowdata = "ㅠ" elif beforedata == "ㅚ": nowdata = "ㅘ" else: nowdata = "ㆍ" elif index == 2: # ㅡ ㅗ ㅛ if beforedata == "ㆍ": nowdata = "ㅗ" elif beforedata == ":": nowdata = "ㅛ" else: nowdata = "ㅡ" self.search_hangul.jungsung = nowdata elif 3 <= index <= 9: # Consonants if self.search_hangul.step == 1: if self.search_hangul.jungsung == "ㆍ" or self.search_hangul.jungsung == ":": self.search_hangul = Hangul() else: self.search_hangul.step = 2 if index == self.search_hangul.searchlastkey[0]: self.search_hangul.searchlastkey[1] = ( self.search_hangul.searchlastkey[1] + 1) % len( self.search_keyboard[self.searchtype][ self.searchindex][1][index]) else: self.search_hangul.searchlastkey = [index, 0] if self.search_hangul.step == 2 and self.search_hangul.jongsung: self.search_hangul.step = 3 elif self.search_hangul.step == 3: self.searchstring += self.search_hangul.getHangul() self.search_hangul = Hangul() nowdata = self.search_keyboard[self.searchtype][self.searchindex][ 1][index][self.search_hangul.searchlastkey[1]] if self.search_hangul.step == 0: self.search_hangul.chosung = nowdata elif self.search_hangul.step == 2: self.search_hangul.jongsung = nowdata elif self.search_hangul.step == 3: self.search_hangul.jongsung2 = nowdata def searchFindFromKeyboard(self, index): if 0 <= index < 10: if len(self.search_keyboard[self.searchtype][self.searchindex][1] [index]) == 1: self.searchstring += str(self.search_keyboard[self.searchtype][ self.searchindex][1][index]) else: if index == self.searchlastkey[0]: self.searchlastkey[1] = (self.searchlastkey[1] + 1) % len( self.search_keyboard[self.searchtype][ self.searchindex][1][index]) else: if self.searchlastkey[0] != -1: self.searchstring = self.searchGetJoinString() self.searchlastkey = [index, 0, ''] @pyqtSlot(object) def searchButtonPressedNumber(self, index): try: self.searchtimer.stop() if self.search_keyboard[self.searchtype][ self.searchindex][0] == 'KR': self.searchKoreanNumber(index) else: self.searchFindFromKeyboard(index) self.searchtimer.start() except: settings.logger.printException() self.searchTextDisplay() self.callSearchCallback() @pyqtSlot() def searchButtonPressedTimeout(self): self.searchtimer.stop() if self.searchlastkey[0] != -1: self.searchstring = self.searchGetFinalString() self.searchlastkey = [-1, 0, ''] self.search_hangul = Hangul() self.searchTextDisplay() @pyqtSlot(object) def searchButtonPressedFunction(self, index): if index == 'F1': self.searchenteroption.click() elif index == 'F2': self.searchbackspaceoption.click() elif index == 'F3': self.searchstring = '' self.searchlastkey = [-1, 0, ''] self.searchenteroption.click() elif index == 'F4': self.searchButtonPressedTimeout() self.searchindex = (self.searchindex + 1) % len( self.search_keyboard[self.searchtype]) self.displaySearchNumbers() @pyqtSlot(object) def searchButtonPressedBackspace(self, index): self.searchtimer.stop() if self.searchlastkey[0] == -2: if self.search_hangul.step == 0: self.search_hangul = Hangul() self.searchlastkey = [-1, 0] else: self.search_hangul.step -= 1 self.search_hangul.searchlastkey = [-1, 0] if self.search_hangul.step <= 2: self.search_hangul.jongsung2 = '' if self.search_hangul.step <= 1: self.search_hangul.jongsung = '' if self.search_hangul.step <= 0: self.search_hangul.jungsung = '' # if delete vowel and no leading consonant if self.search_hangul.step == 0 and not self.search_hangul.chosung: self.searchlastkey = [-1, 0] self.searchtimer.start() elif self.searchlastkey[0] != -1: self.searchlastkey = [-1, 0, ''] else: self.searchstring = self.searchstring[:-1] self.searchTextDisplay() self.callSearchCallback() @pyqtSlot(object) def searchButtonPressedEnter(self, index): self.searchButtonPressedTimeout() self.stopSearch() self.callSearchCallback() def resizeEvent(self, QResizeEvent): super().resizeEvent(QResizeEvent) self.setSearchPos() self.setTextSize() def gotoPage(self, u_int): self.stackedlayout.setCurrentIndex(u_int) self.setTextSize() def setHeaders(self, options): for i, option in enumerate(self.functionoption): try: option.clicked.disconnect() except: pass if i in options.keys(): try: option.setText(options[i]['text']) if callable(options[i]['func']): option.clicked.connect(options[i]['func']) except: settings.logger.printException() else: option.setText('') def setFooters(self, options): for i, option in enumerate(self.footeroption): try: option.clicked.disconnect() except: pass if i in options.keys(): try: option.setText(options[i]['text']) if callable(options[i]['func']): option.clicked.connect(options[i]['func']) except: settings.logger.printException() else: option.setText('') if 'pagertext' in options.keys(): self.pageroption.setText(options['pagertext']) else: self.pageroption.setText('') def setContents(self, screenNum, options): if 0 <= screenNum <= 1: self.gotoPage(screenNum) for i, option in enumerate(self.contentoption[screenNum]): try: option.clicked.disconnect() except: pass if i in options.keys(): try: option.setText(options[i]['text']) if callable(options[i]['func']): option.clicked.connect(options[i]['func']) option.connect = options[i]['func'] altimage = self.nosingerimage if type( option) == QLabeImageButton else None try: option.setImage(options[i]['image'], altimage) except: option.setPixmap(altimage) except: settings.logger.printException() else: option.setText('') if callable(option.clearPixmap): option.clearPixmap() def setBackCallback(self, backcallback): try: self.backoption.clicked.disconnect() except: pass try: if callable(backcallback): self.backoption.clicked.connect(backcallback) except: settings.logger.printException() def setStatusText(self, p_str): self.statustext = p_str if not self.timer.isActive(): self.statusframe.setText(p_str) def setStatusTempText(self, p_str, msec): if self.timer.isActive(): self.timer.stop() self.timer.setSingleShot(True) self.timer.start(msec) self.statusframe.setText(p_str) self.statusframe.x = 0 self.statusframe.paused = True self.statusframe.repaint() @pyqtSlot() def setOldStatusText(self): self.statusframe.setText(self.statustext) self.statusframe.paused = False
class ComboEditor(QDialog): closeSplit = pyqtSignal(QWidget)#closeSplit allFilesClosed = pyqtSignal() splitEditor = pyqtSignal("QWidget*", "QWidget*", bool) recentTabsModified = pyqtSignal() aboutToCloseComboEditor = pyqtSignal() class NAVIGATE: prev = 0 next = 1 Q_ENUMS(NAVIGATE) def __init__(self, original=False): super(ComboEditor, self).__init__(None, Qt.WindowStaysOnTopHint) self.__original = original self.__undocked = [] self._symbols_index = [] vbox = QVBoxLayout(self) vbox.setContentsMargins(0, 0, 0, 0) vbox.setSpacing(0) self.bar = ActionBar(main_combo=original) vbox.addWidget(self.bar) self.stacked = QStackedLayout() vbox.addLayout(self.stacked) self._main_container = IDE.get_service('main_container') if not self.__original: self._main_container.fileOpened.connect(self._file_opened_by_main) self.bar.combo.showComboSelector.connect(self._main_container.change_tab) self.bar.changeCurrent.connect(self._set_current) self.bar.editorSplited.connect(self.split_editor) self.bar.runFile[str].connect(self._run_file) self.bar.closeFile.connect(lambda: self.closeSplit.emit(self)) self.bar.addToProject[str].connect(self._add_to_project) self.bar.showFileInExplorer.connect(self._show_file_in_explorer) self.bar.goToSymbol.connect(self._go_to_symbol) self.bar.undockEditor.connect(self.undock_editor) self.bar.reopenTab[str].connect(self._main_container.open_file) self.bar.recentTabsModified.connect(self._main_container.recent_files_changed) self.bar.code_navigator.btnPrevious.clicked['bool'].connect(lambda: self._navigate_code(self.NAVIGATE.prev)) self.bar.code_navigator.btnNext.clicked['bool'].connect(lambda: self._navigate_code(self.NAVIGATE.prev)) def _navigate_code(self, val): op = self.bar.code_navigator.operation self._main_container.navigate_code_history(val, op) def currentWidget(self): return self.stacked.currentWidget() def setFocus(self): super(ComboEditor, self).setFocus() w = self.stacked.currentWidget() if w: w.setFocus() self._editor_with_focus() def _file_opened_by_main(self, path): index = self.stacked.currentIndex() ninjaide = IDE.getInstance() editable = ninjaide.get_or_create_editable(path) print("_file_opened_by_main", editable) self.add_editor(editable) self.bar.set_current_by_index(index) if index == -1: self.bar.set_current_by_index(0) def add_editor(self, neditable, keep_index=False): """Add Editor Widget to the UI area.""" if neditable.editor: if self.__original: editor = neditable.editor else: editor = self._main_container.create_editor_from_editable( neditable) index = self.stacked.currentIndex() self.stacked.addWidget(editor) self.bar.add_item(neditable.display_name, neditable) if keep_index: self.bar.set_current_by_index(index) # Editor Signals editor.cursorPositionChanged[int, int].connect(self._update_cursor_position) editor.editorFocusObtained.connect(self._editor_with_focus) editor.currentLineChanged.connect(self._set_current_symbol) editor.modificationChanged['bool'].connect(self._editor_modified) neditable.checkersUpdated.connect(self._show_notification_icon) neditable.fileSaved.connect(self._update_symbols) neditable.fileSaved.connect(self._update_combo_info) # Connect file system signals only in the original neditable.fileClosing.connect(self._close_file) if self.__original: neditable.askForSaveFileClosing.connect(self._ask_for_save) neditable.fileChanged.connect(self._file_has_been_modified) # Load Symbols self._load_symbols(neditable) def show_combo_file(self): print("show_combo_file") self.bar.combo.showPopup() def show_combo_symbol(self): self.bar.symbols_combo.showPopup() def unlink_editors(self): for index in range(self.stacked.count()): widget = self.stacked.widget(index) widget.setDocument(QsciDocument()) def split_editor(self, orientationVertical): new_widget = ComboEditor() for neditable in self.bar.get_editables(): print("\nsplit_editor", neditable, new_widget) new_widget.add_editor(neditable) self.splitEditor.emit(self, new_widget, orientationVertical) def undock_editor(self): new_combo = ComboEditor() new_combo.setWindowTitle("NINJA-IDE") self.__undocked.append(new_combo) for neditable in self.bar.get_editables(): print("undock_editor", neditable) new_combo.add_editor(neditable) new_combo.resize(500, 500) new_combo.aboutToCloseComboEditor.connect(self._remove_undock) new_combo.show() def _remove_undock(self): widget = self.sender() self.__undocked.remove(widget) def close_current_file(self): self.bar.about_to_close_file() def _close_file(self, neditable): index = self.bar.close_file(neditable) layoutItem = self.stacked.takeAt(index) #neditable.editor.completer.cc.unload_module() self._add_to_last_opened(neditable.file_path) layoutItem.widget().deleteLater() if self.stacked.isEmpty(): self.allFilesClosed.emit() def _add_to_last_opened(self, path): if path not in settings.LAST_OPENED_FILES: settings.LAST_OPENED_FILES.append(path) if len(settings.LAST_OPENED_FILES) > settings.MAX_REMEMBER_TABS: self.__lastOpened = self.__lastOpened[1:] self.recentTabsModified.emit() def _editor_with_focus(self): if self._main_container.current_widget is not self: self._main_container.current_widget = self editor = self.stacked.currentWidget() self._main_container.current_editor_changed( editor.neditable.file_path) self._load_symbols(editor.neditable) editor.neditable.update_checkers_display() def _ask_for_save(self, neditable): val = QMessageBox.No fileName = neditable.nfile.file_name val = QMessageBox.question( self, (self.tr('The file %s was not saved') % fileName), self.tr("Do you want to save before closing?"), QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel) if val == QMessageBox.No: neditable.nfile.close(force_close=True) elif val == QMessageBox.Yes: neditable.ignore_checkers = True self._main_container.save_file(neditable.editor) neditable.nfile.close() def _file_has_been_modified(self, neditable): val = QMessageBox.No fileName = neditable.file_path val = QMessageBox.question( self, translations.TR_FILE_HAS_BEEN_MODIFIED, "%s%s" % (fileName, translations.TR_FILE_MODIFIED_OUTSIDE), QMessageBox.Yes | QMessageBox.No) if val == QMessageBox.Yes: neditable.reload_file() def _run_file(self, path): self._main_container.run_file(path) def _add_to_project(self, path): self._main_container._add_to_project(path) def _show_file_in_explorer(self, path): '''Connected to ActionBar's showFileInExplorer(QString) signal, forwards the file path on to the main container.''' self._main_container._show_file_in_explorer(path) def set_current(self, neditable): if neditable: self.bar.set_current_file(neditable) def _set_current(self, neditable, index): if neditable: self.stacked.setCurrentIndex(index) editor = self.stacked.currentWidget() self._update_cursor_position(ignore_sender=True) editor.setFocus() self._main_container.current_editor_changed( neditable.file_path) self._load_symbols(neditable) self._show_file_in_explorer(neditable.file_path) neditable.update_checkers_display() def widget(self, index): return self.stacked.widget(index) def count(self): """Return the number of editors opened.""" return self.stacked.count() def _update_cursor_position(self, line=0, col=0, ignore_sender=False): obj = self.sender() editor = self.stacked.currentWidget() # Check if it's current to avoid signals from other splits. if ignore_sender or editor == obj: line += 1 self.bar.update_line_col(line, col) def _set_current_symbol(self, line, ignore_sender=False): obj = self.sender() editor = self.stacked.currentWidget() # Check if it's current to avoid signals from other splits. if ignore_sender or editor == obj: index = bisect.bisect(self._symbols_index, line) if (index >= len(self._symbols_index) or self._symbols_index[index] > (line + 1)): index -= 1 self.bar.set_current_symbol(index) def _editor_modified(self, value): obj = self.sender() neditable = obj.neditable if value: text = "\u2022 %s" % neditable.display_name self.bar.update_item_text(neditable, text) else: self.bar.update_item_text(neditable, neditable.display_name) def _go_to_symbol(self, index): print("_go_to_symbol in index:", index) line = self._symbols_index[index] editor = self.stacked.currentWidget() editor.go_to_line(line) def _update_symbols(self, neditable): editor = self.stacked.currentWidget() # Check if it's current to avoid signals from other splits. if editor == neditable.editor: self._load_symbols(neditable) def _update_combo_info(self, neditable): self.bar.update_item_text(neditable, neditable.display_name) self._main_container.current_editor_changed(neditable.file_path) def _load_symbols(self, neditable): symbols_handler = handlers.get_symbols_handler('py') source = neditable.editor.text() source = source.encode(neditable.editor.encoding) symbols, symbols_simplified = symbols_handler.obtain_symbols( source, simple=True) self._symbols_index = sorted(symbols_simplified.keys()) symbols_simplified = sorted( list(symbols_simplified.items()), key=lambda x: x[0]) self.bar.add_symbols(symbols_simplified) line, _ = neditable.editor.getCursorPosition() self._set_current_symbol(line, True) tree_symbols = IDE.get_service('symbols_explorer') tree_symbols.update_symbols_tree(symbols, neditable.file_path) def _show_notification_icon(self, neditable): checkers = neditable.sorted_checkers icon = QIcon() for items in checkers: checker, color, _ = items if checker.checks: if isinstance(checker.checker_icon, int): icon = self.style().standardIcon(checker.checker_icon) elif isinstance(checker.checker_icon, str): icon = QIcon(checker.checker_icon) break self.bar.update_item_icon(neditable, icon) def show_menu_navigation(self): self.bar.code_navigator.show_menu_navigation() def closeEvent(self, event): self.aboutToCloseComboEditor.emit() super(ComboEditor, self).closeEvent(event) def reject(self): if not self.__original: super(ComboEditor, self).reject()