class AddWindow(SubProcessDialog): def __init__(self, tree, selected_list, dialog=True, ui_mode=True, parent=None, local=None, message=None): self.tree = tree self.initial_selected_list = selected_list super(AddWindow, self).__init__( gettext("Add"), name="add", default_size=(400, 400), ui_mode=ui_mode, dialog=dialog, parent=parent, hide_progress=True, ) self.throbber = ThrobberWidget(self) # Display the list of unversioned files groupbox = QtGui.QGroupBox(gettext("Unversioned Files"), self) vbox = QtGui.QVBoxLayout(groupbox) self.filelist = TreeWidget(groupbox) self.filelist.throbber = self.throbber self.filelist.tree_model.is_item_in_select_all = lambda item: ( # Is in select all. - Not versioned, and not Ignored item.change is not None and item.change.is_ignored( ) is None and not item.change.is_versioned(), # look at children. - Not ignored item.change is not None and item.change.is_ignored() is None or item.change is None) def filter_context_menu(): items = self.filelist.get_selection_items() selection_len = len(items) single_file = (selection_len == 1 and items[0].item.kind == "file") single_item_in_tree = (selection_len == 1 and (items[0].change is None or items[0].change[6][1] is not None)) self.filelist.action_open_file.setEnabled(True) self.filelist.action_open_file.setVisible(True) self.filelist.action_show_file.setEnabled(single_file) self.filelist.action_show_file.setVisible(True) self.filelist.action_show_annotate.setVisible(False) self.filelist.action_show_log.setVisible(False) self.filelist.action_show_diff.setVisible(False) self.filelist.action_add.setVisible(False) self.filelist.action_revert.setVisible(False) self.filelist.action_merge.setVisible(False) self.filelist.action_resolve.setVisible(False) self.filelist.action_rename.setVisible(True) self.filelist.action_rename.setEnabled(single_item_in_tree) self.filelist.action_remove.setVisible(False) self.filelist.action_mark_move.setVisible(False) self.filelist.filter_context_menu = filter_context_menu vbox.addWidget(self.filelist) selectall_checkbox = SelectAllCheckBox(self.filelist, groupbox) vbox.addWidget(selectall_checkbox) selectall_checkbox.setCheckState(QtCore.Qt.Checked) selectall_checkbox.setEnabled(True) self.show_ignored_checkbox = QtGui.QCheckBox( gettext("Show ignored files"), groupbox) vbox.addWidget(self.show_ignored_checkbox) self.connect(self.show_ignored_checkbox, QtCore.SIGNAL("toggled(bool)"), self.show_ignored) # groupbox gets disabled as we are executing. QtCore.QObject.connect(self, QtCore.SIGNAL("disableUi(bool)"), groupbox, QtCore.SLOT("setDisabled(bool)")) self.splitter = QtGui.QSplitter(QtCore.Qt.Vertical) self.splitter.addWidget(groupbox) self.splitter.addWidget(self.make_default_status_box()) self.splitter.setStretchFactor(0, 10) self.restoreSplitterSizes([150, 150]) layout = QtGui.QVBoxLayout(self) layout.addWidget(self.throbber) layout.addWidget(self.splitter) layout.addWidget(self.buttonbox) self.throbber.show() def show(self): SubProcessDialog.show(self) QtCore.QTimer.singleShot(1, self.initial_load) @runs_in_loading_queue @ui_current_widget @reports_exception() def initial_load(self): self.filelist.tree_model.checkable = True fmodel = self.filelist.tree_filter_model fmodel.setFilter(fmodel.CHANGED, False) fmodel.setFilter(fmodel.UNCHANGED, False) self.filelist.set_tree( self.tree, changes_mode=True, initial_checked_paths=self.initial_selected_list, change_load_filter=lambda c: not c.is_versioned()) self.throbber.hide() def _get_files_to_add(self): return [ref.path for ref in self.filelist.tree_model.iter_checked()] def validate(self): if not self._get_files_to_add(): self.operation_blocked(gettext("Nothing selected to add")) return False return True def do_start(self): """Add the files.""" files = self._get_files_to_add() self.process_widget.do_start(self.tree.basedir, "add", "--no-recurse", *files) def show_ignored(self, state): """Show/hide ignored files.""" fmodel = self.filelist.tree_filter_model fmodel.setFilter(fmodel.IGNORED, state) #self.filelist.update_selectall_state(None, None) def _saveSize(self, config): SubProcessDialog._saveSize(self, config) self._saveSplitterSizes(config, self.splitter)
def __init__(self, tree, selected_list, dialog=True, ui_mode=True, parent=None, local=None, message=None): self.tree = tree self.initial_selected_list = selected_list super(AddWindow, self).__init__( gettext("Add"), name="add", default_size=(400, 400), ui_mode=ui_mode, dialog=dialog, parent=parent, hide_progress=True, ) self.throbber = ThrobberWidget(self) # Display the list of unversioned files groupbox = QtGui.QGroupBox(gettext("Unversioned Files"), self) vbox = QtGui.QVBoxLayout(groupbox) self.filelist = TreeWidget(groupbox) self.filelist.throbber = self.throbber self.filelist.tree_model.is_item_in_select_all = lambda item: ( # Is in select all. - Not versioned, and not Ignored item.change is not None and item.change.is_ignored( ) is None and not item.change.is_versioned(), # look at children. - Not ignored item.change is not None and item.change.is_ignored() is None or item.change is None) def filter_context_menu(): items = self.filelist.get_selection_items() selection_len = len(items) single_file = (selection_len == 1 and items[0].item.kind == "file") single_item_in_tree = (selection_len == 1 and (items[0].change is None or items[0].change[6][1] is not None)) self.filelist.action_open_file.setEnabled(True) self.filelist.action_open_file.setVisible(True) self.filelist.action_show_file.setEnabled(single_file) self.filelist.action_show_file.setVisible(True) self.filelist.action_show_annotate.setVisible(False) self.filelist.action_show_log.setVisible(False) self.filelist.action_show_diff.setVisible(False) self.filelist.action_add.setVisible(False) self.filelist.action_revert.setVisible(False) self.filelist.action_merge.setVisible(False) self.filelist.action_resolve.setVisible(False) self.filelist.action_rename.setVisible(True) self.filelist.action_rename.setEnabled(single_item_in_tree) self.filelist.action_remove.setVisible(False) self.filelist.action_mark_move.setVisible(False) self.filelist.filter_context_menu = filter_context_menu vbox.addWidget(self.filelist) selectall_checkbox = SelectAllCheckBox(self.filelist, groupbox) vbox.addWidget(selectall_checkbox) selectall_checkbox.setCheckState(QtCore.Qt.Checked) selectall_checkbox.setEnabled(True) self.show_ignored_checkbox = QtGui.QCheckBox( gettext("Show ignored files"), groupbox) vbox.addWidget(self.show_ignored_checkbox) self.connect(self.show_ignored_checkbox, QtCore.SIGNAL("toggled(bool)"), self.show_ignored) # groupbox gets disabled as we are executing. QtCore.QObject.connect(self, QtCore.SIGNAL("disableUi(bool)"), groupbox, QtCore.SLOT("setDisabled(bool)")) self.splitter = QtGui.QSplitter(QtCore.Qt.Vertical) self.splitter.addWidget(groupbox) self.splitter.addWidget(self.make_default_status_box()) self.splitter.setStretchFactor(0, 10) self.restoreSplitterSizes([150, 150]) layout = QtGui.QVBoxLayout(self) layout.addWidget(self.throbber) layout.addWidget(self.splitter) layout.addWidget(self.buttonbox) self.throbber.show()
def assertSelectedPaths(self, treewidget, paths): if 0: treewidget = TreeWidget() selected = [item.path for item in treewidget.tree_model.iter_checked()] # we do not care for the order in this test. self.assertEqual(set(selected), set(paths))
def test_show_widget(self): widget = TreeWidget() self.widget = widget self.run_model_tests() self.addCleanup(widget.close) # make the widget bigger so that we can see what is going on. widget.setGeometry(0, 0, 500, 500) widget.show() QtCore.QCoreApplication.processEvents() widget.set_tree(self.tree, self.branch, changes_mode=self.changes_mode) self.run_model_tests() widget.update() QtCore.QCoreApplication.processEvents() widget.expandAll() self.run_model_tests() widget.update() QtCore.QCoreApplication.processEvents() self.modify_tree(self, self.tree) widget.refresh() self.run_model_tests() widget.update() QtCore.QCoreApplication.processEvents() widget.expandAll() self.run_model_tests() widget.update() QtCore.QCoreApplication.processEvents()
def filter_context_menu(): TreeWidget.filter_context_menu(self.filelist) self.filelist.action_add.setVisible(False) self.filelist.action_revert.setVisible(False)
def __init__(self, tree, selected_list, dialog=True, parent=None, local=None, message=None, ui_mode=True, backup=True): self.tree = tree self.has_pending_merges = len(tree.get_parent_ids()) > 1 self.initial_selected_list = selected_list SubProcessDialog.__init__(self, gettext("Revert"), name="revert", default_size=(400, 400), ui_mode=ui_mode, dialog=dialog, parent=parent, hide_progress=True) self.throbber = ThrobberWidget(self) # Display the list of changed files self.file_groupbox = QtGui.QGroupBox( gettext("Select changes to revert"), self) self.filelist = TreeWidget(self.file_groupbox) self.filelist.throbber = self.throbber self.filelist.tree_model.set_select_all_kind('versioned') def filter_context_menu(): TreeWidget.filter_context_menu(self.filelist) self.filelist.action_add.setVisible(False) self.filelist.action_revert.setVisible(False) self.filelist.filter_context_menu = filter_context_menu self.selectall_checkbox = SelectAllCheckBox(self.filelist, self.file_groupbox) self.selectall_checkbox.setEnabled(True) self.no_backup_checkbox = QtGui.QCheckBox( gettext('Do not save backups of reverted files')) if not backup: self.no_backup_checkbox.setCheckState(QtCore.Qt.Checked) self.no_backup_checkbox.setEnabled(True) filesbox = QtGui.QVBoxLayout(self.file_groupbox) filesbox.addWidget(self.filelist) filesbox.addWidget(self.selectall_checkbox) filesbox.addWidget(self.no_backup_checkbox) if self.has_pending_merges: self.file_groupbox.setCheckable(True) self.merges_groupbox = QtGui.QGroupBox( gettext("Forget pending merges")) self.merges_groupbox.setCheckable(True) # This keeps track of what the merges_groupbox was before the # select all changes it, so that it can put it back to the state # it was. self.merges_base_checked = True self.pending_merges = PendingMergesList(self.processEvents, self.throbber, self) merges_box = QtGui.QVBoxLayout(self.merges_groupbox) merges_box.addWidget(self.pending_merges) self.connect(self.selectall_checkbox, QtCore.SIGNAL("stateChanged(int)"), self.selectall_state_changed) self.connect(self.merges_groupbox, QtCore.SIGNAL("clicked(bool)"), self.merges_clicked) self.connect(self.file_groupbox, QtCore.SIGNAL("clicked(bool)"), self.file_groupbox_clicked) self.connect( self.filelist.tree_model, QtCore.SIGNAL("dataChanged(QModelIndex, QModelIndex)"), self.filelist_data_changed) # groupbox gets disabled as we are executing. QtCore.QObject.connect(self, QtCore.SIGNAL("disableUi(bool)"), self.file_groupbox, QtCore.SLOT("setDisabled(bool)")) self.splitter = QtGui.QSplitter(QtCore.Qt.Vertical) self.splitter.addWidget(self.file_groupbox) if self.has_pending_merges: self.splitter.addWidget(self.merges_groupbox) self.splitter.addWidget(self.make_default_status_box()) self.splitter.setStretchFactor(0, 10) self.restoreSplitterSizes([150, 150]) layout = QtGui.QVBoxLayout(self) layout.addWidget(self.throbber) layout.addWidget(self.splitter) # Diff button to view changes in files selected to revert self.diffbuttons = DiffButtons(self) self.diffbuttons.setToolTip( gettext("View changes in files selected to revert")) self.connect(self.diffbuttons, QtCore.SIGNAL("triggered(QString)"), self.show_diff_for_checked) hbox = QtGui.QHBoxLayout() hbox.addWidget(self.diffbuttons) hbox.addWidget(self.buttonbox) layout.addLayout(hbox) self.throbber.show()
class RevertWindow(SubProcessDialog): def __init__(self, tree, selected_list, dialog=True, parent=None, local=None, message=None, ui_mode=True, backup=True): self.tree = tree self.has_pending_merges = len(tree.get_parent_ids()) > 1 self.initial_selected_list = selected_list SubProcessDialog.__init__(self, gettext("Revert"), name="revert", default_size=(400, 400), ui_mode=ui_mode, dialog=dialog, parent=parent, hide_progress=True) self.throbber = ThrobberWidget(self) # Display the list of changed files self.file_groupbox = QtGui.QGroupBox( gettext("Select changes to revert"), self) self.filelist = TreeWidget(self.file_groupbox) self.filelist.throbber = self.throbber self.filelist.tree_model.set_select_all_kind('versioned') def filter_context_menu(): TreeWidget.filter_context_menu(self.filelist) self.filelist.action_add.setVisible(False) self.filelist.action_revert.setVisible(False) self.filelist.filter_context_menu = filter_context_menu self.selectall_checkbox = SelectAllCheckBox(self.filelist, self.file_groupbox) self.selectall_checkbox.setEnabled(True) self.no_backup_checkbox = QtGui.QCheckBox( gettext('Do not save backups of reverted files')) if not backup: self.no_backup_checkbox.setCheckState(QtCore.Qt.Checked) self.no_backup_checkbox.setEnabled(True) filesbox = QtGui.QVBoxLayout(self.file_groupbox) filesbox.addWidget(self.filelist) filesbox.addWidget(self.selectall_checkbox) filesbox.addWidget(self.no_backup_checkbox) if self.has_pending_merges: self.file_groupbox.setCheckable(True) self.merges_groupbox = QtGui.QGroupBox( gettext("Forget pending merges")) self.merges_groupbox.setCheckable(True) # This keeps track of what the merges_groupbox was before the # select all changes it, so that it can put it back to the state # it was. self.merges_base_checked = True self.pending_merges = PendingMergesList(self.processEvents, self.throbber, self) merges_box = QtGui.QVBoxLayout(self.merges_groupbox) merges_box.addWidget(self.pending_merges) self.connect(self.selectall_checkbox, QtCore.SIGNAL("stateChanged(int)"), self.selectall_state_changed) self.connect(self.merges_groupbox, QtCore.SIGNAL("clicked(bool)"), self.merges_clicked) self.connect(self.file_groupbox, QtCore.SIGNAL("clicked(bool)"), self.file_groupbox_clicked) self.connect( self.filelist.tree_model, QtCore.SIGNAL("dataChanged(QModelIndex, QModelIndex)"), self.filelist_data_changed) # groupbox gets disabled as we are executing. QtCore.QObject.connect(self, QtCore.SIGNAL("disableUi(bool)"), self.file_groupbox, QtCore.SLOT("setDisabled(bool)")) self.splitter = QtGui.QSplitter(QtCore.Qt.Vertical) self.splitter.addWidget(self.file_groupbox) if self.has_pending_merges: self.splitter.addWidget(self.merges_groupbox) self.splitter.addWidget(self.make_default_status_box()) self.splitter.setStretchFactor(0, 10) self.restoreSplitterSizes([150, 150]) layout = QtGui.QVBoxLayout(self) layout.addWidget(self.throbber) layout.addWidget(self.splitter) # Diff button to view changes in files selected to revert self.diffbuttons = DiffButtons(self) self.diffbuttons.setToolTip( gettext("View changes in files selected to revert")) self.connect(self.diffbuttons, QtCore.SIGNAL("triggered(QString)"), self.show_diff_for_checked) hbox = QtGui.QHBoxLayout() hbox.addWidget(self.diffbuttons) hbox.addWidget(self.buttonbox) layout.addLayout(hbox) self.throbber.show() def show(self): SubProcessDialog.show(self) QtCore.QTimer.singleShot(1, self.initial_load) @runs_in_loading_queue @ui_current_widget @reports_exception() def initial_load(self): self.filelist.tree_model.checkable = True #fmodel.setFilter(fmodel.UNVERSIONED, False) if self.initial_selected_list is None and not self.has_pending_merges: self.initial_selected_list = [] self.filelist.set_tree( self.tree, changes_mode=True, want_unversioned=False, initial_checked_paths=self.initial_selected_list) self.filelist_checked_base = list( self.filelist.tree_model.iter_checked()) self.selectall_checkbox.update_state() self.processEvents() if self.has_pending_merges: self.pending_merges.load_tree(self.tree) self.processEvents() self.throbber.hide() # The logic for the next 4 methods is like this: # * Either file_groupbox or merges_groupbox or both must be checked, # never neither. # * If merges_groupbox is checked, all files must be checked. If a file is # unchecked, merges_groupbox must be unchecked. # Unless: # * file_groupbox is unchecked - then all files are unchecked. # # We keep a recored of what was checked, so that we we change something, # and then later we go back to a state where that change was not necessary, # we can return to what it was. This is stored in merges_base_checked, and # filelist_checked_base. def selectall_state_changed(self, state): if state == QtCore.Qt.Checked: self.merges_groupbox.setChecked(self.merges_base_checked) elif self.file_groupbox.isChecked(): self.merges_groupbox.setChecked(False) def merges_clicked(self, state): self.merges_base_checked = state if state: if self.file_groupbox.isChecked(): self.selectall_checkbox.clicked(QtCore.Qt.Checked) else: self.selectall_checkbox.clicked(QtCore.Qt.Unchecked) if not state: self.file_groupbox.setChecked(True) self.filelist.tree_model.set_checked_items( self.filelist_checked_base, ignore_no_file_error=True) def file_groupbox_clicked(self, state): if not state: self.merges_groupbox.setChecked(True) self.selectall_checkbox.clicked(QtCore.Qt.Unchecked) if state: if not self.merges_base_checked: self.filelist.tree_model.set_checked_items( self.filelist_checked_base, ignore_no_file_error=True) else: self.selectall_checkbox.clicked(QtCore.Qt.Checked) def filelist_data_changed(self, start, end): if (self.file_groupbox.isChecked() and not self.merges_groupbox.isChecked()): self.filelist_checked_base = list( self.filelist.tree_model.iter_checked()) def _is_revert_pending_merges(self): """Return True if selected to revert pending merges, False if not selected, None if there is no pending merges. """ if not self.has_pending_merges: return None return bool(self.merges_groupbox.isChecked()) def _get_files_to_revert(self): return [ ref.path for ref in self.filelist.tree_model.iter_checked( include_unchanged_dirs=False) ] def validate(self): if (self._is_revert_pending_merges() is False and self.selectall_checkbox.checkState() == QtCore.Qt.Checked): if not self.ask_confirmation( gettext("You have selected revert for all changed paths\n" "but keep pending merges.\n\n" "Do you want to continue?")): return False # It doesn't matter if selectall_checkbox checkbox is activated or not - # we really need to check if there are files selected, because you can # check the 'select all' checkbox if there are no files selectable. if not self._is_revert_pending_merges( ) and not self._get_files_to_revert(): self.operation_blocked( gettext("You have not selected anything to revert.")) return False return True def do_start(self): """Revert the files.""" args = ["revert"] if (self._is_revert_pending_merges() is None or (self._is_revert_pending_merges() is False and self.file_groupbox.isChecked())): args.extend(self._get_files_to_revert()) if (self._is_revert_pending_merges() is True and not self.file_groupbox.isChecked()): args.append("--forget-merges") if self.no_backup_checkbox.checkState(): args.append("--no-backup") self.process_widget.do_start(self.tree.basedir, *args) def _saveSize(self, config): SubProcessDialog._saveSize(self, config) self._saveSplitterSizes(config, self.splitter) def show_diff_for_checked(self, ext_diff=None, dialog_action='revert'): """Diff button clicked: show the diff for checked entries. @param ext_diff: selected external diff tool (if any) @param dialog_action: purpose of parent window (main action) """ # XXX make this function universal for both qcommit and qrevert (?) checked = [ref.path for ref in self.filelist.tree_model.iter_checked()] if checked: arg_provider = InternalWTDiffArgProvider( self.tree.basis_tree().get_revision_id(), self.tree, self.tree.branch, self.tree.branch, specific_files=checked) show_diff(arg_provider, ext_diff=ext_diff, parent_window=self, context=self.filelist.diff_context) else: msg = "No changes selected to " + dialog_action QtGui.QMessageBox.warning(self, "QBzr - " + gettext("Diff"), gettext(msg), QtGui.QMessageBox.Ok)