dirnotes 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. #!/usr/bin/python
  2. """ a simple gui or command line app
  3. to view and create/edit file comments
  4. comments are stored in xattr user.xdg.comment
  5. depends on python-pyxattr
  6. because files are so often over-written, save a copy
  7. of the comments in a database ~/.dirnotes.db
  8. these comments stick to the symlink
  9. """
  10. COMMENT_KEY = "user.xdg.comment"
  11. DATABASE_NAME = "~/.dirnotes.db"
  12. import sys,os,argparse
  13. from PyQt4.QtGui import *
  14. from PyQt4 import QtGui, QtCore
  15. import xattr, sqlite3, time
  16. DATABASE_NAME = os.path.expanduser(DATABASE_NAME)
  17. class DataBase:
  18. ''' the database is flat
  19. fileName: fully qualified name
  20. st_mtime: a float
  21. size: a long
  22. comment: a string
  23. comment_time: a float, the time of the comment save
  24. this is effectively a log file, as well as a resource for a restore
  25. (in case a file-move is done without comment)
  26. the database is associated with a user, in the $HOME dir
  27. '''
  28. def __init__(self):
  29. '''try to open the database; if not found, create it'''
  30. try:
  31. self.db = sqlite3.connect(DATABASE_NAME)
  32. except sqlite3.OperationalError:
  33. print("Database %s not found" % DATABASE_NAME)
  34. raise OperationalError
  35. c = self.db.cursor()
  36. try:
  37. c.execute("select * from dirnotes")
  38. except sqlite3.OperationalError:
  39. print("Table %s created" % ("dirnotes"))
  40. c.execute("create table dirnotes (name TEXT, date REAL, size INTEGER, comment TEXT, comment_date REAL)")
  41. def getData(self, fileName):
  42. c = self.db.cursor()
  43. c.execute("select * from dirnotes where name=?",(fileName,))
  44. return c.fetchone()
  45. def setData(self, fileName, _date, _size, comment):
  46. c = self.db.cursor()
  47. c.execute("insert into dirnotes values (?,?,?,?,?)",
  48. (fileName, _date, _size, comment, time.time()))
  49. self.db.commit()
  50. return True
  51. def parse():
  52. parser = argparse.ArgumentParser(description='dirnotes application')
  53. parser.add_argument('filename',metavar='filename',type=str,
  54. nargs="*",help='filename or directory',default=".")
  55. parser.add_argument('-n','--nogui',action="store_const",const="1",
  56. help='use text base interface')
  57. parser.add_argument('-v','--version',action='version',version='%(prog)s 0.2')
  58. return parser.parse_args()
  59. def debug(x):
  60. print("debugging " + x.text() + " r:" + str(x.row()) + " c:" + str(x.column()))
  61. the_file = dn.files[x.row()]
  62. the_file.setComment(str(x.text()))
  63. class FileObj():
  64. def __init__(self, fileName):
  65. self.fileName = fileName
  66. # also get the date, directory or not, etc
  67. self.directory = "a"
  68. self.comment = ''
  69. try:
  70. self.comment = xattr.getxattr(fileName,COMMENT_KEY)
  71. except:
  72. pass
  73. def getName(self):
  74. return self.fileName
  75. def getComment(self):
  76. return self.comment
  77. def setComment(self,newComment):
  78. self.comment = newComment
  79. try:
  80. xattr.setxattr(self.fileName,COMMENT_KEY,self.comment)
  81. except:
  82. print("problem setting the comment on file %s" % self.fileName)
  83. class DirNotes(QMainWindow):
  84. def __init__(self, filename, parent=None):
  85. super(DirNotes,self).__init__(parent)
  86. win = QWidget()
  87. self.setCentralWidget(win)
  88. lb = QTableWidget()
  89. lb.setColumnCount(2)
  90. lb.horizontalHeader().setResizeMode( 1, QHeaderView.Stretch );
  91. # resize the comments column
  92. # and resize the parent window to match the directory size
  93. # allow multiple entries on the line at this point
  94. #d = os.listdir(p.filename[0])
  95. #d.sort()
  96. current, dirs, files = os.walk(filename,followlinks=True).next()
  97. dirs = map(lambda x:x+'/', dirs)
  98. dirs.sort()
  99. files.sort()
  100. d = dirs + files
  101. lb.setRowCount(len(d))
  102. self.files = []
  103. for i in range(len(d)):
  104. this_file = FileObj(d[i])
  105. self.files = self.files + [this_file]
  106. item = QTableWidgetItem(this_file.getName())
  107. item.setFlags(QtCore.Qt.ItemIsEnabled)
  108. lb.setItem(i,0,item)
  109. #lb.itemAt(i,0).setFlags(Qt.ItemIsEnabled) #NoItemFlags)
  110. comment = this_file.getComment()
  111. lb.setItem(i,1,QTableWidgetItem(comment))
  112. lb.setHorizontalHeaderItem(0,QTableWidgetItem("file"))
  113. lb.setHorizontalHeaderItem(1,QTableWidgetItem("comment"))
  114. lb.resizeColumnsToContents()
  115. lb.verticalHeader().setVisible(False)
  116. e = QLabel("View and edit file comments stored in extended attributes user.xdg.comment")
  117. layout = QVBoxLayout()
  118. layout.addWidget(e)
  119. layout.addWidget(lb)
  120. win.setLayout(layout)
  121. lb.itemChanged.connect(debug)
  122. QShortcut(QKeySequence("Ctrl+Q"), self, self.close)
  123. self.setWindowTitle("test")
  124. self.setMinimumSize(600,400)
  125. def closeEvent(self,e):
  126. print("closing")
  127. if __name__=="__main__":
  128. p = parse()
  129. db = DataBase()
  130. db.setData("a",float(time.time()),1244445,"a comment")
  131. print(db.getData("a"))
  132. (f,d,s,c,cd) = db.getData("a")
  133. print(time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(d)))
  134. a = QApplication([])
  135. dn = DirNotes(p.filename[0])
  136. dn.show()
  137. a.exec_()
  138. #xattr.setxattr(filename,COMMENT_KEY,commentText)
  139. ''' files from directories
  140. use os.isfile()
  141. os.isdir()
  142. current, dirs, files = os.walk("path").next()
  143. possible set folllowLinks=True'''