def update_view(self): """ Updates file/folder view :return: """ self.view.clear() qdir = QDir(self.directory) qdir.setNameFilters(self.get_filter_patterns()) filters = QDir.Dirs | QDir.AllDirs | QDir.Files | QDir.NoDot | QDir.NoDotDot if self.show_hidden.isChecked(): filters = filters | QDir.Hidden entries = qdir.entryInfoList(filters=filters, sort=QDir.DirsFirst | QDir.Name) file_path = self.get_file_path('..') if os.path.exists(file_path) and file_path != self.directory: icon = QFileIconProvider().icon(QFileInfo(self.directory)) QListWidgetItem(icon, '..', self.view, 0) for info in entries: icon = QFileIconProvider().icon(info) suf = info.completeSuffix() name, tp = (info.fileName(), 0) if info.isDir() else ( '%s%s' % (info.baseName(), '.%s' % suf if suf else ''), 1) QListWidgetItem(icon, name, self.view, tp) self.view.setFocus()
def get_drives_widget(self): """ Returns a QGroupBox widget that contains all disk drivers of the PC in a vertical layout :return: QGroupBox """ w = QGroupBox('') w.setParent(self) box = layouts.VerticalLayout() box.setAlignment(Qt.AlignTop) places = [(getpass.getuser(), os.path.realpath(os.path.expanduser('~')))] places += [ (q, q) for q in [os.path.realpath(x.absolutePath()) for x in QDir().drives()] ] for label, loc in places: icon = QFileIconProvider().icon(QFileInfo(loc)) drive_btn = QRadioButton(label) drive_btn.setIcon(icon) drive_btn.setToolTip(loc) drive_btn.setProperty('path', loc) drive_btn.clicked.connect(self.go_to_drive) self.places[loc] = drive_btn box.addWidget(drive_btn) w.setLayout(box) return w
def updateFileStatus(self, truncated=False): """ Cache the status of a file. :Parameters: truncated : `bool` If the file was truncated on read, and therefore should never be edited. """ if self.path: self.fileInfo = QFileInfo(self.path) if truncated: self.status = self.FILE_TRUNCATED elif self.fileInfo.isWritable(): self.status = self.FILE_WRITABLE else: self.status = self.FILE_NOT_WRITABLE else: self.status = self.FILE_NEW
def dropEvent(self, event): if event.mimeData().hasUrls(): data = event.mimeData().urls() file_info = QFileInfo(data[0].toLocalFile()) file_name = file_info.absoluteFilePath() if file_name and os.path.isfile(file_name): file_extension = os.path.splitext(file_name)[-1] data_extension = skeleton.SkeletonFileData.get_data_extension() if not data_extension.startswith('.'): data_extension = '.{}'.format(data_extension) if file_extension == data_extension: self._show_bones_hierarchy(file_name) event.accept() elif event.mimeData().hasText(): self.setText(event.mimeData().text()) event.accept()
def parseMatch(self, match, linkPath, nativeAbsPath, fileInfo): """ Parse a RegEx match of a patch to another file. Override for specific language parsing. :Parameters: match RegEx match object linkPath : `str` Displayed file path matched by the RegEx nativeAbsPath : `str` OS-native absolute file path for the file being parsed fileInfo : `QFileInfo` File info object for the file being parsed :Returns: HTML link :Rtype: `str` :Raises ValueError: If path does not exist or cannot be resolved. """ # linkPath = `str` displayed file path # fullPath = `str` absolute file path # Example: <a href="fullPath">linkPath</a> if QFileInfo(linkPath).isAbsolute(): fullPath = QFileInfo(expandPath(linkPath, nativeAbsPath)).absoluteFilePath() logger.debug("Parsed link is absolute (%s). Expanded to %s", linkPath, fullPath) else: # Relative path from the current file to the link. fullPath = fileInfo.dir().absoluteFilePath(expandPath(linkPath, nativeAbsPath)) logger.debug("Parsed link is relative (%s). Expanded to %s", linkPath, fullPath) # Make the HTML link. if self.exists[fullPath]: return '<a href="file://{}">{}</a>'.format(fullPath, linkPath) elif '*' in linkPath or '<UDIM>' in linkPath or '.#.' in linkPath: # Create an orange link for files with wildcards in the path, # designating zero or more files may exist. return '<a title="Multiple files may exist" class="mayNotExist" href="file://{}">{}</a>'.format( fullPath, linkPath) return '<a title="File not found" class="badLink" href="file://{}">{}</a>'.format(fullPath, linkPath)
def parseMatch(self, match, linkPath, nativeAbsPath, fileInfo): """ Parse a RegEx match of a patch to another file. Override for specific language parsing. :Parameters: match RegEx match object linkPath : `str` Displayed file path matched by the RegEx nativeAbsPath : `str` OS-native absolute file path for the file being parsed fileInfo : `QFileInfo` File info object for the file being parsed :Returns: HTML link :Rtype: `str` :Raises ValueError: If path does not exist or cannot be resolved. """ # This group number must be carefully kept in sync based on the default RegEx from the parent class. queryStr = "?line=" + match.group(2) if match.group(2) is not None else "" if QFileInfo(linkPath).isAbsolute(): fullPath = QFileInfo(expandPath(linkPath, nativeAbsPath)).absoluteFilePath() else: # Relative path from the current file to the link. fullPath = fileInfo.dir().absoluteFilePath(expandPath(linkPath, nativeAbsPath)) # Make the HTML link. if self.exists[fullPath]: return '<a href="file://{}{}">{}</a>'.format(fullPath, queryStr, linkPath) elif '*' in linkPath or '<UDIM>' in linkPath or '.#.' in linkPath: # Create an orange link for files with wildcards in the path, # designating zero or more files may exist. return '<a title="Multiple files may exist" class="mayNotExist" href="file://{}{}">{}</a>'.format( fullPath, queryStr, linkPath) return '<a title="File not found" class="badLink" href="file://{}{}">{}</a>'.format( fullPath, queryStr, linkPath)
def icon_from_filename(file_path): """ Returns icon of the given file path :param file_path: str :return: QIcon """ global _ICON_PROVIDER if not _ICON_PROVIDER: _ICON_PROVIDER = QFileIconProvider() file_info = QFileInfo(file_path) file_icon = _ICON_PROVIDER.icon(file_info) if not file_icon or file_icon.isNull(): return QApplication.style().standardIcon(QStyle.SP_FileIcon) else: return file_icon
class FileStatus(object): """ File status cache class allowing overriding with additional statuses for custom integration of things like a revision control system. """ FILE_NEW = 0 # New file, never saved. Ok to edit, save. FILE_NOT_WRITABLE = 1 # File not writable. Nothing allowed. FILE_WRITABLE = 2 # File writable. Ok to edit, save. FILE_TRUNCATED = 4 # File was truncated on read. Nothing allowed. def __init__(self, url=None, update=True, truncated=False): """ Initialize the FileStatus cache :Parameters: url : `QtCore.QUrl` File URL update : `bool` Immediately update file status or not, like checking if it's writable. truncated : `bool` If the file was truncated on read, and therefore should never be edited. """ self.url = url if url else QUrl() self.path = "" if self.url.isEmpty() else self.url.toLocalFile() self.status = self.FILE_NEW self.fileInfo = None if update: self.updateFileStatus(truncated) def updateFileStatus(self, truncated=False): """ Cache the status of a file. :Parameters: truncated : `bool` If the file was truncated on read, and therefore should never be edited. """ if self.path: if self.fileInfo is None: self.fileInfo = QFileInfo(self.path) self.fileInfo.setCaching(False) if truncated: self.status = self.FILE_TRUNCATED elif self.fileInfo.isWritable(): self.status = self.FILE_WRITABLE else: self.status = self.FILE_NOT_WRITABLE else: self.status = self.FILE_NEW @property def icon(self): """ Get an icon to display representing the file's status. :Returns: Icon (may be blank) :Rtype: `QIcon` """ if self.status == self.FILE_NOT_WRITABLE: return QIcon(":images/images/lock") return QIcon() @property def text(self): """ Get a status string to display for the file. :Returns: File status (may be an empty string) :Rtype: `str` """ if self.status == self.FILE_NEW: return "" elif self.status == self.FILE_NOT_WRITABLE: return "File not writable" elif self.status == self.FILE_WRITABLE: return "File writable" elif self.status == self.FILE_TRUNCATED: return "File too large to fully display" else: logger.error("Unexpected file status code: %s", self.status) return "" @property def writable(self): """ Get if the file is writable. :Returns: If the file is writable :Rtype: `bool` """ return self.status in [self.FILE_NEW, self.FILE_WRITABLE]
def parseMatch(self, match, linkPath, nativeAbsPath, fileInfo): """ Parse a RegEx match of a path to another file. Override for specific language parsing. :Parameters: match RegEx match object linkPath : `str` Displayed file path matched by the RegEx nativeAbsPath : `str` OS-native absolute file path for the file being parsed fileInfo : `QFileInfo` File info object for the file being parsed :Returns: HTML link :Rtype: `str` :Raises ValueError: If path does not exist or cannot be resolved. """ expanded_path = utils.expandPath( linkPath, nativeAbsPath, self.sdf_format_args, extractedDir=self.extractedDir) if QFileInfo(linkPath).isAbsolute(): fullPath = QFileInfo(expanded_path).absoluteFilePath() logger.debug("Parsed link is absolute (%s). Expanded to %s", linkPath, fullPath) else: # Relative path from the current file to the link. fullPath = fileInfo.dir().absoluteFilePath(expanded_path) logger.debug("Parsed link is relative (%s). Expanded to %s", linkPath, fullPath) # Override any previously set sdf format args. local_sdf_args = self.sdf_format_args.copy() if match.group(3): for kv in match.group(3).split("&"): k, v = kv.split("=", 1) expanded_path = utils.expandPath( v, nativeAbsPath, self.sdf_format_args, extractedDir=self.extractedDir) local_sdf_args[k] = expanded_path.replace("&", "+").replace("=", ":") if local_sdf_args: queryParams = ["sdf=" + "+".join("{}:{}".format(k, v) for k, v in sorted(local_sdf_args.items(), key=lambda x: x[0]))] else: queryParams = [] # .usdz file references (e.g. @set.usdz[foo/bar.usd]@) if match.group(2): queryParams.append("layer=" + match.group(2)) # Propogate the extracted archive if this resolved file is in the same archive if self.extractedDir and fullPath.startswith(self.extractedDir + sep): queryParams.append("extractedDir=" + self.extractedDir) # Make the HTML link. if self.exists[fullPath]: _, fullPathExt = splitext(fullPath) if fullPathExt == ".usdc" or (fullPathExt == ".usd" and utils.isUsdCrate(fullPath)): queryParams.insert(0, "binary=1") return '<a class="binary" href="file://{}?{}">{}</a>'.format(fullPath, "&".join(queryParams), linkPath) queryStr = "?" + "&".join(queryParams) if queryParams else "" return '<a href="file://{}{}">{}</a>'.format(fullPath, queryStr, linkPath) elif '*' in linkPath or '<UDIM>' in linkPath or '.#.' in linkPath: # Create an orange link for files with wildcards in the path, # designating zero or more files may exist. queryStr = "?" + "&".join(queryParams) if queryParams else "" return '<a title="Multiple files may exist" class="mayNotExist" href="file://{}{}">{}</a>'.format( fullPath, queryStr, linkPath) queryStr = "?" + "&".join(queryParams) if queryParams else "" return '<a title="File not found" class="badLink" href="file://{}{}">{}</a>'.format( fullPath, queryStr, linkPath)