| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 | #!/usr/bin/python""" a simple gui or command line appto view and create/edit file commentscomments are stored in xattr user.xdg.commentdepends on python-pyxattrbecause files are so often over-written, save a copyof the comments in a database ~/.dirnotes.dbthese comments stick to the symlink"""COMMENT_KEY = "user.xdg.comment"DATABASE_NAME = "~/.dirnotes.db"import sys,os,argparsefrom PyQt4.QtGui import *from PyQt4 import QtGui, QtCoreimport xattr, sqlite3, timeDATABASE_NAME = os.path.expanduser(DATABASE_NAME)class DataBase:	''' the database is flat		fileName: fully qualified name		st_mtime: a float		size: a long		comment: a string		comment_time: a float, the time of the comment save		this is effectively a log file, as well as a resource for a restore			(in case a file-move is done without comment)		the database is associated with a user, in the $HOME dir	'''	def __init__(self):		'''try to open the database; if not found, create it'''		try:			self.db = sqlite3.connect(DATABASE_NAME)		except sqlite3.OperationalError:			print("Database %s not found" % DATABASE_NAME)			raise OperationalError		c = self.db.cursor()		try:			c.execute("select * from dirnotes")		except sqlite3.OperationalError:			print("Table %s created" % ("dirnotes"))			c.execute("create table dirnotes (name TEXT, date REAL, size INTEGER, comment TEXT, comment_date REAL)")			def getData(self, fileName):		c = self.db.cursor()		c.execute("select * from dirnotes where name=?",(fileName,))		return c.fetchone()	def setData(self, fileName, _date, _size, comment):		c = self.db.cursor()		c.execute("insert into dirnotes values (?,?,?,?,?)",			(fileName, _date, _size, comment, time.time()))		self.db.commit()		return Truedef parse():	parser = argparse.ArgumentParser(description='dirnotes application')	parser.add_argument('filename',metavar='filename',type=str,		nargs="*",help='filename or directory',default=".")	parser.add_argument('-n','--nogui',action="store_const",const="1",		help='use text base interface')	parser.add_argument('-v','--version',action='version',version='%(prog)s 0.2')	return parser.parse_args()def debug(x):	print("debugging " + x.text() + " r:" + str(x.row()) + " c:" + str(x.column()))	the_file = dn.files[x.row()]	the_file.setComment(str(x.text())) class FileObj():	def __init__(self, fileName):		self.fileName = fileName		# also get the date, directory or not, etc		self.directory = "a"		self.comment = ''		try:			self.comment = xattr.getxattr(fileName,COMMENT_KEY)		except:			pass	def getName(self):		return self.fileName	def getComment(self):		return self.comment	def setComment(self,newComment):		self.comment = newComment		try:			xattr.setxattr(self.fileName,COMMENT_KEY,self.comment)		except:			print("problem setting the comment on file %s" % self.fileName)class DirNotes(QMainWindow):	def __init__(self, filename, parent=None):		super(DirNotes,self).__init__(parent)		win = QWidget()		self.setCentralWidget(win)		lb = QTableWidget()		lb.setColumnCount(2)		lb.horizontalHeader().setResizeMode( 1, QHeaderView.Stretch );		# resize the comments column		# and resize the parent window to match the directory size		# allow multiple entries on the line at this point		#d = os.listdir(p.filename[0])		#d.sort()		current, dirs, files = os.walk(filename,followlinks=True).next()		dirs = map(lambda x:x+'/', dirs)		dirs.sort()		files.sort()				d = dirs + files		lb.setRowCount(len(d))		self.files = []		for i in range(len(d)):			this_file = FileObj(d[i])			self.files = self.files + [this_file]			item = QTableWidgetItem(this_file.getName())			item.setFlags(QtCore.Qt.ItemIsEnabled)			lb.setItem(i,0,item)			#lb.itemAt(i,0).setFlags(Qt.ItemIsEnabled) #NoItemFlags)			comment = this_file.getComment()			lb.setItem(i,1,QTableWidgetItem(comment))		lb.setHorizontalHeaderItem(0,QTableWidgetItem("file"))		lb.setHorizontalHeaderItem(1,QTableWidgetItem("comment"))		lb.resizeColumnsToContents()		lb.verticalHeader().setVisible(False)		e = QLabel("View and edit file comments stored in extended attributes user.xdg.comment")		layout = QVBoxLayout()		layout.addWidget(e)		layout.addWidget(lb)		win.setLayout(layout)				lb.itemChanged.connect(debug)		QShortcut(QKeySequence("Ctrl+Q"), self, self.close)			self.setWindowTitle("test")		self.setMinimumSize(600,400)	def closeEvent(self,e):		print("closing")		if __name__=="__main__":	p = parse()		db = DataBase()	db.setData("a",float(time.time()),1244445,"a comment")	print(db.getData("a"))	(f,d,s,c,cd) = db.getData("a")	print(time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(d)))	a = QApplication([])	dn = DirNotes(p.filename[0])	dn.show()		a.exec_()		#xattr.setxattr(filename,COMMENT_KEY,commentText)''' files from directoriesuse os.isfile()os.isdir()current, dirs, files = os.walk("path").next()possible set folllowLinks=True'''
 |