|  | @@ -16,6 +16,30 @@ where possible, comments are duplicated in
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  """
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +helpMsg = """<h1>Dirnotes</h1><h3>Overview</h3>
 | 
	
		
			
				|  |  | +This app allows you to add comments to files. The comments are stored in 
 | 
	
		
			
				|  |  | +a database, and where possible, saved in the xattr (hidden attributes) 
 | 
	
		
			
				|  |  | +field of the file system.
 | 
	
		
			
				|  |  | +<p>
 | 
	
		
			
				|  |  | +You can sort the directory listing by clicking on the column heading.
 | 
	
		
			
				|  |  | +<p>
 | 
	
		
			
				|  |  | +Double click on directory names to navigate the file system. Hover over
 | 
	
		
			
				|  |  | +fields for more information.
 | 
	
		
			
				|  |  | +<p>
 | 
	
		
			
				|  |  | +<h3>xattr extended attributes</h3>
 | 
	
		
			
				|  |  | +The xattr property is handy, but suffers from a few problems:
 | 
	
		
			
				|  |  | +<ul>
 | 
	
		
			
				|  |  | +<li>is not implemented on FAT/VFAT/EXFAT file systems (like USB sticks)
 | 
	
		
			
				|  |  | +<li>xattrs are not (by default) copied with the file when it's duplicated 
 | 
	
		
			
				|  |  | +or backedup
 | 
	
		
			
				|  |  | +<li>xattrs are not available for symlinks
 | 
	
		
			
				|  |  | +<li>many programs which edit files do not preserve the xattrs during file-save
 | 
	
		
			
				|  |  | +</ul>
 | 
	
		
			
				|  |  | +When the database version of a comment differs from the xattr version, the
 | 
	
		
			
				|  |  | +comment box gets a light yellow background.
 | 
	
		
			
				|  |  | +"""
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  import sys,os,argparse,stat
 | 
	
		
			
				|  |  |  #~ from dirWidget import DirWidget
 | 
	
		
			
				|  |  |  from PyQt4.QtGui import *
 | 
	
	
		
			
				|  | @@ -131,18 +155,20 @@ class FileObj():
 | 
	
		
			
				|  |  |  			self.size = s.st_size
 | 
	
		
			
				|  |  |  		self.comment = ''
 | 
	
		
			
				|  |  |  		try:
 | 
	
		
			
				|  |  | -			self.comment = xattr.getxattr(fileName,COMMENT_KEY)
 | 
	
		
			
				|  |  | +			self.comment = xattr.get(fileName,COMMENT_KEY,nofollow=True)
 | 
	
		
			
				|  |  |  		except Exception as e:
 | 
	
		
			
				|  |  | -			#print("comment read on %s failed, execption %s" % (self.fileName,e)) 
 | 
	
		
			
				|  |  | +			print("comment read on %s failed, execption %s" % (self.fileName,e)) 
 | 
	
		
			
				|  |  |  			pass
 | 
	
		
			
				|  |  |  	def getName(self):
 | 
	
		
			
				|  |  |  		return self.fileName
 | 
	
		
			
				|  |  | +	def getFileName(self):
 | 
	
		
			
				|  |  | +		return os.path.split(self.fileName)[1]
 | 
	
		
			
				|  |  |  	def getComment(self):
 | 
	
		
			
				|  |  |  		return self.comment
 | 
	
		
			
				|  |  |  	def setComment(self,newComment):
 | 
	
		
			
				|  |  |  		self.comment = newComment
 | 
	
		
			
				|  |  |  		try:
 | 
	
		
			
				|  |  | -			xattr.setxattr(self.fileName,COMMENT_KEY,self.comment)
 | 
	
		
			
				|  |  | +			xattr.set(self.fileName,COMMENT_KEY,self.comment,nofollow=True)
 | 
	
		
			
				|  |  |  			return True
 | 
	
		
			
				|  |  |  		# we need to move these cases out to a handler 
 | 
	
		
			
				|  |  |  		except Exception as e:
 | 
	
	
		
			
				|  | @@ -169,18 +195,8 @@ class HelpWidget(QDialog):
 | 
	
		
			
				|  |  |  		self.layout = QVBoxLayout(self)
 | 
	
		
			
				|  |  |  		self.tb = QLabel(self)
 | 
	
		
			
				|  |  |  		self.tb.setWordWrap(True)
 | 
	
		
			
				|  |  | -		msg = """<h1>Overview</h1>
 | 
	
		
			
				|  |  | -This app allows you to add comments to files. The comments are stored in 
 | 
	
		
			
				|  |  | -a database, and where possible, saved in the xattr (hidden attributes) 
 | 
	
		
			
				|  |  | -field of the file system.
 | 
	
		
			
				|  |  | -<p>
 | 
	
		
			
				|  |  | -You can sort the directory listing by clicking on the column heading.
 | 
	
		
			
				|  |  | -<p>
 | 
	
		
			
				|  |  | -The small box at the top left lets you navigate the directory listings.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -"""
 | 
	
		
			
				|  |  | -		self.tb.setText(msg)
 | 
	
		
			
				|  |  | -		self.tb.setFixedWidth(600)
 | 
	
		
			
				|  |  | +		self.tb.setText(helpMsg)
 | 
	
		
			
				|  |  | +		self.tb.setFixedWidth(500)
 | 
	
		
			
				|  |  |  		self.pb = QPushButton('OK',self)
 | 
	
		
			
				|  |  |  		self.pb.setFixedWidth(200)
 | 
	
		
			
				|  |  |  		self.layout.addWidget(self.tb)
 | 
	
	
		
			
				|  | @@ -243,6 +259,12 @@ class DirNotes(QMainWindow):
 | 
	
		
			
				|  |  |  		self.refill()
 | 
	
		
			
				|  |  |  		lb.resizeColumnsToContents()
 | 
	
		
			
				|  |  |  		
 | 
	
		
			
				|  |  | +		if len(filename)>0:
 | 
	
		
			
				|  |  | +			for i in range(lb.rowCount()):
 | 
	
		
			
				|  |  | +				if filename == lb.item(i,0).data(32).toPyObject().getFileName():
 | 
	
		
			
				|  |  | +					lb.setCurrentCell(i,3)
 | 
	
		
			
				|  |  | +					break
 | 
	
		
			
				|  |  | +		
 | 
	
		
			
				|  |  |  		layout = QVBoxLayout()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		e = QLabel("View and edit file comments stored in extended attributes user.xdg.comment",win)
 | 
	
	
		
			
				|  | @@ -300,7 +322,7 @@ class DirNotes(QMainWindow):
 | 
	
		
			
				|  |  |  		print("change dir to "+self.dirLeft.currentPath())
 | 
	
		
			
				|  |  |  	def double(self,row,col):
 | 
	
		
			
				|  |  |  		print("double click {} {}".format(row, col))
 | 
	
		
			
				|  |  | -		fo = self.lb.item(row,col).data(32).toPyObject()
 | 
	
		
			
				|  |  | +		fo = self.lb.item(row,0).data(32).toPyObject()
 | 
	
		
			
				|  |  |  		if col==0 and fo.getSize() == FileObj.FILE_IS_DIR:
 | 
	
		
			
				|  |  |  			print("double click on {}".format(fo.getName()))
 | 
	
		
			
				|  |  |  			self.curPath = fo.getName()
 | 
	
	
		
			
				|  | @@ -340,6 +362,7 @@ class DirNotes(QMainWindow):
 | 
	
		
			
				|  |  |  				item = SortableTableWidgetItem(d[i],d[i])
 | 
	
		
			
				|  |  |  			item.setFlags(QtCore.Qt.ItemIsEnabled)
 | 
	
		
			
				|  |  |  			item.setData(32,this_file)	# keep a hidden copy of the file object
 | 
	
		
			
				|  |  | +			item.setToolTip(this_file.getName())
 | 
	
		
			
				|  |  |  			self.lb.setItem(i,0,item)
 | 
	
		
			
				|  |  |  			#lb.itemAt(i,0).setFlags(Qt.ItemIsEnabled) #NoItemFlags) 
 | 
	
		
			
				|  |  |  			comment = this_file.getComment()
 | 
	
	
		
			
				|  | @@ -347,6 +370,7 @@ class DirNotes(QMainWindow):
 | 
	
		
			
				|  |  |  			dt = this_file.getDate()
 | 
	
		
			
				|  |  |  			da = SortableTableWidgetItem(DataBase.getShortDate(dt),dt)
 | 
	
		
			
				|  |  |  			#da.setFont(small_font)
 | 
	
		
			
				|  |  | +			da.setToolTip(dt)
 | 
	
		
			
				|  |  |  			da.setFlags(QtCore.Qt.ItemIsEnabled)
 | 
	
		
			
				|  |  |  			self.lb.setItem(i,1,da)
 | 
	
		
			
				|  |  |  			si = this_file.getSize()
 | 
	
	
		
			
				|  | @@ -354,8 +378,10 @@ class DirNotes(QMainWindow):
 | 
	
		
			
				|  |  |  				sa = SortableTableWidgetItem('',0)
 | 
	
		
			
				|  |  |  				item.setIcon(dirIcon)
 | 
	
		
			
				|  |  |  			elif si==FileObj.FILE_IS_LINK:
 | 
	
		
			
				|  |  | -				sa = SortableTableWidgetItem('',0)
 | 
	
		
			
				|  |  | +				sa = SortableTableWidgetItem('symlink',-1)
 | 
	
		
			
				|  |  |  				item.setIcon(linkIcon)
 | 
	
		
			
				|  |  | +				dst = os.path.realpath(this_file.getName())
 | 
	
		
			
				|  |  | +				sa.setToolTip("symlink: " + dst)
 | 
	
		
			
				|  |  |  			else:
 | 
	
		
			
				|  |  |  				sa = SortableTableWidgetItem(str(si),si)
 | 
	
		
			
				|  |  |  				item.setIcon(fileIcon)
 | 
	
	
		
			
				|  | @@ -373,7 +399,7 @@ class DirNotes(QMainWindow):
 | 
	
		
			
				|  |  |  		print("      selected file: "+self.lb.item(x.row(),0).data(32).toPyObject().getName())
 | 
	
		
			
				|  |  |  		the_file = self.lb.item(x.row(),0).data(32).toPyObject()
 | 
	
		
			
				|  |  |  		print("      and the row file is "+the_file.getName())
 | 
	
		
			
				|  |  | -		r = the_file.setComment(str(x.text())) 
 | 
	
		
			
				|  |  | +		r = the_file.setComment(str(x.text())) # TODO: change priority
 | 
	
		
			
				|  |  |  		if r:
 | 
	
		
			
				|  |  |  			self.db.log(the_file.getName(),x.text())
 | 
	
		
			
				|  |  |  	def restore_from_database(self):
 | 
	
	
		
			
				|  | @@ -415,7 +441,6 @@ if __name__=="__main__":
 | 
	
		
			
				|  |  |  	
 | 
	
		
			
				|  |  |  	#xattr.setxattr(filename,COMMENT_KEY,commentText)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  ''' files from directories
 | 
	
		
			
				|  |  |  use os.isfile()
 | 
	
		
			
				|  |  |  os.isdir()
 |