def _setup_ui(self): self.setLayout(QtGui.QVBoxLayout()) self._task_combo = ComboBox() self._task_combo.addItem('Loading...', {'loading': True}) self._task_combo.currentIndexChanged.connect(self._task_changed) self._name_combo = ComboBox() self._name_combo.addItem('Loading...', {'loading': True}) self._name_combo.addItem('Create new stream...', {'new': True}) self._name_combo.currentIndexChanged.connect(self._name_changed) self._tasksLabel = QtGui.QLabel("Task") self.layout().addLayout(hbox( vbox(self._tasksLabel, self._task_combo), vbox("Publish Stream", self._name_combo), spacing=4 )) self._name_field = QtGui.QLineEdit(self._basename) self._name_field.setEnabled(False) self._name_field.editingFinished.connect(self._on_name_edited) self._version_spinbox = QtGui.QSpinBox() self._version_spinbox.setMinimum(1) self._version_spinbox.setMaximum(9999) self._version_spinbox.valueChanged.connect(self._on_version_changed) self._version_warning_issued = False self.layout().addLayout(hbox( vbox("Name", self._name_field), vbox("Version", self._version_spinbox), spacing=4 )) # Get publish data in the background. self.loaded_publishes.connect(self._populate_existing_data) self._thread = QtCore.QThread() self._thread.run = self._fetch_existing_data self._thread.start() self._description = QtGui.QTextEdit('') self._description.setMaximumHeight(100) self._thumbnail_path = None self._thumbnail_canvas = QtGui.QLabel() self._thumbnail_canvas.setFrameShadow(QtGui.QFrame.Sunken) self._thumbnail_canvas.setFrameShape(QtGui.QFrame.Panel) self._thumbnail_canvas.setToolTip("Click to specify part of screen.") self._thumbnail_canvas.mouseReleaseEvent = self.take_partial_screenshot self.layout().addLayout(hbox( vbox("Describe Your Changes", self._description), vbox("Thumbnail", self._thumbnail_canvas), )) self._movie_path = QtGui.QLineEdit() self._movie_browse = QtGui.QPushButton(icon('silk/folder', size=12, as_icon=True), "Browse") self._movie_browse.clicked.connect(self._on_movie_browse) self._movie_layout = hbox(self._movie_path, self._movie_browse) self.layout().addLayout(vbox("Path to Movie or Frames (to be copied to publish)", self._movie_layout, spacing=4)) self._movie_browse.setFixedHeight(self._movie_path.sizeHint().height()) self._movie_browse.setFixedWidth(self._movie_browse.sizeHint().width() + 2) self._promote_checkbox = QtGui.QCheckBox("Promote to 'Version' for review") # self.layout().addWidget(self._promote_checkbox) self._timelog_spinbox = TimeSpinner() add_hour = QtGui.QPushButton("+1 Hour") add_hour.setFixedHeight(self._timelog_spinbox.sizeHint().height()) @add_hour.clicked.connect def on_add_hour(): self._timelog_spinbox.setValue(self._timelog_spinbox.value() + 60) add_day = QtGui.QPushButton("+1 Day") add_day.setFixedHeight(self._timelog_spinbox.sizeHint().height()) @add_day.clicked.connect def on_add_day(): self._timelog_spinbox.setValue(self._timelog_spinbox.value() + 60 * 8) self.layout().addLayout(hbox( vbox("Time to Log", hbox(self._timelog_spinbox, "hrs:mins", add_hour, add_day)), vbox("Review", self._promote_checkbox), ))
class Widget(QtGui.QWidget): # Windows should hide on these. beforeScreenshot = QtCore.pyqtSignal() afterScreenshot = QtCore.pyqtSignal() # Need a signal to communicate across threads. loaded_publishes = QtCore.pyqtSignal(object, object) def __init__(self, exporter): super(Widget, self).__init__() self._exporter = exporter self._existing_streams = set() basename = os.path.basename(exporter.filename_hint) basename = os.path.splitext(basename)[0] self._basename = re.sub(r'_*[rv]\d+', '', basename) self._setup_ui() # First screenshot. self.take_full_screenshot() def _setup_ui(self): self.setLayout(QtGui.QVBoxLayout()) self._task_combo = ComboBox() self._task_combo.addItem('Loading...', {'loading': True}) self._task_combo.currentIndexChanged.connect(self._task_changed) self._name_combo = ComboBox() self._name_combo.addItem('Loading...', {'loading': True}) self._name_combo.addItem('Create new stream...', {'new': True}) self._name_combo.currentIndexChanged.connect(self._name_changed) self._tasksLabel = QtGui.QLabel("Task") self.layout().addLayout(hbox( vbox(self._tasksLabel, self._task_combo), vbox("Publish Stream", self._name_combo), spacing=4 )) self._name_field = QtGui.QLineEdit(self._basename) self._name_field.setEnabled(False) self._name_field.editingFinished.connect(self._on_name_edited) self._version_spinbox = QtGui.QSpinBox() self._version_spinbox.setMinimum(1) self._version_spinbox.setMaximum(9999) self._version_spinbox.valueChanged.connect(self._on_version_changed) self._version_warning_issued = False self.layout().addLayout(hbox( vbox("Name", self._name_field), vbox("Version", self._version_spinbox), spacing=4 )) # Get publish data in the background. self.loaded_publishes.connect(self._populate_existing_data) self._thread = QtCore.QThread() self._thread.run = self._fetch_existing_data self._thread.start() self._description = QtGui.QTextEdit('') self._description.setMaximumHeight(100) self._thumbnail_path = None self._thumbnail_canvas = QtGui.QLabel() self._thumbnail_canvas.setFrameShadow(QtGui.QFrame.Sunken) self._thumbnail_canvas.setFrameShape(QtGui.QFrame.Panel) self._thumbnail_canvas.setToolTip("Click to specify part of screen.") self._thumbnail_canvas.mouseReleaseEvent = self.take_partial_screenshot self.layout().addLayout(hbox( vbox("Describe Your Changes", self._description), vbox("Thumbnail", self._thumbnail_canvas), )) self._movie_path = QtGui.QLineEdit() self._movie_browse = QtGui.QPushButton(icon('silk/folder', size=12, as_icon=True), "Browse") self._movie_browse.clicked.connect(self._on_movie_browse) self._movie_layout = hbox(self._movie_path, self._movie_browse) self.layout().addLayout(vbox("Path to Movie or Frames (to be copied to publish)", self._movie_layout, spacing=4)) self._movie_browse.setFixedHeight(self._movie_path.sizeHint().height()) self._movie_browse.setFixedWidth(self._movie_browse.sizeHint().width() + 2) self._promote_checkbox = QtGui.QCheckBox("Promote to 'Version' for review") # self.layout().addWidget(self._promote_checkbox) self._timelog_spinbox = TimeSpinner() add_hour = QtGui.QPushButton("+1 Hour") add_hour.setFixedHeight(self._timelog_spinbox.sizeHint().height()) @add_hour.clicked.connect def on_add_hour(): self._timelog_spinbox.setValue(self._timelog_spinbox.value() + 60) add_day = QtGui.QPushButton("+1 Day") add_day.setFixedHeight(self._timelog_spinbox.sizeHint().height()) @add_day.clicked.connect def on_add_day(): self._timelog_spinbox.setValue(self._timelog_spinbox.value() + 60 * 8) self.layout().addLayout(hbox( vbox("Time to Log", hbox(self._timelog_spinbox, "hrs:mins", add_hour, add_day)), vbox("Review", self._promote_checkbox), )) def _fetch_existing_data(self): try: sgfs = SGFS() tasks = sgfs.entities_from_path(self._exporter.workspace) if not tasks: raise ValueError('No entities in workspace %r' % self._exporter.workspace) if any(x['type'] != 'Task' for x in tasks): raise ValueError('Non-Task entity in workspace %r' % self._exporter.workspace) publishes = sgfs.session.find( 'PublishEvent', [ ('sg_link.Task.id', 'in') + tuple(x['id'] for x in tasks), ('sg_type', 'is', self._exporter.publish_type), ('sg_version', 'greater_than', 0), # Skipped failures. ], [ 'code', 'sg_version' ] ) except Exception as e: self._task_combo.clear() self._task_combo.addItem('Loading Error! %s' % e, {}) raise else: self.loaded_publishes.emit(tasks, publishes) def _populate_existing_data(self, tasks, publishes): if tasks: entity = tasks[0].fetch('entity') name = entity.get('code') or entity.get('name') if name: self._tasksLabel.setText('Task on %s %s' % (entity['type'], name)) history = self._exporter.get_previous_publish_ids() select = None publishes.sort(key=lambda p: p['sg_version']) for t_i, task in enumerate(tasks): name_to_publish = {} for publish in publishes: if publish['sg_link'] is not task: continue self._existing_streams.add((task['id'], publish['code'])) name = publish['code'] name_to_publish[name] = publish if publish['id'] in history: select = t_i, name self._task_combo.addItem('%s - %s' % task.fetch(('step.Step.short_name', 'content')), { 'task': task, 'publishes': name_to_publish, }) if 'loading' in self._task_combo.itemData(0): if self._task_combo.currentIndex() == 0: self._task_combo.setCurrentIndex(1) self._task_combo.removeItem(0) if select: self._task_combo.setCurrentIndex(select[0]) for i in xrange(self._name_combo.count()): data = self._name_combo.itemData(i) if data and data.get('name') == select[1]: self._name_combo.setCurrentIndex(i) break def _task_changed(self, index): data = self._name_combo.currentData() if not data: return was_new = 'new' in data or 'loading' in data self._name_combo.clear() data = self._task_combo.currentData() or {} for name, publish in sorted(data.get('publishes', {}).iteritems()): self._name_combo.addItem('%s (v%04d)' % (name, publish['sg_version']), {'name': name, 'publish': publish}) self._name_combo.addItem('Create New Stream...', {'new': True}) if was_new: self._name_combo.setCurrentIndex(self._name_combo.count() - 1) else: self._name_combo.setCurrentIndex(0) def _name_changed(self, index): data = self._name_combo.itemData(index) if not data: return self._name_field.setEnabled('new' in data) self._name_field.setText(data.get('name', self._basename)) self._version_spinbox.setValue(data.get('publish', {}).get('sg_version', 0) + 1) def _on_name_edited(self): name = str(self._name_field.text()) name = re.sub(r'\W+', '_', name).strip('_') self._name_field.setText(name) def _on_version_changed(self, new_value): data = self._name_combo.itemData(self._name_combo.currentIndex()) if data.get('publish') and new_value != data['publish']['sg_version'] + 1 and not self._version_warning_issued: res = QtGui.QMessageBox.warning(None, "Manual Versions?", "Are you sure you want to change the version?\n" "The next one has already been selected for you...", QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Cancel ) if res & QtGui.QMessageBox.Cancel: self._version_spinbox.setValue(data['publish']['sg_version'] + 1) return self._version_warning_issued = True def _on_movie_browse(self): existing = str(self._movie_path.text()) dialog = QtGui.QFileDialog(None, "Select Movie or First Frame") dialog.setFilter('Movie or Frame (*.mov *.exr *.tif *.tiff *.jpg *.jpeg)') dialog.setFileMode(dialog.ExistingFile) dialog.setDirectory(os.path.dirname(existing) if existing else os.getcwd()) if existing: dialog.selectFile(existing) if not dialog.exec_(): return files = dialog.selectedFiles() path = str(files.First()) self.setFrames(path) def setFrames(self, path): self._movie_path.setText(path) if path: self._promote_checkbox.setCheckState(Qt.Checked) def take_full_screenshot(self): pass def take_partial_screenshot(self, *args): path = tempfile.NamedTemporaryFile(suffix=".png", prefix="screenshot", delete=False).name self.beforeScreenshot.emit() if sys.platform.startswith('darwin'): # use built-in screenshot command on the mac proc = subprocess.Popen(['screencapture', '-mis', path]) else: proc = subprocess.Popen(['import', path]) proc.wait() self.afterScreenshot.emit() if os.stat(path).st_size: self.setThumbnail(path) def setThumbnail(self, path): self._thumbnail_path = path pixmap = QtGui.QPixmap(path).scaled(200, 100, Qt.KeepAspectRatio, Qt.SmoothTransformation) self._thumbnail_canvas.setPixmap(pixmap) self._thumbnail_canvas.setFixedSize(pixmap.size()) def name(self): data = self._name_combo.currentData() return data.get('name', str(self._name_field.text())) def description(self): return str(self._description.toPlainText()) def version(self): return self._version_spinbox.value() def thumbnail_path(self): return self._thumbnail_path def _path_is_image(self, path): if os.path.splitext(path)[1][1:].lower() in ( 'jpg', 'jpeg', 'tif', 'tiff', 'exr', ): return path def frames_path(self): path = str(self._movie_path.text()) if path and self._path_is_image(path): return path return None def movie_path(self): path = str(self._movie_path.text()) if path and not self._path_is_image(path): return path return None def safety_check(self, **kwargs): # Check that the name is unique for publishes on this task. task = self._task_combo.currentData().get('task') existing_name = self._name_combo.currentData().get('name') new_name = str(self._name_field.text()) if existing_name is None and (task['id'], new_name) in self._existing_streams: print 'XXX', task['id'], repr(existing_name), repr(new_name) print self._existing_streams QtGui.QMessageBox.critical(self, "Name Collision", "You cannot create a new stream with the same name as an" " existing one. Please select the existing stream or enter a" " unique name.", ) # Fatal. return False # Promoting to version without a movie. if self._promote_checkbox.isChecked() and not (self.frames_path() or self.movie_path()): QtGui.QMessageBox.critical(self, "Review Version Without Movie", "You cannot promote a publish for review without frames or a" " movie.", ) # Fatal. return False # Promoting to version without a timelog. if self._promote_checkbox.isChecked() and not self._timelog_spinbox.value(): res = QtGui.QMessageBox.warning(self, "Version without Time Log", "Are you sure that this version did not take you any time?", QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No, ) if res & QtGui.QMessageBox.No: return False return True def export(self, **kwargs): with ticket_ui_context(pass_through=PublishSafetyError): return self._export(kwargs) def _export(self, kwargs): if not self.safety_check(**kwargs): raise PublishSafetyError() task_data = self._task_combo.currentData() task = task_data.get('task') if not task: sgfs = SGFS() tasks = sgfs.entities_from_path(self._exporter.workspace, 'Task') if not tasks: raise ValueError('Could not find SGFS tagged entities') task = tasks[0] stream_data = self._name_combo.currentData() parent = stream_data.get('publish') publisher = self._exporter.publish(task, name=self.name(), description=self.description(), version=self.version(), parent=parent, thumbnail_path=self.thumbnail_path(), frames_path=self.frames_path(), movie_path=self.movie_path(), export_kwargs=kwargs, ) if self._promote_checkbox.isChecked(): # progress.setLabelText('Creating Version for Review...') promotion_fields = self._exporter.fields_for_review_version(publisher, **kwargs) print "PROMOTE", promotion_fields publisher.promote_for_review(**promotion_fields) # Create the timelog. minutes = self._timelog_spinbox.value() if minutes: # progress.setLabelText('Logging time...') publisher.sgfs.session.create('TimeLog', { 'project': publisher.entity.project(), 'entity': publisher.link, 'user': publisher.sgfs.session.guess_user(), 'duration': minutes, 'description': '%s_v%04d' % (publisher.name, publisher.version), 'date': datetime.datetime.utcnow().date(), }) # progress.hide() return publisher
class Widget(QtGui.QWidget): # Windows should hide on these. beforeScreenshot = QtCore.pyqtSignal() afterScreenshot = QtCore.pyqtSignal() # Need a signal to communicate across threads. loaded_publishes = QtCore.pyqtSignal(object, object) def __init__(self, exporter): super(Widget, self).__init__() self._exporter = exporter self._existing_streams = set() basename = os.path.basename(exporter.filename_hint) basename = os.path.splitext(basename)[0] basename = re.sub(r'[^\w-]+', '_', basename) self._basename = re.sub(r'_*[rv]\d+', '', basename) self._setup_ui() # First screenshot. self.take_full_screenshot() def _setup_ui(self): self.setLayout(QtGui.QVBoxLayout()) self._task_combo = ComboBox() self._task_combo.addItem('Loading...', {'loading': True}) self._task_combo.currentIndexChanged.connect(self._task_changed) self._name_combo = ComboBox() self._name_combo.addItem('Loading...', {'loading': True}) self._name_combo.addItem('Create new stream...', {'new': True}) self._name_combo.currentIndexChanged.connect(self._name_changed) self._tasksLabel = QtGui.QLabel("Task") self.layout().addLayout(hbox( vbox(self._tasksLabel, self._task_combo), vbox("Publish Stream", self._name_combo), spacing=4 )) self._name_field = QtGui.QLineEdit(self._basename) self._name_field.setEnabled(False) self._name_field.editingFinished.connect(self._on_name_edited) self._version_spinbox = QtGui.QSpinBox() self._version_spinbox.setMinimum(1) self._version_spinbox.setMaximum(9999) self._version_spinbox.valueChanged.connect(self._on_version_changed) self._version_warning_issued = False self.layout().addLayout(hbox( vbox("Name", self._name_field), vbox("Version", self._version_spinbox), spacing=4 )) # Get publish data in the background. self.loaded_publishes.connect(self._populate_existing_data) self._thread = QtCore.QThread() self._thread.run = self._fetch_existing_data self._thread.start() self._description = QtGui.QTextEdit('') self._description.setMaximumHeight(100) self._thumbnail_path = None self._thumbnail_canvas = QtGui.QLabel() self._thumbnail_canvas.setFrameShadow(QtGui.QFrame.Sunken) self._thumbnail_canvas.setFrameShape(QtGui.QFrame.Panel) self._thumbnail_canvas.setToolTip("Click to specify part of screen.") self._thumbnail_canvas.mouseReleaseEvent = self.take_partial_screenshot self.layout().addLayout(hbox( vbox("Describe Your Changes", self._description), vbox("Thumbnail", self._thumbnail_canvas), )) self._movie_path = QtGui.QLineEdit() self._movie_browse = QtGui.QPushButton(icon('silk/folder', size=12, as_icon=True), "Browse") self._movie_browse.clicked.connect(self._on_movie_browse) self._movie_layout = hbox(self._movie_path, self._movie_browse) self.layout().addLayout(vbox("Path to Movie or Frames (to be copied to publish)", self._movie_layout, spacing=4)) self._movie_browse.setFixedHeight(self._movie_path.sizeHint().height()) self._movie_browse.setFixedWidth(self._movie_browse.sizeHint().width() + 2) self._promote_checkbox = QtGui.QCheckBox("Promote to 'Version' for review") # self.layout().addWidget(self._promote_checkbox) self._timelog_spinbox = TimeSpinner() add_hour = QtGui.QPushButton("+1 Hour") add_hour.setFixedHeight(self._timelog_spinbox.sizeHint().height()) @add_hour.clicked.connect def on_add_hour(): self._timelog_spinbox.setValue(self._timelog_spinbox.value() + 60) add_day = QtGui.QPushButton("+1 Day") add_day.setFixedHeight(self._timelog_spinbox.sizeHint().height()) @add_day.clicked.connect def on_add_day(): self._timelog_spinbox.setValue(self._timelog_spinbox.value() + 60 * 8) self.layout().addLayout(hbox( vbox("Time to Log", hbox(self._timelog_spinbox, "hrs:mins", add_hour, add_day)), vbox("Review", self._promote_checkbox), )) def _fetch_existing_data(self): try: sgfs = SGFS() tasks = sgfs.entities_from_path(self._exporter.workspace) if not tasks: raise ValueError('No entities in workspace %r' % self._exporter.workspace) if any(x['type'] != 'Task' for x in tasks): raise ValueError('Non-Task entity in workspace %r' % self._exporter.workspace) publishes = sgfs.session.find( 'PublishEvent', [ ('sg_link.Task.id', 'in') + tuple(x['id'] for x in tasks), ('sg_type', 'is', self._exporter.publish_type), ('sg_version', 'greater_than', 0), # Skipped failures. ], [ 'code', 'sg_version' ] ) except Exception as e: self._task_combo.clear() self._task_combo.addItem('Loading Error! %s' % e, {}) raise else: self.loaded_publishes.emit(tasks, publishes) def _populate_existing_data(self, tasks, publishes): if tasks: entity = tasks[0].fetch('entity') name = entity.get('code') or entity.get('name') if name: self._tasksLabel.setText('Task on %s %s' % (entity['type'], name)) history = self._exporter.get_previous_publish_ids() select = None publishes.sort(key=lambda p: p['sg_version']) for t_i, task in enumerate(tasks): name_to_publish = {} for publish in publishes: if publish['sg_link'] is not task: continue self._existing_streams.add((task['id'], publish['code'])) name = publish['code'] name_to_publish[name] = publish if publish['id'] in history: select = t_i, name self._task_combo.addItem('%s - %s' % task.fetch(('step.Step.short_name', 'content')), { 'task': task, 'publishes': name_to_publish, }) if 'loading' in self._task_combo.itemData(0): if self._task_combo.currentIndex() == 0: self._task_combo.setCurrentIndex(1) self._task_combo.removeItem(0) if select: self._task_combo.setCurrentIndex(select[0]) for i in xrange(self._name_combo.count()): data = self._name_combo.itemData(i) if data and data.get('name') == select[1]: self._name_combo.setCurrentIndex(i) break def _task_changed(self, index): data = self._name_combo.currentData() if not data: return was_new = 'new' in data or 'loading' in data self._name_combo.clear() data = self._task_combo.currentData() or {} for name, publish in sorted(data.get('publishes', {}).iteritems()): self._name_combo.addItem('%s (v%04d)' % (name, publish['sg_version']), {'name': name, 'publish': publish}) self._name_combo.addItem('Create New Stream...', {'new': True}) if was_new: self._name_combo.setCurrentIndex(self._name_combo.count() - 1) else: self._name_combo.setCurrentIndex(0) def _name_changed(self, index): data = self._name_combo.itemData(index) if not data: return self._name_field.setEnabled('new' in data) self._name_field.setText(data.get('name', self._basename)) self._version_spinbox.setValue(data.get('publish', {}).get('sg_version', 0) + 1) def _on_name_edited(self): name = str(self._name_field.text()) name = re.sub(r'\W+', '_', name).strip('_') self._name_field.setText(name) def _on_version_changed(self, new_value): data = self._name_combo.itemData(self._name_combo.currentIndex()) if data.get('publish') and new_value != data['publish']['sg_version'] + 1 and not self._version_warning_issued: res = QtGui.QMessageBox.warning(None, "Manual Versions?", "Are you sure you want to change the version?\n" "The next one has already been selected for you...", QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Cancel ) if res & QtGui.QMessageBox.Cancel: self._version_spinbox.setValue(data['publish']['sg_version'] + 1) return self._version_warning_issued = True def _on_movie_browse(self): existing = str(self._movie_path.text()) dialog = QtGui.QFileDialog(None, "Select Movie or First Frame") dialog.setFilter('Movie or Frame (*.mov *.exr *.tif *.tiff *.jpg *.jpeg)') dialog.setFileMode(dialog.ExistingFile) dialog.setDirectory(os.path.dirname(existing) if existing else os.getcwd()) if existing: dialog.selectFile(existing) if not dialog.exec_(): return files = dialog.selectedFiles() path = str(files.First()) self.setFrames(path) def setFrames(self, path): self._movie_path.setText(path) if path: self._promote_checkbox.setCheckState(Qt.Checked) def take_full_screenshot(self): pass def take_partial_screenshot(self, *args): path = tempfile.NamedTemporaryFile(suffix=".png", prefix="screenshot", delete=False).name self.beforeScreenshot.emit() if sys.platform.startswith('darwin'): # use built-in screenshot command on the mac proc = subprocess.Popen(['screencapture', '-mis', path]) else: proc = subprocess.Popen(['import', path]) proc.wait() self.afterScreenshot.emit() if os.stat(path).st_size: self.setThumbnail(path) def setThumbnail(self, path): self._thumbnail_path = path pixmap = QtGui.QPixmap(path).scaled(200, 100, Qt.KeepAspectRatio, Qt.SmoothTransformation) self._thumbnail_canvas.setPixmap(pixmap) self._thumbnail_canvas.setFixedSize(pixmap.size()) def name(self): data = self._name_combo.currentData() return data.get('name', str(self._name_field.text())) def description(self): return str(self._description.toPlainText()) def version(self): return self._version_spinbox.value() def thumbnail_path(self): return self._thumbnail_path def _path_is_image(self, path): if os.path.splitext(path)[1][1:].lower() in ( 'jpg', 'jpeg', 'tif', 'tiff', 'exr', ): return path def frames_path(self): path = str(self._movie_path.text()) if path and self._path_is_image(path): return path return None def movie_path(self): path = str(self._movie_path.text()) if path and not self._path_is_image(path): return path return None def safety_check(self, **kwargs): # Check that the name is unique for publishes on this task. task = self._task_combo.currentData().get('task') existing_name = self._name_combo.currentData().get('name') new_name = str(self._name_field.text()) if existing_name is None and (task['id'], new_name) in self._existing_streams: print 'XXX', task['id'], repr(existing_name), repr(new_name) print self._existing_streams QtGui.QMessageBox.critical(self, "Name Collision", "You cannot create a new stream with the same name as an" " existing one. Please select the existing stream or enter a" " unique name.", ) # Fatal. return False # Promoting to version without a movie. if self._promote_checkbox.isChecked() and not (self.frames_path() or self.movie_path()): QtGui.QMessageBox.critical(self, "Review Version Without Movie", "You cannot promote a publish for review without frames or a" " movie.", ) # Fatal. return False # Promoting to version without a timelog. if self._promote_checkbox.isChecked() and not self._timelog_spinbox.value(): res = QtGui.QMessageBox.warning(self, "Version without Time Log", "Are you sure that this version did not take you any time?", QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No, ) if res & QtGui.QMessageBox.No: return False return True def export(self, **kwargs): with ticket_ui_context(pass_through=PublishSafetyError): return self._export(kwargs) def _export(self, kwargs): if not self.safety_check(**kwargs): raise PublishSafetyError() task_data = self._task_combo.currentData() task = task_data.get('task') if not task: sgfs = SGFS() tasks = sgfs.entities_from_path(self._exporter.workspace, 'Task') if not tasks: raise ValueError('Could not find SGFS tagged entities') task = tasks[0] stream_data = self._name_combo.currentData() parent = stream_data.get('publish') # Do the promotion. if self._promote_checkbox.isChecked(): review_version_fields = self._exporter.fields_for_review_version(**kwargs) else: review_version_fields = None publisher = self._exporter.publish(task, name=self.name(), description=self.description(), version=self.version(), parent=parent, thumbnail_path=self.thumbnail_path(), frames_path=self.frames_path(), movie_path=self.movie_path(), review_version_fields=review_version_fields, export_kwargs=kwargs, ) # Create the timelog. minutes = self._timelog_spinbox.value() if minutes: publisher.sgfs.session.create('TimeLog', { 'project': publisher.entity.project(), 'entity': publisher.link, 'user': publisher.sgfs.session.guess_user(), 'duration': minutes, 'description': '%s_v%04d' % (publisher.name, publisher.version), 'date': datetime.datetime.utcnow().date(), }) return publisher