def __init__(self, settings_ini: (str, SettingsINI), parent=None): """ :param settings_ini: (str, SettingsINI) can be a settings_ini file path or configured SettingsINI object. """ self.df_manager = DataFrameModelManager() QtGui.QMainWindow.__init__(self, parent=parent) self.setupUi(self) self.icons = Icons() self.dialog_settings = SettingsDialog(settings=settings_ini) self.dialog_merge_purge = MergePurgeDialog(self.df_manager) self.dialog_export = DataFrameModelExportDialog(self.df_manager, parent=self) self.dialog_import = DataFrameModelImportDialog(self.df_manager, parent=self) self.dialog_new_folder = DirectoryPathCreateDialog(self.treeView, parent=self) self.dialog_cloud = None self.key_delete = QtGui.QShortcut(self) self.key_enter = QtGui.QShortcut(self) self.key_zip = QtGui.QShortcut(self) self.key_rename = QtGui.QShortcut(self) self.connect_window_title() self.connect_actions() self.connect_treeview() self.connect_icons() self.connect_settings_dialog() self.connect_import_dialog() self.connect_export_dialog() self.connect_cloud_dialog() self.current_model = None
def __init__(self, directory, settings_ini, default_dirs=True, tree_view=None, main_control=None, **kwargs): self.parent = kwargs.get('parent', None) self.main_control = main_control if default_dirs is True: settings_ini.set_safe('GENERAL', 'ROOT_DIRECTORY', directory) settings_ini.set_safe('GENERAL', 'LOG_DIRECTORY', os.path.join(directory, 'logs')) self._directory = directory self._df_manager = DataFrameModelManager() self._file_tree_model = FileTreeModel(root_dir=directory, parent=self.parent) self._dialog_export_df_model = DataFrameModelExportDialog( self.df_manager) self._dialog_merge_purge = MergePurgeDialog(self.df_manager, parent=self.parent) self._dialog_add_directory = DirectoryPathCreateDialog( base_dirname=directory, parent=self.parent) self._dialog_import_df_model = DataFrameModelImportDialog( self.df_manager, parent=self.parent) self._dialog_import_df_model.signalImported.connect( self._handle_imported_df_model) self._dialog_settings = ProjectSettingsDialog(settings_ini) self._tree_view = None self.tree_view = tree_view
def dialog(self, qtbot, example_file_path) -> DataFrameModelImportDialog: dfm = DataFrameModelManager() dialog = DataFrameModelImportDialog(dfm, file_path=example_file_path) dialog.show() qtbot.add_widget(dialog) return dialog
def configure(self): """ called once on __init__ - Sets AlchemyConnectionManager and/or DataFrameModelManager if they were not set in the __init__(**kwargs) - Connects default actions - sets treeView model. :return: (None) """ self.setupUi(self) if self.con_manager is None: self.con_manager = AlchemyConnectionManager() if self.df_manager is None: self.df_manager = DataFrameModelManager() self._key_enter.setKey('return') self._key_ctrl_t.setKey('ctrl+T') self._key_enter.activated.connect(self.open_query_alchemyview) self._key_ctrl_t.activated.connect(self.open_table_description_dialog) self.treeView.setModel(self.con_manager.get_standard_item_model()) self.actionRemove.triggered.connect(self.delete) self.actionRefreshSchemas.triggered.connect(self.refresh_schemas) self.actionSaveText.triggered.connect(self.save_last_sql_text) self.actionSaveTextAs.triggered.connect(self.save_sql_text) self.actionOpenFile.triggered.connect(self.open_sql_text) self.actionOpenQueryData.triggered.connect(self.open_query_fileview) self.actionConnectToDatabase.triggered.connect(self.connect_database) self.actionDisconnectFromDatabase.triggered.connect( self.disconnect_database) self.actionExportFile.triggered.connect(self.export_table) self.actionImportFile.triggered.connect(self.open_import_dialog) self.actionAddDatabase.triggered.connect( self.open_add_connection_dialog) self.actionExecuteQuery.triggered.connect(self.execute_query) self.actionExecuteSelectedQuery.triggered.connect( self.execute_query_selected) self.treeView.expanded.connect(self.sync_current_database) self.connect_default_databases()
def main_window(self, qtbot, sqlite_db_path): """ Creates & returns a DatabasesMainWindow object loaded with one test sqlite connection named "con1" - any existing tables are dropped. :param qtbot: :param sqlite_db_path: :return: """ c = AlchemyConnection(name="con1") c.configure("sqlite:///" + sqlite_db_path, reset=True) c.meta.drop_all() cm = AlchemyConnectionManager() cm.add_connection(connection=c) window = DatabasesMainWindow(df_manager=DataFrameModelManager(), connection_manager=cm) qtbot.addWidget(window) return window
class ProjectMainWindow(QtGui.QMainWindow, Ui_ProjectWindow): """ The ProjectMainWindow displays a project that the user wants to work on. The project lives in a directory within the ZeexApp.ROOT_DIRECTORY. Each project gets a DataFrameModelManager object which controls the DataFrameModel of each file opened. The main window shows all files in this directory and provides very convenient features to work with files containing rows/columns. Project's settings are stored in a .ini file in the root project directory. """ signalModelChanged = QtCore.Signal(str) signalModelOpened = QtCore.Signal(str) signalModelDestroyed = QtCore.Signal(str) def __init__(self, settings_ini: (str, SettingsINI), parent=None): """ :param settings_ini: (str, SettingsINI) can be a settings_ini file path or configured SettingsINI object. """ self.df_manager = DataFrameModelManager() QtGui.QMainWindow.__init__(self, parent=parent) self.setupUi(self) self.icons = Icons() self.dialog_settings = SettingsDialog(settings=settings_ini) self.dialog_merge_purge = MergePurgeDialog(self.df_manager) self.dialog_export = DataFrameModelExportDialog(self.df_manager, parent=self) self.dialog_import = DataFrameModelImportDialog(self.df_manager, parent=self) self.dialog_new_folder = DirectoryPathCreateDialog(self.treeView, parent=self) self.dialog_cloud = None self.key_delete = QtGui.QShortcut(self) self.key_enter = QtGui.QShortcut(self) self.key_zip = QtGui.QShortcut(self) self.key_rename = QtGui.QShortcut(self) self.connect_window_title() self.connect_actions() self.connect_treeview() self.connect_icons() self.connect_settings_dialog() self.connect_import_dialog() self.connect_export_dialog() self.connect_cloud_dialog() self.current_model = None @property def project_directory(self): """ The project's root directory stores everything for the project. :return: (str) ProjectMainWindow.treeView.QFileSystemModel.rootPath """ return self.treeView.model().rootPath() @property def log_directory(self): """ The project's log directory stores output logs. :return: (str) ProjectMainWindow.project_directory/log """ return os.path.join(self.project_directory, 'log') @QtCore.Slot(SettingsINI, str) def sync_settings(self, config: SettingsINI = None, file_path=None): """ Anytime settings are saved this method gets triggered. Sets defaults for various views. :param config: :param file_path: :return: """ self.connect_export_dialog() self.connect_import_dialog() def connect_window_title(self): """ Sets the ProjectMainWindow.windowTitle to "Project - dirname - dirpath" :return: None """ root_dir = self.dialog_settings.rootDirectoryLineEdit.text() base_name = os.path.basename(root_dir) self.dialog_settings.setWindowTitle("{} - Settings".format(base_name)) self.setWindowTitle("Project: {} - {}".format( base_name, root_dir.replace(base_name, ""))) def connect_actions(self): """ Connects all project actions. :return: None """ self.actionPreferences.triggered.connect(self.dialog_settings.show) self.actionAddFolder.triggered.connect(self.dialog_new_folder.show) self.actionNew.triggered.connect(self.dialog_import.show) self.actionOpen.triggered.connect(self.open_tableview_window) self.actionSave.triggered.connect(self.dialog_export.show) self.actionRemove.triggered.connect(self.remove_tree_selected_path) self.actionRename.triggered.connect(self.open_rename_path_dialog) self.actionMergePurge.triggered.connect(self.open_merge_purge_dialog) self.actionUnzip.triggered.connect(self.handle_compression) self.actionZip.triggered.connect(self.handle_compression) self.key_delete.setKey('del') self.key_enter.setKey('return') self.key_zip.setKey(QtGui.QKeySequence(self.tr('Ctrl+Z'))) self.key_rename.setKey(QtGui.QKeySequence(self.tr('Ctrl+R'))) self.key_delete.activated.connect(self.remove_tree_selected_path) self.key_enter.activated.connect(self.open_tableview_window) self.key_zip.activated.connect(self.handle_compression) self.key_rename.activated.connect(self.open_rename_path_dialog) def connect_icons(self): """ Sets all the menu/window icons. :return: None """ self.setWindowIcon(self.icons['folder']) self.actionNew.setIcon(self.icons['add']) self.actionAddFolder.setIcon(self.icons['folder']) self.actionOpen.setIcon(self.icons['spreadsheet']) self.actionPreferences.setIcon(self.icons['settings']) self.actionRemove.setIcon(self.icons['delete']) self.actionSave.setIcon(self.icons['save']) self.dialog_settings.setWindowIcon(self.icons['settings']) self.actionMergePurge.setIcon(self.icons['merge']) self.actionRename.setIcon(self.icons['rename']) self.dialog_merge_purge.setWindowIcon(self.icons['merge']) self.actionZip.setIcon(self.icons['archive']) self.dialog_new_folder.setWindowIcon(self.icons['folder']) self.actionUnzip.setIcon(self.icons['unzip']) def connect_treeview(self): """ Uses the ProjectMainWindow.dialog_settings.rootDirectoryLineEdit to get the root directory name of the project. It then connects the filetree using a QFileSystemModel. :return: None """ rootdir = self.dialog_settings.rootDirectoryLineEdit.text() model = FileTreeModel(root_dir=rootdir) self.treeView.setModel(model) self.treeView.setRootIndex(model.index(rootdir)) self.treeView.setColumnWidth(0, 400) self.treeView.setSelectionMode(self.treeView.ExtendedSelection) def connect_settings_dialog(self): """ Re-purposes the ProjectMainWindow.dialog_settings dialog to fit the scope of a project rather than the application as a whole. :return: None """ #Adjust the box to remove irrelevant items. self.dialog_settings.cloudProviderComboBox.hide() self.dialog_settings.cloudProviderLabel.hide() self.dialog_settings.btnLogDirectory.hide() self.dialog_settings.btnRootDirectory.hide() self.dialog_settings.themeComboBox.hide() self.dialog_settings.themeLabel.hide() # Override the log/root directory options self.dialog_settings.logDirectoryLineEdit.setText(self.log_directory) self.dialog_settings.logDirectoryLineEdit.setReadOnly(True) self.dialog_settings.rootDirectoryLineEdit.setText( self.project_directory) self.dialog_settings.rootDirectoryLineEdit.setReadOnly(True) self.dialog_settings.btnSetDefault.setVisible(False) self.dialog_settings.signalSettingsSaved.connect(self.sync_settings) self.dialog_new_folder.base_dirname = self.dialog_settings.rootDirectoryLineEdit.text( ) def connect_cloud_dialog(self): try: self.dialog_cloud = DropBoxViewDialog(self.treeView, self) self.actionViewCloud.triggered.connect(self.dialog_cloud.show) self.actionViewCloud.setIcon(self.icons['cloud']) except Exception as e: logging.error("Error connecting to cloud: {}".format(e)) self.actionViewCloud.setVisible(False) def connect_export_dialog(self): """ Sets defaults of the DataFrameModelExport Dialog. :return: None """ self.dialog_export.signalExported.connect(self._flush_export) self.dialog_export.setWindowIcon(self.icons['export_generic']) sep = self.dialog_settings.separatorComboBox.currentText() enc = self.dialog_settings.encodingComboBox.currentText() self.dialog_export.set_encoding(enc) self.dialog_export.set_separator(sep) def connect_import_dialog(self): """ Sets defaults of the DataFrameModelImport Dialog. :return: None """ self.dialog_import.signalImported.connect(self.import_file) self.dialog_import.setWindowIcon(self.icons['add']) sep = self.dialog_settings.separatorComboBox.currentText() enc = self.dialog_settings.encodingComboBox.currentText() self.dialog_import.set_encoding(enc) self.dialog_import.set_separator(sep) def open_tableview_window(self, model: DataFrameModel = None): """ Opens a FileTableWindow for the filename selected in the ProjectMainWindow.treeView. :param model: The qtpandas.models.DataFrameModel to edit. :return: None """ if model is None: # Maybe it's selected on the tree? model = self.get_tree_selected_model() if model is None: # No, not sure why this was called.. #box = get_ok_msg_box(self, "No model available to open.") #box.show() pass self.df_manager.get_fileview_window(model.filePath).show() self.add_recent_file_menu_entry(model.filePath, model) def open_merge_purge_dialog(self, model: DataFrameModel = None): if model is None: model = self.get_tree_selected_model() current_model = self.dialog_merge_purge.source_model if current_model is None or current_model.filePath is not model.filePath: self.dialog_merge_purge.set_source_model(model=model, configure=True) self.dialog_merge_purge.show() def get_tree_selected_model(self, raise_on_error=True) -> (DataFrameModel, None): """ Returns a DataFrameModel based on the filepath selected in the ProjectMainWindow.treeView. :return: qtpandas.DataFrameModel """ # Check if file is selected in tree view selected = self.treeView.selectedIndexes() if selected: idx = selected[0] file_path = self.treeView.model().filePath(idx) return self.df_manager.read_file(file_path) return None def get_tree_selected_path(self): selected = self.treeView.selectedIndexes() if selected: idx = selected[0] return self.treeView.model().filePath(idx) return None def remove_tree_selected_path(self): #TODO: need to emit a signal here. idxes = self.treeView.selectedIndexes() if idxes: file_model = self.treeView.model() for idx in idxes: if not file_model.isDir(idx): file_model.remove(idx) else: file_model.rmdir(idx) def open_tableview_current(self, model: DataFrameModel = None): """ Opens a tableview window for the current_model or the model kwarg. :param model: DataFrameModel :return: None """ if model is None: model = self.current_model else: self.set_current_df_model(model) assert isinstance(model, DataFrameModel), "No current DataFrame model." return self.open_tableview_window(model) def set_current_df_model(self, model: DataFrameModel): """ Sets the current dataframe model. for the project. :param model: DataFrameModel :return: None """ self.df_manager.set_model(model, model._filePath) self.current_model = self.df_manager.get_model(model._filePath) @QtCore.Slot('DataFrameModel', str) def import_file(self, filepath, open=True): if isinstance(filepath, DataFrameModel): model = filepath filepath = model.filePath self.df_manager.set_model(model, filepath) model = self.df_manager.get_model(filepath) name = os.path.basename(model.filePath) dirname = self.dialog_settings.rootDirectoryLineEdit.text() assert os.path.isdir( dirname), "Root Directory is not a directory: {}".format(dirname) if os.path.dirname(filepath) != dirname: newpath = os.path.join(dirname, name) self.df_manager.save_file(filepath, save_as=newpath, keep_orig=False) filepath = newpath if open is True: model = self.df_manager.get_model(filepath) self.open_tableview_window(model) def add_recent_file_menu_entry(self, name, model): action = QtGui.QAction(name, self.menuRecent_Files) action.triggered.connect(partial(self.open_tableview_window, model)) actions = self.menuRecent_Files.actions() if actions: self.menuRecent_Files.insertAction(actions[0], action) else: self.menuRecent_Files.addAction(action) def maybe_save_copy(self, df, filepath, max_size=20000, **kwargs): """ Saves a copy of the file to the project folder if its smaller than max_size its larger than 0 rows :param df: DataFrame: to save :param filepath: str: the filepath of the DataFrame :param max_size: int: max size of DataFrame :param kwargs: DataFrame.to_csv(**kwargs) :return: None """ if df.index.size <= max_size and not df.empty: kwargs['index'] = kwargs.get('index', False) df.to_csv(filepath, **kwargs) def _flush_export(self, orig_path, new_path): if orig_path != new_path: self.add_recent_file_menu_entry( new_path, self.df_manager.get_model(new_path)) def open_rename_path_dialog(self): current_path = self.get_tree_selected_path() dialog = FilePathRenameDialog(current_path, parent=self) dialog.show() def handle_compression(self, fpath=None, **kwargs): if fpath is None: fpath = self.get_tree_selected_path() assert fpath is not None, "No selected path!" if not fpath.lower().endswith('.zip'): return ostools.zipfile_compress(fpath, **kwargs) else: return ostools.zipfile_unzip( file_path=fpath, dir=self.dialog_settings.rootDirectoryLineEdit.text())
def manager(self) -> DataFrameModelManager: return DataFrameModelManager()
class DatabasesMainWindow(QtGui.QMainWindow, Ui_DatabasesMainWindow): """ The general query/database maintenance MainWindow that is home to the following main objects: - A ToolBar with actions for simple database actions. - A TreeView of all databases registered. - A TextEdit for writing SQL queries - A TableView for viewing results. """ def __init__(self, *args, df_manager: DataFrameModelManager = None, connection_manager: AlchemyConnectionManager = None, **kwargs): QtGui.QMainWindow.__init__(self, *args, **kwargs) self.bookmarks = BookmarkManager('sql_bookmark_manager') self._last_df_model = None self._last_text_dir = '' self._last_text_path = '' self.con_manager = connection_manager self.df_manager = df_manager self._dialog_add_con = None self._dialog_import = None self._key_enter = QtGui.QShortcut(self) self._key_ctrl_t = QtGui.QShortcut(self) self.configure() @property def tree_model(self) -> QtGui.QStandardItemModel: """ Returns the QStandardItemModel containing the databases, tables, and columns. :return: (QtGui.QStandardItemModel) """ return self.treeView.model() @property def dialog_add_con(self) -> AlchemyConnectionDialog: if self._dialog_add_con is None: self._dialog_add_con = AlchemyConnectionDialog(self.con_manager, parent=self) self._dialog_add_con.signalConnectionAdded.connect( self.refresh_schemas) return self._dialog_add_con @property def dialog_import(self) -> AlchemyTableImportDialog: if self._dialog_import is None: self._dialog_import = AlchemyTableImportDialog( self.connection, self.con_manager, df_manager=self.df_manager, parent=self) return self._dialog_import @property def connection(self) -> AlchemyConnection: return self.con_manager.connection( self.comboBoxCurrentDatabase.currentText()) def connect_default_databases(self): """ Connects to system databases by default. TODO: maybe repurpose this into adding a dictionary of database configurations? :return: (None) """ new = False for name, ci in DEFAULT_CONNECTIONS.items(): try: self.con_manager.connection(name) except KeyError: try: self.con_manager.add_connection(name=name, **ci) new = True except Exception as e: pass others = self.con_manager.add_connections_from_settings() if new or others: self.treeView.setModel(self.con_manager.get_standard_item_model()) def configure(self): """ called once on __init__ - Sets AlchemyConnectionManager and/or DataFrameModelManager if they were not set in the __init__(**kwargs) - Connects default actions - sets treeView model. :return: (None) """ self.setupUi(self) if self.con_manager is None: self.con_manager = AlchemyConnectionManager() if self.df_manager is None: self.df_manager = DataFrameModelManager() self._key_enter.setKey('return') self._key_ctrl_t.setKey('ctrl+T') self._key_enter.activated.connect(self.open_query_alchemyview) self._key_ctrl_t.activated.connect(self.open_table_description_dialog) self.treeView.setModel(self.con_manager.get_standard_item_model()) self.actionRemove.triggered.connect(self.delete) self.actionRefreshSchemas.triggered.connect(self.refresh_schemas) self.actionSaveText.triggered.connect(self.save_last_sql_text) self.actionSaveTextAs.triggered.connect(self.save_sql_text) self.actionOpenFile.triggered.connect(self.open_sql_text) self.actionOpenQueryData.triggered.connect(self.open_query_fileview) self.actionConnectToDatabase.triggered.connect(self.connect_database) self.actionDisconnectFromDatabase.triggered.connect( self.disconnect_database) self.actionExportFile.triggered.connect(self.export_table) self.actionImportFile.triggered.connect(self.open_import_dialog) self.actionAddDatabase.triggered.connect( self.open_add_connection_dialog) self.actionExecuteQuery.triggered.connect(self.execute_query) self.actionExecuteSelectedQuery.triggered.connect( self.execute_query_selected) self.treeView.expanded.connect(self.sync_current_database) self.connect_default_databases() def refresh_schemas(self): """ Refreshes the database schemas for each connection. Then resets the treeView with the new info. :return: (None) """ for c in self.con_manager.connections.keys(): con = self.con_manager.connection(c) con.refresh_schemas() self.treeView.setModel(self.con_manager.get_standard_item_model()) def delete(self, idx=None): """ Deletes a database, table, or column on a database. If a database can't support dropping a column (like SQLite), an error is raised. Otherwise, the item is removed from the database if it's a table/column, the item is always removed from the treeView list if removed. :param idx: :return: """ if idx is None: idx = self.treeView.selectedIndexes() if not idx: raise Exception("Nothing selected to delete!") idx = idx[0] item = self.tree_model.itemFromIndex(idx) if item: if not item.parent(): # It's a database - just remove it off the list self.con_manager.remove_connection(item.text()) self.tree_model.takeRow(item.row()) elif not item.parent().parent(): # It's a table db_item = item.parent() table_name = item.text() db_name = db_item.text() con = self.con_manager.connection(db_name) table = con.meta.tables[table_name] table.drop(checkfirst=True) db_item.removeRow(item.row()) elif not item.hasChildren(): # It's a column table_item = self.tree_model.itemFromIndex( item.parent().index()) db_name = self.tree_model.itemFromIndex( table_item.parent().index()).text() con = self.con_manager.connection(db_name) table_name = table_item.text() try: sql = "ALTER TABLE '{}' DROP COLUMN '{}'".format( table_name, item.text()) con.engine.execute(sql) table_item.removeRow(item.row()) except Exception: raise NotImplementedError( "Unable to drop columns for SQL version: {}".format( con.engine.name)) def save_sql_text(self, file_path=''): """ Saves the current text in the textEdit to file_path. :param file_path: (str, default None) None will open a QFileDialog to ask for a save name. :return: (str) Of the saved file_path. """ if file_path == '': file_path = self.comboBoxCurrentFile.currentText() if file_path == '': file_path = QtGui.QFileDialog.getSaveFileName( dir=self._last_text_dir)[0] self._last_text_dir = os.path.dirname(file_path) new_text = self.textEdit.document().toPlainText() with open(file_path, "w") as fp: fp.write(new_text) if file_path in self.bookmarks.names: self.bookmarks.bookmark(file_path).set_text(new_text, save_changes=False) self.set_current_file(file_path) return file_path def save_last_sql_text(self): """ Convenience function to save the last opened text file back to disk. :return: (str) The saved file path """ return self.save_sql_text(file_path=self._last_text_path) def open_sql_text(self, file_path=''): """ Reads all text from file_path into the text edit widget :param file_path: (str, default '') The file_path to open. Defaults to a getOpenFileName :return: None """ if file_path is '': file_path = QtGui.QFileDialog.getOpenFileName( dir=self._last_text_dir)[0] self._last_text_dir = os.path.dirname(file_path) self._last_text_path = file_path self.bookmarks.add_bookmark(file_path, file_path=file_path) text = self.bookmarks.bookmark(file_path).get_text() self.textEdit.setPlainText(text) self.set_current_file(file_path) def open_add_connection_dialog(self): self.dialog_add_con.show() def open_import_dialog(self): self.dialog_import.show() def open_table_description_dialog(self, idx=None): if idx is None: idx = self.treeView.selectedIndexes()[0] table_name = self.tree_model.itemFromIndex(idx).text() con_name = self.tree_model.itemFromIndex(idx.parent()).text() con = self.con_manager.connection(con_name) self._table_desc_dialog = AlchemyTableDescriptionDialog(con) self._table_desc_dialog.set_table(table_name) self._table_desc_dialog.show() def set_current_file(self, file_path): """ Sets the current file combo box based on the given :param file_path. new items are inserted at the top. :param file_path: (str) :return: None """ idx = self.comboBoxCurrentFile.findText(file_path) if idx < 0: self.comboBoxCurrentFile.insertItem(0, file_path) idx = self.comboBoxCurrentFile.findText(file_path) self.comboBoxCurrentFile.setCurrentIndex(idx) def set_current_database(self, db_name): """ Sets the current database combo box based on the :param db_name. new items are inserted at the top. :param db_name: (str) :return: None """ idx = self.comboBoxCurrentDatabase.findText(db_name) if idx < 0: self.comboBoxCurrentDatabase.insertItem(0, db_name) idx = self.comboBoxCurrentDatabase.currentIndex() self.comboBoxCurrentDatabase.setCurrentIndex(idx) def sync_current_database(self, idx): """ Keeps the database combo box item up-to-date based on the user's current treeview selection. :param idx: (QModelIndex) Accepted from TreeView (or anyone, really) :return: None """ item = self.tree_model.itemFromIndex(idx) if not item.parent(): # It's a database self.set_current_database(item.text()) elif not item.parent().parent(): # It's a table self.set_current_database(item.parent().text()) elif not item.hasChildren(): # It's a column self.set_current_database(item.parent().parent().text()) def connect_database(self, db_name=None): """ Sets the currently active database. This one is a 'tough' design call because the con_manager automatically generates connections for databases in order to read out their MetaData and such... :param db_name: (str) The name of the database to activate :return: None """ if db_name is None: db_name = self.tree_model.itemFromIndex( self.treeView.selectedIndexes()[0]).text() self.set_current_database(db_name) def disconnect_database(self): """ Sets the comboBoxCurrentDatabase to blank. :param db_name: (str) The name of the database to deactivate. :return: None """ self.set_current_database('') def export_table(self, db_name, table_name, **kwargs): """ Opens export dialog for current database displaying a DatabaseTableExportDialog. The user can export a table to a file from there. :param db_name: :param table_name: :param kwargs: :return: (None) """ pass def add_database(self, *args, **kwargs): """ Registers a new database connection. and sync's the databases treeview. This is also a slot that gets activated when the DatabaseImportDialog is accepted. See zeex.core.ctrls.sql.AlchemyConnectionManager.add_connection(*args, **kwargs) for more details. :param args: (AlchemyConnectionManager.add_connection(*args, **kwargs)) :param kwargs: (AlchemyConnectionManager.add_connection(*args, **kwargs)) :return: (None) """ name = kwargs.get('name', None) con = kwargs.get('connection', None) check_name = (name if name is not None else con.name) kwargs['allow_duplicate'] = False self.con_manager.add_connection(*args, **kwargs) self.refresh_schemas() def execute_query(self, db_name=None, selected_text_only=False): """ Executes the given SQL query against the given database. Displays a message box with the error (if any), otherwise: Stores the DataFrameModel to the TableView. :param db_name: (str) The name of the database to execute the query on. :param selected_text_only: (bool, default False) True executes only the selected text in the textEdit False executes the entire text no matter what. :return: None """ if db_name is None: db_name = self.comboBoxCurrentDatabase.currentText() try: con = self.con_manager.connection(db_name) statement = self.textEdit.textCursor().selectedText().lstrip( ).rstrip() if selected_text_only is False or statement is '': statement = self.textEdit.document().toPlainText().lstrip( ).rstrip() self._last_df_model = dfm = con.execute_sql(statement) except Exception as e: if isinstance(e, KeyError): e = "Invalid database selection: {}".format(e) box = get_ok_msg_box(self, str(e), title="ERROR EXECUTING QUERY") box.show() raise self.tableView.setModel(dfm) def execute_query_selected(self, db_name=None): """ Executes the selected text against the given database. DatabasesMainWindow.execute_query(db_name, selected_text_only=True) :param db_name: (str) The database to execute the query on. :return: None """ return self.execute_query(db_name=db_name, selected_text_only=True) def open_query_fileview(self, save_path=None): dfm = self.tableView.model() assert dfm is not None, "No dataframe model available!" if save_path is None: if self._last_text_path is not '': save_path = os.path.splitext(self._last_text_path)[0] + ".csv" else: save_path = QtGui.QFileDialog.getSaveFileName( dir=self._last_text_dir)[0] base, ext = os.path.splitext(save_path) if ext.lower() not in ['.txt', '.xlsx', '.csv']: save_path = base + ".csv" self.df_manager.set_model(dfm, save_path) self.df_manager.get_fileview_window(save_path).show() def open_query_alchemyview(self): con = self.connection table_name = self.tree_model.itemFromIndex( self.treeView.selectedIndexes()[0]).text() window = con.get_alchemy_query_editor_window(table_name, parent=self) window.show()
def df_manager(self) -> DataFrameModelManager: if self._df_manager is None: self._df_manager = DataFrameModelManager() return self._df_manager