def __init__(self, name, parent, bv, db): QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) self.hitcounts = [] self.orig_hitcounts = [] self.db = db self.bv = bv self.descending = True self.highlight = False self.current_page = 0 self.hitcounts = self.db.get_hitcounts() self.orig_hitcounts = [e for e in self.hitcounts] self.actionHandler = UIActionHandler() self.actionHandler.setupActionHandler(self) vlayout = QVBoxLayout() # Top label self.hitcount_counter = QLabel("Basic block count: {}".format( self.db.hitcount_count)) self.hitcount_counter.setAlignment(Qt.AlignLeft | Qt.AlignTop) # BB Hitcount table self.hit_table = QTableWidget(0, 3) self.hit_table.setHorizontalHeaderLabels( ["Address", "Hitcount", "Function"]) self.hit_table.verticalHeader().hide() self.hit_table.horizontalHeader().setStretchLastSection(True) self.hit_table.itemDoubleClicked.connect(self._cb_table) self._render_page() # Option buttons optionslayout = QHBoxLayout() optionsbox = QGroupBox("Options") ascending_checkbox = QCheckBox("Sort ascending") highlight_checkbox = QCheckBox("Highlight basic blocks") ascending_checkbox.stateChanged.connect(self._cb_ascending) highlight_checkbox.stateChanged.connect(self._cb_highlight) optionslayout.addWidget(ascending_checkbox) optionslayout.addWidget(highlight_checkbox) optionsbox.setLayout(optionslayout) # Diffing buttons diffinglayout = QHBoxLayout() diffingoptions = QGroupBox("Diffing") diffing_reset_button = QPushButton("Reset") diffing_diff_button = QPushButton("Difference") diffing_inter_button = QPushButton("Intersection") diffing_reset_button.clicked.connect(self._cb_diff_reset) diffing_diff_button.clicked.connect(self._cb_diff_diff) diffing_inter_button.clicked.connect(self._cb_diff_inter) diffinglayout.addWidget(diffing_diff_button) diffinglayout.addWidget(diffing_inter_button) diffinglayout.addWidget(diffing_reset_button) diffingoptions.setLayout(diffinglayout) # Bottom buttons for page change prevnextlayout = QHBoxLayout() self.back_button = QPushButton("<") self.next_button = QPushButton(">") self.page_count_label = QLabel("") self.page_count_label.setAlignment(Qt.AlignCenter) self._render_nav_line() self.back_button.clicked.connect(self._cb_prev_page) self.next_button.clicked.connect(self._cb_next_page) prevnextlayout.addWidget(self.back_button) prevnextlayout.addWidget(self.page_count_label) prevnextlayout.addWidget(self.next_button) vlayout.addWidget(self.hitcount_counter) vlayout.addWidget(self.hit_table) vlayout.addWidget(optionsbox) vlayout.addWidget(diffingoptions) vlayout.addLayout(prevnextlayout) self.setLayout(vlayout)
def __init__(self, parent, name, view): QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) layout = QGridLayout(self) webview = QWebEngineView() webview.load("https://cloud.binary.ninja") layout.addWidget(webview, 0, 0)
def __init__(self, parent, name, data): global instance_id QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) self.actionHandler = UIActionHandler() self.actionHandler.setupActionHandler(self) offset_layout = QHBoxLayout() offset_layout.addWidget(QLabel("Offset: ")) self.offset = QLabel(hex(0)) offset_layout.addWidget(self.offset) offset_layout.setAlignment(QtCore.Qt.AlignCenter) datatype_layout = QHBoxLayout() datatype_layout.addWidget(QLabel("Data Type: ")) self.datatype = QLabel("") datatype_layout.addWidget(self.datatype) datatype_layout.setAlignment(QtCore.Qt.AlignCenter) layout = QVBoxLayout() title = QLabel(name, self) title.setAlignment(QtCore.Qt.AlignCenter) instance = QLabel("Instance: " + str(instance_id), self) instance.setAlignment(QtCore.Qt.AlignCenter) layout.addStretch() layout.addWidget(title) layout.addWidget(instance) layout.addLayout(datatype_layout) layout.addLayout(offset_layout) layout.addStretch() self.setLayout(layout) instance_id += 1 self.data = data
def __init__(self, parent, name, data): QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) self.actionHandler = UIActionHandler() self.actionHandler.setupActionHandler(self) status_layout = QHBoxLayout() status_layout.addWidget(QLabel('Status: ')) self.status = QLabel('idle') status_layout.addWidget(self.status) status_layout.setAlignment(QtCore.Qt.AlignCenter) client_dbg_layout = QHBoxLayout() client_dbg_layout.addWidget(QLabel('Client debugger: ')) self.client_dbg = QLabel('n/a') client_dbg_layout.addWidget(self.client_dbg) client_dbg_layout.setAlignment(QtCore.Qt.AlignCenter) client_pgm_layout = QHBoxLayout() client_pgm_layout.addWidget(QLabel('Client program: ')) self.client_pgm = QLabel('n/a') client_pgm_layout.addWidget(self.client_pgm) client_pgm_layout.setAlignment(QtCore.Qt.AlignCenter) layout = QVBoxLayout() layout.addStretch() layout.addLayout(status_layout) layout.addLayout(client_dbg_layout) layout.addLayout(client_pgm_layout) layout.addStretch() self.setLayout(layout)
def __init__(self, parent, name, data): QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) self.actionHandler = UIActionHandler() self.actionHandler.setupActionHandler(self) self.data = data self.parent = parent self.current_state = None self.arch = None self.address_start = None self.size = 512 self.changes = set() self.tab_name = None self.symb_idx = 0 self._layout = QVBoxLayout() self.button = QPushButton("Monitor Memory") self.button.clicked.connect(self.on_monitor_button_click) self.hexWidget = HexViewWidget( menu_handler=self.on_customContextMenuRequested) self.hexWidget.data_edited.connect(self._handle_data_edited) self.hexWidget.setEnabled(False) self._layout.addWidget(self.button) self._layout.addWidget(self.hexWidget) self._layout.setContentsMargins(0, 0, 0, 0) self.setMaximumWidth(self.hexWidget.optimal_width + 25) self.setLayout(self._layout)
def __init__(self, parent, name, data): QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) self.parent = parent self.arch = None self.current_state = None self.symb_idx = 0 self.reg_to_index = dict() self.index_to_reg = dict() self.reg_cache = dict() self.data = data self.tab_name = None self.actionHandler = UIActionHandler() self.actionHandler.setupActionHandler(self) self._layout = QVBoxLayout() # Set up register table self._table = QTableWidget() self._table.setColumnCount(2) self._table.setHorizontalHeaderLabels(['Register', 'Value']) self._table.horizontalHeader().setStretchLastSection(True) self._table.verticalHeader().setVisible(False) self._table.setContextMenuPolicy(Qt.CustomContextMenu) self._table.customContextMenuRequested.connect( self.on_customContextMenuRequested) self._table.doubleClicked.connect(self.on_doubleClick) self._layout.addWidget(self._table) self.setLayout(self._layout)
def __init__(self, parent, name, data): if not type(data) == binaryninja.binaryview.BinaryView: raise Exception('expected widget data to be a BinaryView') self.bv = data QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) self.actionHandler = UIActionHandler() self.actionHandler.setupActionHandler(self) self.table = QTableView(self) self.model = DebugModulesListModel(self.table, data) self.table.setModel(self.model) self.item_delegate = DebugModulesItemDelegate(self) self.table.setItemDelegate(self.item_delegate) # self.table.setSortingEnabled(True) self.table.setSelectionBehavior( QAbstractItemView.SelectionBehavior.SelectRows) self.table.setSelectionMode(QAbstractItemView.ExtendedSelection) self.table.verticalHeader().setSectionResizeMode( QHeaderView.ResizeToContents) self.table.verticalHeader().setVisible(False) self.table.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel) self.table.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel) self.table.resizeColumnsToContents() self.table.resizeRowsToContents() for i in range(len(self.model.columns)): self.table.setColumnWidth( i, self.item_delegate.sizeHint( self.table.viewOptions(), self.model.index(-1, i, QModelIndex())).width()) update_layout = QHBoxLayout() update_layout.setContentsMargins(0, 0, 0, 0) update_label = QLabel("Data is Stale") update_button = QPushButton("Refresh") update_button.clicked.connect(lambda: self.refresh()) update_layout.addWidget(update_label) update_layout.addStretch(1) update_layout.addWidget(update_button) self.update_box = QWidget() self.update_box.setLayout(update_layout) self.layout = QVBoxLayout() self.layout.setContentsMargins(0, 0, 0, 0) self.layout.setSpacing(0) self.layout.addWidget(self.table) self.setLayout(self.layout)
def __init__(self, parent, name, data): QtWidgets.QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) self.actionHandler = UIActionHandler() self.actionHandler.setupActionHandler(self) self.HyaraBinaryNinja = HyaraBinaryNinja() self.setLayout(self.HyaraBinaryNinja.layout)
def __init__(self, parent, name): QtWidgets.QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) self.actionHandler = UIActionHandler() self.actionHandler.setupActionHandler(self) self._active_view = None self._visible_for_view = collections.defaultdict(lambda: False)
def __init__(self, parent, name, data): # Read the configuration settings = Settings() settings.register_group("ghinja", "Ghinja") settings.register_setting("ghinja.ghidra_install_path", """ { "title" : "Ghidra Installation Path", "type" : "string", "default" : "", "description" : "Path to analyzeHeadless file in Ghidra installation dir." } """) if not os.path.exists(settings.get_string("ghinja.ghidra_install_path")): show_message_box("Path to Ghidra headless was not found!", "To allow the Ghinja plugin to work, you will be prompted to specify the path to the \"analyzeHeadless(.bat)\" file.", buttons=0, icon=2) settings.set_string("ghinja.ghidra_install_path",get_open_filename_input("Provide Path to Ghidra \"analyzeHeadless(.bat)\" file (Usually: <GHIDRA_INSTALL>/support/analyzeHeadless)").decode("utf-8")) self.rename_settings = Settings() self.rename_settings.register_group("ghinja_rename","Rename") self.rename_settings.register_setting("ghinja_rename.ghinja_rename_struct", """ { "title" : "Ghidra Rename Struct", "type" : "string", "default" : "{}", "description" : "Settings to hold renames for variables." } """) global instance_id self.binja_renames = {} # {"function_name":[{"original":"new"})]} self.current_function = None self.current_offset = None self.decomp = None self.current_view = None self.function_output = None self.decompile_result_path = None self.decompile_offset_path = None self.decompiler_done = False self.function_args = [] QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) self.actionHandler = UIActionHandler() self.actionHandler.setupActionHandler(self) layout = QVBoxLayout() self.editor = QTextEdit(self) self.editor.setReadOnly(True) self.editor.installEventFilter(self) self.editor.setStyleSheet("QTextEdit { font-family: Consolas }") self.editor.setPlainText(" Click anywhere in the dock to start decompiler") self.editor.selectionChanged.connect(self.onSelect) highlighter = Highlighter(self.editor.document(),"",self.function_args) layout.addWidget(self.editor) layout.setAlignment(QtCore.Qt.AlignLeft) self.setLayout(layout) instance_id += 1 self.data = data
def __init__(self, name, parent=None): QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) self.base = BinjaWidgetBase() # self._main_window.addDockWidget(Qt.RightDockWidgetArea, self) #self._tabs = QTabWidget() #self._tabs.setTabPosition(QTabWidget.East) #self.setWidget(self._tabs) # self.hide() self.show()
def __init__(self, parent, name, data): if not type(data) == BinaryView: raise Exception('expected widget data to be a BinaryView') self.bv = data QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) self.actionHandler = UIActionHandler() self.actionHandler.setupActionHandler(self) self.table = QTableView(self) self.model = DebugThreadsListModel(self.table) self.table.setModel(self.model) self.table.clicked.connect(self.threadRowClicked) self.item_delegate = DebugThreadsItemDelegate(self) self.table.setItemDelegate(self.item_delegate) # self.table.setSortingEnabled(True) self.table.setSelectionBehavior( QAbstractItemView.SelectionBehavior.SelectRows) self.table.setSelectionMode(QAbstractItemView.ExtendedSelection) self.table.verticalHeader().setSectionResizeMode( QHeaderView.ResizeToContents) self.table.verticalHeader().setVisible(False) self.table.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel) self.table.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel) self.table.resizeColumnsToContents() self.table.resizeRowsToContents() for i in range(len(self.model.columns)): self.table.setColumnWidth( i, self.item_delegate.sizeHint( self.table.viewOptions(), self.model.index(-1, i, QModelIndex())).width()) self.table.horizontalHeader().setSectionResizeMode( 1, QHeaderView.Stretch) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self.table) self.setLayout(layout)
def __init__(self, parent, name, view): try: QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) view.session_data['emulator.memory.dockWidget'] = self self.view = view self.layout = QHBoxLayout(self) dock_handler = DockHandler.getActiveDockHandler() dock_handler.setVisible('Emulator Memory View', False) except Exception as e: print(e)
def __init__(self, parent, name, view): try: QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) layout = QGridLayout(self) self.registers_label = QLabel(None) self.registers_label.setText('Registers') self.registers_view = RegisterEmulatorView(None, view) self.memory_label = QLabel(None) self.memory_label.setText('Memory Map') self.memory_view = EmulatorMemoryView(None, view) self.stack_label = QLabel(None) self.stack_label.setText('Stack View') self.stack_view = EmulatorStackView(None, view) # TODO # Implement a view that shows the top 0x100 bytes of the stack # OR....OR...let's make a "local variables" view self.button_widget = EmulatorButtonsWidget(self, view) layout.addWidget(self.button_widget, 0, 0, Qt.AlignLeft) layout.addWidget(self.memory_label, 1, 0) layout.addWidget(self.memory_view, 2, 0) layout.addWidget(self.registers_label, 1, 1) layout.addWidget(self.registers_view, 2, 1) layout.addWidget(self.stack_label, 1, 2) layout.addWidget(self.stack_view, 2, 2) self.registers_view.horizontalHeader().setStretchLastSection(True) self.view = view self.view_frame = None self.emulator = BinaryNinjaEmulator(view, self) dock_handler = DockHandler.getActiveDockHandler() dock_handler.setVisible('BNIL Emulator', False) except Exception as e: print(e)
def __init__(self, parent, name, data, bnwidgets): QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) self.actionHandler = UIActionHandler() self.actionHandler.setupActionHandler(self) self.data = data self.parent = parent self.bnwidgets = bnwidgets self.current_state = None self.arch = None self.address_start = None self.size = 512 self.changes = set() self.tab_name = None self.monitor_history = list() self.symb_idx = 0 self._layout = QGridLayout() self.button = QPushButton("Monitor Memory") self.button.setStyleSheet("margin-left: 10px;") self.button.clicked.connect( self._condom_async(self, self.on_monitor_button_click)) self.back_button = QPushButton("Back") self.back_button.setStyleSheet("margin-right: 10px;") self.back_button.clicked.connect( self._condom_async(self, self.on_back_click)) self.hexWidget = HexViewWidget( menu_handler=self.on_customContextMenuRequested) self.hexWidget.data_edited.connect(self._handle_data_edited) self.hexWidget.setEnabled(False) self._layout.addWidget(self.button, 0, 0, 1, 4) self._layout.addWidget(self.back_button, 0, 4, 1, 1) self._layout.addWidget(self.hexWidget, 1, 0, 1, 5) self._layout.setContentsMargins(0, 0, 0, 0) self.setMaximumWidth(self.hexWidget.optimal_width + 25) self.setLayout(self._layout)
def __init__(self, parent, name): QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) self.actionHandler = UIActionHandler() self.actionHandler.setupActionHandler(self) font = getMonospaceFont(self) fm = QFontMetricsF(font) table_layout = QVBoxLayout() self.table = QTableView() self.table.setFont(font) self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.table.verticalHeader().hide() self.table.verticalHeader().setSectionResizeMode(QHeaderView.Fixed) self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) # sorting self.table.setSortingEnabled(True) self.table.horizontalHeader().setSortIndicator(0, QtCore.Qt.AscendingOrder) data = [] self.model = TableModel(data) self.table.setModel(self.model) table_layout.addWidget(self.table) layout = QVBoxLayout() layout.addLayout(table_layout) self.setLayout(layout) # init double click action self.table.doubleClicked.connect(self._ui_entry_double_click) # init right click menu self.ctx_menu = QMenu() self._action_patch = QAction("Invert Branch", None) self.ctx_menu.addAction(self._action_patch) self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self._ui_table_ctx_menu_handler) self.bv = None self.filename = None self.do_sync = True
def __init__(self, parent, name, data): if not type(data) == binaryninja.binaryview.BinaryView: raise Exception('expected widget data to be a BinaryView') self.bv = data memory_view = binjaplug.get_state(data).memory_view QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) self.editor = LinearView(memory_view, ViewFrame.viewFrameForWidget(self)) self.actionHandler = UIActionHandler() self.actionHandler.setupActionHandler(self) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self.editor) self.setLayout(layout)
def __init__(self, parent: QWidget, name: str, bv: Optional[BinaryView]): """ Initialize a new NotepadDockWidget. :param parent: the QWidget to parent this NotepadDockWidget to :param name: the name to register the dock widget under :param bv: the currently focused BinaryView (may be None) """ self.bv = bv QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) # Set up the save timer to save the current notepad content on timeout. self.save_timer = QTimer(self) self.save_timer.setSingleShot(True) self.save_timer.timeout.connect(lambda: self.store_notes()) # Initialize the editor and set up the text changed callback. self.editor = JMarkdownEditor(self) self.editor.textChanged.connect(self.on_editor_text_changed) # Create the viewer self.viewer = JMarkdownViewer(self, self.editor) # Add both widgets to a tab container self.tab_container = QTabWidget() self.tab_container.addTab(self.viewer, "View") self.tab_container.addTab(self.editor, "Edit") # Create a simple layout for the editor and set it as the root layout. layout = QVBoxLayout() layout.addWidget(self.tab_container) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) # Probably does nothing since there should be no BV when the program # starts, but needs confirmation, so here it will stay. self.query_notes()
def __init__(self, parent, name, data): if not type(data) == binaryninja.binaryview.BinaryView: raise Exception('expected widget data to be a BinaryView') self.bv = data QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) self.actionHandler = UIActionHandler() self.actionHandler.setupActionHandler(self) layout = QVBoxLayout() self.consoleText = QTextEdit(self) self.consoleText.setReadOnly(True) self.consoleText.setFont(getMonospaceFont(self)) layout.addWidget(self.consoleText, 1) inputLayout = QHBoxLayout() inputLayout.setContentsMargins(4, 4, 4, 4) promptLayout = QVBoxLayout() promptLayout.setContentsMargins(0, 5, 0, 5) inputLayout.addLayout(promptLayout) self.consoleEntry = QLineEdit(self) inputLayout.addWidget(self.consoleEntry, 1) label = QLabel("dbg>>> ", self) label.setFont(getMonospaceFont(self)) promptLayout.addWidget(label) promptLayout.addStretch(1) self.consoleEntry.returnPressed.connect(lambda: self.sendLine()) layout.addLayout(inputLayout) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) self.setLayout(layout)
def __init__(self, parent, name, data): if not type(data) == BinaryView: raise Exception('expected widget data to be a BinaryView') self.bv = data QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) self.actionHandler = UIActionHandler() self.actionHandler.setupActionHandler(self) self.table = QTableView(self) self.model = DebugRegistersListModel(self.table, data) self.table.setModel(self.model) self.item_delegate = DebugRegistersItemDelegate(self) self.table.setItemDelegate(self.item_delegate) # self.table.setSortingEnabled(True) self.table.setSelectionBehavior( QAbstractItemView.SelectionBehavior.SelectRows) self.table.setSelectionMode(QAbstractItemView.ExtendedSelection) self.table.verticalHeader().setSectionResizeMode( QHeaderView.ResizeToContents) self.table.verticalHeader().setVisible(False) self.table.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel) self.table.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel) self.table.resizeColumnsToContents() self.table.resizeRowsToContents() layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self.table) self.setLayout(layout)
def __init__(self, parent, name, data): QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) self.onNewBufferSignal.connect(self.update) self.parent = parent self.current_state = None self.data = data self.tab_name = None self.actionHandler = UIActionHandler() self.actionHandler.setupActionHandler(self) self._layout = QVBoxLayout() # Set up register table self._table = QTableWidget() self._table.setColumnCount(4) self._table.setHorizontalHeaderLabels( ['Address', 'Name', 'Size', 'Constraints']) self._table.horizontalHeader().setStretchLastSection(True) self._table.verticalHeader().setVisible(False) self._table.setContextMenuPolicy(Qt.CustomContextMenu) self._table.customContextMenuRequested.connect( self.on_customContextMenuRequested) self._table.doubleClicked.connect(self.on_doubleClick) self.button = QPushButton("New Buffer") self.button.clicked.connect(self.on_newBufferClick) self._layout.addWidget(self.button) self._layout.addWidget(self._table) self.setLayout(self._layout)
def __init__(self, parent, name): global panes panes.append(self) QWidget.__init__(self, parent) DockContextHandler.__init__(self, self, name) self.actionHandler = UIActionHandler() self.actionHandler.setupActionHandler(self) # Top: Headers with line info header_layout = QFormLayout() self.function_info = QLabel("") self.line_info = QLabel("") header_layout.addRow(self.tr("Function:"), self.function_info) header_layout.addRow(self.tr("Line:"), self.line_info) # Middle: main source display pane textbox_layout = QVBoxLayout() self.textbox = QPlainTextEdit() self.textbox.setLineWrapMode(QPlainTextEdit.LineWrapMode.NoWrap) self.textbox.setReadOnly(True) font = getMonospaceFont(self) self.textbox.setFont(font) font = QFontMetrics(font) self.textbox.setMinimumWidth(40 * font.averageCharWidth()) self.textbox.setMinimumHeight(30 * font.lineSpacing()) textbox_layout.addWidget(self.textbox) # Bottom: buttons for stop/start, and substitution paths footer_layout = QVBoxLayout() sync_button_layout = QHBoxLayout() self.sync_button = QPushButton("Turn Source Sync Off") sync_button_layout.addWidget(self.sync_button) path_layout = QFormLayout() self.original_path = QLineEdit() self.substitute_path = QLineEdit() self.substitute_path_button = QPushButton("Do Path Substitution") path_layout.addRow(self.tr("Original Path:"), self.original_path) path_layout.addRow(self.substitute_path_button, self.substitute_path) footer_layout.addLayout(sync_button_layout) footer_layout.addLayout(path_layout) # Putting all the child layouts together layout = QVBoxLayout() layout.addLayout(header_layout) layout.addLayout(textbox_layout) layout.addLayout(footer_layout) self.setLayout(layout) # Set up button signals self.substitute_path_button.clicked.connect(self.do_path_substitution) self.sync_button.clicked.connect(self.toggle_sync) # Actual storage variables self.bv = None self.filename = None self.do_sync = True self.path_substitutions = {} self.failed_substitutions = []