├── FileAll.py ├── GitNote.py ├── GitNote.ui ├── GitNoteUi.py ├── GitNote_back.ui ├── Init.py ├── LogOn.py ├── LogOn.ui ├── LogOnUi.py ├── README.md ├── __pycache__ ├── FileAll.cpython-36.pyc ├── GitNote.cpython-36.pyc ├── GitNoteUi.cpython-36.pyc ├── Init.cpython-36.pyc ├── LogOn.cpython-36.pyc ├── LogOnUi.cpython-36.pyc └── main.cpython-36.pyc ├── addpicture.png ├── app.ico ├── askpass.py ├── blackdir.ico ├── config.ico ├── convert.ico ├── dir.ico ├── dir_back.ico ├── edit.ico ├── loading.gif ├── loading.png ├── main.py ├── pictures ├── gitnote-1.png ├── gitnote-10.png ├── gitnote-11.png ├── gitnote-12.png ├── gitnote-2.png ├── gitnote-3.png ├── gitnote-4.png ├── gitnote-5.png ├── gitnote-6.png ├── gitnote-7.png ├── gitnote-8.png └── gitnote-9.png └── save.ico /FileAll.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | 4 | import main 5 | import getpass, os 6 | 7 | def storeConfig(): 8 | writeHandle = open(os.path.join(main.gitNoteHome, "config"), 'w') 9 | writeHandle.write(main.userName + '\n') 10 | writeHandle.write(main.password + '\n') 11 | writeHandle.write(main.gitUrl + '\n') 12 | writeHandle.close() 13 | 14 | def readConfig(): 15 | readHandle = open(os.path.join(main.gitNoteHome, "config"), 'r') 16 | main.userName = readHandle.readline().strip() 17 | main.password = readHandle.readline().strip() 18 | main.gitUrl = readHandle.readline().strip() 19 | -------------------------------------------------------------------------------- /GitNote.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | 4 | from PyQt5.QtWidgets import QWidget, QApplication, QMainWindow, QTreeWidgetItem, QListWidgetItem, QMenu, QInputDialog, QMessageBox, QFileDialog, QToolButton, QFontDialog, QColorDialog 5 | from PyQt5.QtGui import QIcon, QColor, QBrush, QPalette, QColor, QFontMetricsF, QPixmap, QMovie, QTextCursor, QFont 6 | from PyQt5.QtCore import Qt, QByteArray, QThread, QTimer, QSize 7 | import GitNoteUi 8 | import main 9 | import git 10 | import os, getpass, threading, time, datetime, operator, shutil 11 | import pathlib 12 | import mistune 13 | import json, pdfkit 14 | 15 | movieStatus = False 16 | 17 | class CloneThread(QThread): 18 | def __init__(self): 19 | super(CloneThread, self).__init__() 20 | 21 | def run(self): 22 | global movieStatus 23 | main.setGitEnv() 24 | git.Repo.clone_from(url=main.gitUrl, to_path=main.gitNoteNoteHome) 25 | movieStatus = True 26 | #main.myGitNote.setUpdateBack() 27 | 28 | class UpdateThread(QThread): 29 | def __init__(self): 30 | super(UpdateThread, self).__init__() 31 | 32 | def run(self): 33 | global movieStatus 34 | main.setGitEnv() 35 | repo = git.Repo(main.gitNoteNoteHome) 36 | remote = repo.remote() 37 | repo.git.add('--all') 38 | repo.index.commit('note') 39 | remote.push() 40 | remote.pull() 41 | movieStatus = True 42 | #main.myGitNote.setUpdateBack() 43 | 44 | class GitNote(QWidget, GitNoteUi.Ui_Form_note): 45 | def __init__(self, parent=None): 46 | super(GitNote, self).__init__(parent) 47 | self.setupUi(self) 48 | self.initUi() 49 | self.show() 50 | self.updateUiAfterShow() 51 | 52 | def initUi(self): 53 | if not main.gitExist: 54 | self.mycloneGit() 55 | # 界面配置 56 | self.configfile = os.path.join(main.gitNoteHome, "config.json") 57 | self.initInterface() 58 | self.pushButton_update.clicked.connect(self.myupdateGit) 59 | self.treeWidget_tree.clicked.connect(self.onTreeClicked) 60 | self.treeWidget_tree.customContextMenuRequested.connect(self.menuTreeContextClicked) 61 | self.listWidget_list.clicked.connect(self.clickedListView) 62 | self.listWidget_list.customContextMenuRequested.connect(self.menuListContextClicked) 63 | #self.treeWidget_tree.addTopLevelItem(root) 64 | # set window background color 65 | self.setAutoFillBackground(True) 66 | self.listfileDir = main.gitNoteNoteHome 67 | self.viewfileName = "" 68 | self.viewTexts = "" 69 | self.plainTextEdit_markdown.hide() 70 | self.plainTextEdit_markdown.setTabStopDistance(QFontMetricsF(self.plainTextEdit_markdown.font()).width(' ')*4) 71 | self.saveStatus = False 72 | self.createStatus = False 73 | self.pushButton_save.clicked.connect(self.clickedButtonSave) 74 | self.plainTextEdit_markdown.textChanged.connect(self.textChangedEdit) 75 | self.pushButton_save.setEnabled(False) 76 | self.updateListView(self.listfileDir) 77 | self.newDirName = "" 78 | self.pushButton_addpicture.setEnabled(False) 79 | self.pushButton_addpicture.clicked.connect(self.choosePictures) 80 | self.insertPictures = [] 81 | # 设置更新图标 82 | icon = QIcon() 83 | icon.addPixmap(QPixmap(os.path.join(os.path.dirname(__file__), "loading.png")), QIcon.Normal, QIcon.Off) 84 | self.pushButton_update.setIcon(icon) 85 | saveicon = QIcon() 86 | saveicon.addPixmap(QPixmap(os.path.join(os.path.dirname(__file__), "edit.ico")), QIcon.Normal, QIcon.Off) 87 | self.pushButton_save.setIcon(saveicon) 88 | addpicturicon = QIcon() 89 | addpicturicon.addPixmap(QPixmap(os.path.join(os.path.dirname(__file__), "addpicture.png")), QIcon.Normal, QIcon.Off) 90 | self.pushButton_addpicture.setIcon(addpicturicon) 91 | # 保存打开时的文本 92 | self.oldTexts = "" 93 | # 更新恢复 94 | self.movietimer = QTimer(self) 95 | self.movietimer.start(500) 96 | self.movietimer.timeout.connect(self.movieTimeout) 97 | # 配置 98 | configicon = QIcon() 99 | configicon.addPixmap(QPixmap(os.path.join(os.path.dirname(__file__), "config.ico")), QIcon.Normal, QIcon.Off) 100 | self.toolButton_config.setIcon(configicon) 101 | toolmenu = QMenu() 102 | toolmenu.addAction("设置字体", self.setFont) 103 | toolmenu.addAction("默认主题", self.whiteTheme) 104 | toolmenu.addAction("暗黑主题", self.blackTheme) 105 | self.toolButton_config.setMenu(toolmenu) 106 | self.toolButton_config.setPopupMode(QToolButton.MenuButtonPopup) 107 | # 转换 108 | convertico = QIcon(os.path.join(os.path.dirname(__file__), "convert.ico")) 109 | self.toolButton_functions.setIcon(convertico) 110 | convertmenu = QMenu() 111 | convertmenu.addAction("另存为pdf文件", self.viewToPdf) 112 | self.toolButton_functions.setMenu(convertmenu) 113 | 114 | def viewToPdf(self): 115 | if not self.pushButton_save.isEnabled() and not self.pushButton_addpicture.isEnabled(): 116 | return 117 | filename, filetype = QFileDialog.getSaveFileName(self, "文件保存", str(pathlib.Path.home()), "PdfFiles (*.pdf)") 118 | if filename != "": 119 | if filename[-4:] != '.pdf': 120 | oldfilename = filename 121 | filename = filename + '.pdf' 122 | if os.path.exists(filename) and not os.path.exists(oldfilename): 123 | replay = QMessageBox.question(self, "文件覆盖警告", "文件"+os.path.basename(filename)+"已存在,确定覆盖?", QMessageBox.Yes, QMessageBox.No) 124 | if replay == QMessageBox.No: 125 | return 126 | markdown = mistune.Markdown() 127 | pdfkit.from_string('
' + markdown(self.showRealPictures(self.viewTexts)), filename) 128 | #print(markdown(self.showRealPictures(self.viewTexts))) 129 | 130 | def initInterface(self): 131 | self.interfacedata = {'theme': 'white'} 132 | if not os.path.exists(self.configfile): 133 | self.whiteTheme() 134 | return 135 | with open(self.configfile, 'r') as f: 136 | self.interfacedata = json.load(f) 137 | if 'theme' in self.interfacedata and self.interfacedata['theme'] == 'black': 138 | self.blackTheme() 139 | else: 140 | self.whiteTheme() 141 | if 'font' in self.interfacedata: 142 | font = QFont() 143 | font.fromString(self.interfacedata['font']) 144 | self.plainTextEdit_markdown.setFont(font) 145 | self.textEdit_show.setFont(font) 146 | 147 | def whiteTheme(self): 148 | self.dirIcon = QIcon(os.path.join(os.path.dirname(__file__),"dir.ico")) 149 | self.addTopDirs() 150 | pBack = self.palette() 151 | pBack.setColor(self.backgroundRole(), QColor(239, 235, 231)) 152 | self.setPalette(pBack) 153 | self.treeWidget_tree.setStyleSheet('background-color: rgb(255, 255, 255);color: rgb(0, 0, 0)') 154 | self.listWidget_list.setStyleSheet("QListWidget{background-color: rgb(255, 255, 255);color: rgb(0, 0, 0);}" 155 | "QListWidget::item { border-bottom: 0.5px dotted black; margin-bottom:10px;}" 156 | "QListWidget::item:!selected{}" 157 | "QListWidget::item:selected:active{background:#FFFFFF;color:#19649F;border-width:-1;}" 158 | "QListWidget::item:selected{background:#FFFFFF;color:#19649F;}") 159 | self.lineEdit_title.setStyleSheet('background-color: rgb(255, 255, 255);color: rgb(0, 0, 0)') 160 | self.plainTextEdit_markdown.setStyleSheet('background-color: rgb(255, 255, 255);color: rgb(0, 0, 0)') 161 | self.textEdit_show.setStyleSheet('background-color: rgb(255, 255, 255);color: rgb(0, 0, 0)') 162 | if self.interfacedata['theme'] != 'white': 163 | self.interfacedata['theme'] = 'white' 164 | with open(self.configfile, 'w') as f: 165 | json.dump(self.interfacedata, f) 166 | 167 | def blackTheme(self): 168 | self.dirIcon = QIcon(os.path.join(os.path.dirname(__file__),"blackdir.ico")) 169 | self.addTopDirs() 170 | pBack = self.palette() 171 | pBack.setColor(self.backgroundRole(), QColor(51, 51, 51)) 172 | self.setPalette(pBack) 173 | self.treeWidget_tree.setStyleSheet('background-color: rgb(51, 51, 51);color: rgb(200, 200, 200);') 174 | self.listWidget_list.setStyleSheet("QListWidget{background-color: rgb(37, 37, 38);color: rgb(200, 200, 200);}" 175 | "QListWidget::item { border-bottom: 0.5px dotted white; margin-bottom:10px;}") 176 | self.lineEdit_title.setStyleSheet('background-color: rgb(30, 30, 30);color: rgb(200, 200, 200)') 177 | self.plainTextEdit_markdown.setStyleSheet('background-color: rgb(30, 30, 30);color: rgb(200, 200, 200)') 178 | self.textEdit_show.setStyleSheet('background-color: rgb(30, 30, 30);color: rgb(200, 200, 200)') 179 | if self.interfacedata['theme'] != 'black': 180 | self.interfacedata['theme'] = 'black' 181 | with open(self.configfile, 'w') as f: 182 | json.dump(self.interfacedata, f) 183 | 184 | def setFont(self): 185 | font, ok = QFontDialog.getFont() 186 | if ok: 187 | self.plainTextEdit_markdown.setFont(font) 188 | self.textEdit_show.setFont(font) 189 | self.interfacedata['font'] = font.toString() 190 | with open(self.configfile, 'w') as f: 191 | json.dump(self.interfacedata, f) 192 | 193 | def movieTimeout(self): 194 | global movieStatus 195 | if movieStatus: 196 | movieStatus = False 197 | self.setUpdateBack() 198 | 199 | def closeEvent(self, event): 200 | if self.saveStatus: 201 | unsavereturn = self.saveNote(False) 202 | if not unsavereturn: 203 | replay = QMessageBox.question(self, "未保存警告", "有未保存的未命名笔记,确定退出?", QMessageBox.Yes, QMessageBox.No) 204 | if replay == QMessageBox.Yes: 205 | event.accept() 206 | return 207 | elif replay == QMessageBox.No: 208 | event.ignore() 209 | return 210 | #self.saveNote(True) 211 | event.accept() 212 | 213 | def keyPressEvent(self, event): 214 | if (event.key() == Qt.Key_O): 215 | if QApplication.keyboardModifiers() == Qt.ControlModifier: 216 | self.pushButton_save.clicked.emit() 217 | 218 | def choosePictures(self): 219 | pictures, ok = QFileDialog.getOpenFileNames(self, "选取图片", str(pathlib.Path.home()), "Picture Files (*.png | *.jpg | *.jpeg | *.gif | *.ico | *.svg)") 220 | for eachfile in pictures: 221 | basenamewith = os.path.basename(eachfile) 222 | basename, suffix = os.path.splitext(basenamewith) 223 | i = 0 224 | while os.path.exists(os.path.join(self.showTextDir, basename+"-"+str(i)+suffix)): 225 | i = i + 1 226 | lastbasename =basename + "-" + str(i) + suffix 227 | self.insertPictures.append(lastbasename) 228 | self.plainTextEdit_markdown.insertPlainText("\n\n") 229 | lastname = os.path.join(self.showTextDir, lastbasename) 230 | shutil.copyfile(eachfile, lastname) 231 | time.sleep(0.01) 232 | 233 | def moveDirToDir(self): 234 | dir_choose = QFileDialog.getExistingDirectory(self, "选择目标文件夹", main.gitNoteNoteHome) 235 | if self.listfileDir in dir_choose: 236 | QMessageBox.information(self, "警告", "文件夹不能移动到当前目录和子目录!", QMessageBox.Yes) 237 | return 238 | targetDir = self.getTargetName(dir_choose, os.path.basename(self.listfileDir)) 239 | if os.path.exists(self.listfileDir): 240 | shutil.move(self.listfileDir, targetDir) 241 | if self.listfileDir in self.viewfileName: 242 | self.lineEdit_title.clear() 243 | self.plainTextEdit_markdown.clear() 244 | self.textEdit_show.clear() 245 | self.listfileDir = main.gitNoteNoteHome 246 | self.addTopDirs() 247 | self.listWidget_list.clear() 248 | self.pushButton_save.setEnabled(False) 249 | 250 | def deleteDir(self): 251 | countNotes = 0 252 | for dirpath, dirnames, filenames in os.walk(self.listfileDir): 253 | for eachone in filenames: 254 | if os.path.splitext(eachone)[1] == ".md": 255 | countNotes = countNotes + 1 256 | replay = QMessageBox.warning(self, "警告", "文件夹 " + os.path.basename(os.path.normpath(self.listfileDir)) + "下有" + str(countNotes) + "篇笔记,您确定要删除吗?", QMessageBox.Yes|QMessageBox.No, QMessageBox.No) 257 | if replay == QMessageBox.Yes and os.path.exists(self.listfileDir): 258 | shutil.rmtree(self.listfileDir) 259 | if self.listfileDir in self.viewfileName: 260 | self.lineEdit_title.clear() 261 | self.plainTextEdit_markdown.clear() 262 | self.textEdit_show.clear() 263 | self.listfileDir = main.gitNoteNoteHome 264 | self.addTopDirs() 265 | self.listWidget_list.clear() 266 | self.pushButton_save.setEnabled(False) 267 | 268 | def getPicturesInOneNote(self, filename): 269 | pictures = [] 270 | tmpf = open(filename, "r", encoding='UTF-8') 271 | tmpviewTexts = tmpf.read() 272 | tmpf.close() 273 | multilines = tmpviewTexts.split("\n") 274 | for eachline in multilines: 275 | if "" in eachline.split("[1]: 276 | shotfile = (eachline.split("[1]).split(")")[0] 277 | realfile = os.path.join(self.listfileDir, shotfile) 278 | if os.path.exists(realfile): 279 | pictures.append(realfile) 280 | return pictures 281 | 282 | def deleteNote(self): 283 | if not os.path.exists(self.listmenufilename): 284 | return 285 | basename = os.path.basename(self.listmenufilename) 286 | realname = os.path.splitext(basename)[0] 287 | replay = QMessageBox.warning(self, "警告", "您确定要删除笔记 "+realname+" 吗?", QMessageBox.Yes|QMessageBox.No, QMessageBox.No) 288 | if replay == QMessageBox.Yes: 289 | # 先删除里面的图片 290 | pictures = self.getPicturesInOneNote(self.listmenufilename) 291 | for eachpicture in pictures: 292 | os.remove(eachpicture) 293 | # 然后删除markdown文件和更新控件显示 294 | os.remove(self.listmenufilename) 295 | self.addTopDirs() 296 | if os.path.exists(self.listfileDir): 297 | self.updateListView(self.listfileDir) 298 | if self.listmenufilename.strip() == self.viewfileName.strip(): 299 | self.clearNoteShow() 300 | self.listmenufilename = "" 301 | 302 | def createRootDir(self): 303 | newDirName, ok = QInputDialog.getText(self, "创建新文件夹", "文件夹名") 304 | if len(newDirName) > 0: 305 | newWholeDirName = os.path.join(main.gitNoteNoteHome, newDirName) 306 | if not os.path.exists(newWholeDirName): 307 | os.mkdir(newWholeDirName) 308 | self.addTopDirs() 309 | 310 | def createDir(self): 311 | newDirName, ok = QInputDialog.getText(self, "创建新文件夹", "文件夹名") 312 | if len(newDirName) > 0: 313 | newWholeDirName = os.path.join(self.listfileDir, newDirName) 314 | if not os.path.exists(newWholeDirName): 315 | os.mkdir(newWholeDirName) 316 | self.addTopDirs() 317 | 318 | def menuListContextClicked(self, pos): 319 | item = self.listWidget_list.itemAt(pos) 320 | if item: 321 | itemCount = item.text() 322 | filename = (itemCount.split("\n"))[0] 323 | #self.viewfileName = os.path.join(self.listfileDir, filename) 324 | #if self.viewfileName[-3:] != ".md": 325 | # self.viewfileName = self.viewfileName + ".md" 326 | self.listmenufilename = os.path.join(self.listfileDir, filename) 327 | if self.listmenufilename[-3:] != ".md": 328 | self.listmenufilename = self.listmenufilename + ".md" 329 | self.listmenu = QMenu() 330 | self.listmenu.addAction("删除笔记", self.deleteNote) 331 | self.listmenu.addAction("移动笔记", self.moveNoteToDir) 332 | self.listmenu.addAction("重命名笔记", self.renameNote) 333 | self.listmenu.exec_(self.listWidget_list.mapToGlobal(pos)) 334 | 335 | def clearNoteShow(self): 336 | self.pushButton_save.setEnabled(False) 337 | self.lineEdit_title.clear() 338 | self.lineEdit_title.setReadOnly(True) 339 | self.pushButton_addpicture.setEnabled(False) 340 | self.plainTextEdit_markdown.clear() 341 | self.plainTextEdit_markdown.hide() 342 | self.textEdit_show.clear() 343 | self.viewfileName = "" 344 | 345 | def renameNote(self): 346 | newname, ok = QInputDialog.getText(self, "笔记重命名", "请输入新名:") 347 | newname = newname + ".md" 348 | if ok: 349 | newfilepath = os.path.join(self.listfileDir, newname) 350 | if os.path.exists(newfilepath): 351 | QMessageBox.warning(self, "警告", "笔记已存在,请重新命名", QMessageBox.Yes, QMessageBox.Yes) 352 | return 353 | if os.path.exists(self.listmenufilename): 354 | shutil.move(self.listmenufilename, newfilepath) 355 | if self.viewfileName.strip() == self.listmenufilename.strip(): 356 | realname = os.path.splitext(newname)[0] 357 | self.lineEdit_title.setText(realname) 358 | self.viewfileName = newfilepath 359 | if os.path.exists(self.listfileDir): 360 | self.updateListView(self.listfileDir) 361 | 362 | def getTargetName(self, targetDir, basenamewith): 363 | if os.path.exists(os.path.join(targetDir, basenamewith)): 364 | basename, suffix = os.path.splitext(basenamewith) 365 | i = 0 366 | while os.path.exists(os.path.join(targetDir, basename+"-"+str(i)+suffix)): 367 | i = i + 1 368 | basenamewith = basename + "-" + str(i) + suffix 369 | return os.path.join(targetDir, basenamewith) 370 | 371 | def replacePictureName(self, viewTexts, basename, newbasename): 372 | multilines = viewTexts.split("\n") 373 | newViewTexts = "" 374 | for eachline in multilines: 375 | if "" in eachline.split("[1] and (eachline.split("[1]).split(")")[0] == basename: 376 | newViewTexts = newViewTexts + "\n" 377 | else: 378 | newViewTexts = newViewTexts + eachline+"\n" 379 | return newViewTexts 380 | 381 | def moveNoteToDir(self): 382 | dir_choose = QFileDialog.getExistingDirectory(self, "选择目标文件夹", main.gitNoteNoteHome) 383 | if main.gitNoteNoteHome in dir_choose and os.path.dirname(self.listmenufilename) != dir_choose: 384 | # 移动图片 385 | tmpf = open(self.listmenufilename, "r", encoding='UTF-8') 386 | tmpviewTexts = tmpf.read() 387 | tmpf.close() 388 | pictures = self.getPicturesInOneNote(self.listmenufilename) 389 | for eachpicture in pictures: 390 | basename = os.path.basename(eachpicture) 391 | targetfilename = self.getTargetName(dir_choose, basename) 392 | if os.path.exists(eachpicture): 393 | shutil.move(eachpicture, targetfilename) 394 | newbasename = os.path.basename(targetfilename) 395 | tmpviewTexts= self.replacePictureName(tmpviewTexts, basename, newbasename) 396 | tmpf = open(self.listmenufilename, "w", encoding='UTF-8') 397 | tmpf.write(tmpviewTexts) 398 | tmpf.close() 399 | # 移动日记文件 400 | basename = os.path.basename(self.listmenufilename) 401 | targetfilename = self.getTargetName(dir_choose, basename) 402 | if os.path.exists(self.listmenufilename): 403 | shutil.move(self.listmenufilename, targetfilename) 404 | if self.viewfileName.strip() == self.listmenufilename.strip(): 405 | self.viewfileName = "" 406 | self.clearNoteShow() 407 | self.addTopDirs() 408 | if os.path.exists(self.listfileDir): 409 | self.updateListView(self.listfileDir) 410 | 411 | def renameDir(self): 412 | newname, ok = QInputDialog.getText(self, "笔记重命名", "请输入新名:") 413 | if ok: 414 | if self.listfileDir[-1] == '/' or self.listfileDir[-1] == '\\': 415 | self.listfileDir = self.listfileDir[:-1] 416 | newDir = os.path.join(os.path.dirname(self.listfileDir), newname) 417 | if os.path.exists(newDir): 418 | QMessageBox.warning(self, "警告", "文件夹已存在,请重新命名", QMessageBox.Yes, QMessageBox.Yes) 419 | return 420 | else: 421 | shutil.move(self.listfileDir, newDir) 422 | self.listfileDir = newDir 423 | self.addTopDirs() 424 | self.updateListView(self.listfileDir) 425 | self.clearNoteShow() 426 | 427 | def menuTreeContextClicked(self, pos): 428 | item = self.treeWidget_tree.itemAt(pos) 429 | if item: 430 | self.listfileDir = item.text(1) 431 | self.updateListView(self.listfileDir) 432 | self.treemenu = QMenu() 433 | self.treemenu.addAction("新建笔记", self.createNote) 434 | self.treemenu.addAction("新建日记", self.createDiaryNote) 435 | self.treemenu.addAction("新建文件夹", self.createDir) 436 | self.treemenu.addAction("删除文件夹", self.deleteDir) 437 | self.treemenu.addAction("移动文件夹", self.moveDirToDir) 438 | self.treemenu.addAction("重命名文件夹", self.renameDir) 439 | self.treemenu.exec_(self.treeWidget_tree.mapToGlobal(pos)) 440 | else: 441 | self.listfileDir = main.gitNoteNoteHome 442 | self.treerootmenu = QMenu() 443 | self.treerootmenu.addAction("新建Root文件夹", self.createRootDir) 444 | self.treerootmenu.exec_(self.treeWidget_tree.mapToGlobal(pos)) 445 | 446 | def createNote(self): 447 | self.insertPictures = [] 448 | if self.saveStatus: 449 | self.saveNote(True) 450 | self.saveStatus = True 451 | saveicon = QIcon() 452 | saveicon.addPixmap(QPixmap(os.path.join(os.path.dirname(__file__), "save.ico")), QIcon.Normal, QIcon.Off) 453 | self.pushButton_save.setIcon(saveicon) 454 | self.pushButton_save.setEnabled(True) 455 | self.pushButton_addpicture.setEnabled(True) 456 | self.createStatus = True 457 | self.lineEdit_title.setReadOnly(False) 458 | self.lineEdit_title.clear() 459 | self.plainTextEdit_markdown.clear() 460 | self.plainTextEdit_markdown.show() 461 | self.textEdit_show.clear() 462 | self.lineEdit_title.setFocus() 463 | self.oldTexts = "" 464 | self.showTextDir = self.listfileDir 465 | 466 | def createDiaryNote(self): 467 | today = str(time.strftime("%Y-%m-%d", time.localtime())) 468 | self.createNote() 469 | self.lineEdit_title.setText(today) 470 | self.plainTextEdit_markdown.setFocus() 471 | 472 | def clickedListView(self, qmodelindex): 473 | item = self.listWidget_list.currentItem() 474 | if not item: 475 | return 476 | if self.saveStatus or self.createStatus: 477 | self.saveNote(True) 478 | itemCount = item.text() 479 | filename = (itemCount.split("\n"))[0] 480 | self.pushButton_save.setEnabled(True) 481 | self.viewfileName = os.path.join(self.listfileDir, filename) 482 | if self.viewfileName[-3:] != ".md": 483 | self.viewfileName = self.viewfileName + ".md" 484 | self.lineEdit_title.setText(filename) 485 | tmpf = open(self.viewfileName, "r", encoding='UTF-8') 486 | self.viewTexts = tmpf.read() 487 | tmpf.close() 488 | self.showTextDir = self.listfileDir 489 | #self.textEdit_show.setText(markdown2.markdown(self.showRealPictures(self.viewTexts))) 490 | #self.textEdit_show.setHtml(markdown2.markdown(self.showRealPictures(self.viewTexts))) 491 | markdown = mistune.Markdown() 492 | markdownTxt = markdown(self.showRealPictures(self.viewTexts)) 493 | markdownTxt = markdownTxt.replace("\n<", "$&$&$&").strip() 494 | markdownTxt = markdownTxt.replace("\n", r"", r'')
498 | else:
499 | markdownTxt = markdownTxt.replace("", r'')
500 | self.textEdit_show.setHtml(markdownTxt)
501 | self.textEdit_show.moveCursor(QTextCursor.Start)
502 |
503 | def showRealPictures(self, inputtext):
504 | multilines = inputtext.split("\n")
505 | realtext = ""
506 | for eachline in multilines:
507 | if "" in eachline.split("[1]:
508 | shotfile = (eachline.split("[1]).split(")")[0]
509 | realfile = os.path.join(self.showTextDir, shotfile)
510 | #realtext = realtext + "\n"
511 | realtext = realtext + '
\n'
512 | else:
513 | realtext = realtext + eachline + "\n"
514 | return realtext
515 |
516 | def textChangedEdit(self):
517 | self.viewTexts = self.plainTextEdit_markdown.toPlainText()
518 | #therealmd = self.showRealPictures(self.viewTexts)
519 | #self.textEdit_show.clear()
520 | #self.textEdit_show.setText(markdown2.markdown(therealmd))
521 | #self.textEdit_show.setHtml(markdown2.markdown(therealmd))
522 | #renderer = HighlightRenderer()
523 | #markdown = mistune.Markdown(renderer=renderer)
524 | markdown = mistune.Markdown()
525 | markdownTxt = markdown(self.showRealPictures(self.viewTexts))
526 | markdownTxt = markdownTxt.replace("\n<", "$&$&$&").strip()
527 | markdownTxt = markdownTxt.replace("\n", r"
")
528 | markdownTxt = markdownTxt.replace("$&$&$&", "\n<")
529 | if self.interfacedata['theme'] == 'black':
530 | markdownTxt = markdownTxt.replace("", r'')
531 | else:
532 | markdownTxt = markdownTxt.replace("", r'')
533 | self.textEdit_show.setHtml(markdownTxt)
534 | #markdown = mistune.Markdown()
535 | #self.textEdit_show.setHtml(markdown(self.showRealPictures(self.viewTexts)))
536 | self.textEdit_show.moveCursor(QTextCursor.End)
537 |
538 |
539 | def clickedButtonSave(self):
540 | if not self.saveStatus: # 编辑
541 | if len(self.viewfileName) > 1:
542 | # 更新已有的图片
543 | self.insertPictures = []
544 | multilines = self.viewTexts.split("\n")
545 | for eachline in multilines:
546 | if "" in eachline.split("[1]:
547 | shotfile = (eachline.split("[1]).split(")")[0]
548 | self.insertPictures.append(shotfile)
549 |
550 | self.saveStatus = True
551 | self.plainTextEdit_markdown.setPlainText(self.viewTexts)
552 | self.plainTextEdit_markdown.show()
553 | saveicon = QIcon()
554 | saveicon.addPixmap(QPixmap(os.path.join(os.path.dirname(__file__), "save.ico")), QIcon.Normal, QIcon.Off)
555 | self.pushButton_save.setIcon(saveicon)
556 | self.pushButton_addpicture.setEnabled(True)
557 | self.oldTexts = self.viewTexts
558 | else: #保存
559 | self.pushButton_addpicture.setEnabled(False)
560 | self.saveNote(True)
561 | self.textEdit_show.moveCursor(QTextCursor.Start)
562 |
563 | def saveNote(self, checkwarning):
564 | if len(self.lineEdit_title.text()) < 1:
565 | if checkwarning:
566 | QMessageBox.information(self, "警告", "请输入记录名!", QMessageBox.Yes)
567 | return False
568 | if self.createStatus:
569 | self.viewfileName = os.path.join(self.showTextDir, self.lineEdit_title.text().strip())
570 | self.lineEdit_title.setReadOnly(True)
571 | if self.viewfileName[-3:] != ".md":
572 | self.viewfileName = self.viewfileName + ".md"
573 | self.saveStatus = False
574 | self.plainTextEdit_markdown.hide()
575 | saveicon = QIcon()
576 | saveicon.addPixmap(QPixmap(os.path.join(os.path.dirname(__file__), "edit.ico")), QIcon.Normal, QIcon.Off)
577 | self.pushButton_save.setIcon(saveicon)
578 | self.lineEdit_title.setReadOnly(True)
579 | if len(self.viewfileName) > 1:
580 | if not self.createStatus and self.oldTexts == self.viewTexts:
581 | return True
582 | tmpf = open(self.viewfileName, "w", encoding='UTF-8')
583 | tmpf.write(self.viewTexts)
584 | tmpf.close()
585 | self.updateListView(self.listfileDir)
586 | #pictures
587 | for eachpicture in self.insertPictures:
588 | if eachpicture not in self.viewTexts and os.path.exists(os.path.join(self.listfileDir, eachpicture)):
589 | os.remove(os.path.join(self.listfileDir, eachpicture))
590 | #self.treeWidget_tree.clear()
591 | #self.updateTreeItemName()
592 | if self.createStatus:
593 | self.createStatus = False
594 | self.addTopDirs()
595 | return True
596 |
597 | def updateUiAfterShow(self):
598 | self.treeWidget_tree.setColumnWidth(0,100)
599 |
600 | def mycloneGit(self):
601 | if not main.gitExist:
602 | self.movie = QMovie(os.path.join(os.path.dirname(__file__), "loading.gif"), QByteArray(), self)
603 | self.movie.frameChanged.connect(self.setButtonIcon)
604 | self.movie.start()
605 | main.updateStatus = True
606 | self.cloneThread = CloneThread()
607 | self.cloneThread.start()
608 |
609 | def myupdateGit(self):
610 | if main.updateStatus:
611 | return
612 | else:
613 | main.updateStatus = True
614 | self.setUpdateStatus()
615 | self.updateThread = UpdateThread()
616 | self.updateThread.start()
617 |
618 | def setUpdateBack(self):
619 | self.movie = None
620 | icon = QIcon()
621 | icon.addPixmap(QPixmap(os.path.join(os.path.dirname(__file__), "loading.png")), QIcon.Normal, QIcon.Off)
622 | self.pushButton_update.setIcon(icon)
623 | self.addTopDirs()
624 | self.treeWidget_tree.expandAll()
625 | main.updateStatus = False
626 | #self.pushButton_update.setText("更新")
627 |
628 | def setButtonIcon(self):
629 | if self.movie:
630 | self.pushButton_update.setIcon(QIcon(self.movie.currentPixmap()))
631 |
632 | def setUpdateStatus(self):
633 | self.movie = QMovie(os.path.join(os.path.dirname(__file__), "loading.gif"), QByteArray(), self)
634 | self.movie.frameChanged.connect(self.setButtonIcon)
635 | self.movie.start()
636 | #self.pushButton_update.setText("更新中")
637 |
638 | def addTopDirs(self):
639 | self.treeWidget_tree.clear()
640 | files = os.listdir(main.gitNoteNoteHome)
641 | for eachone in files:
642 | eachone_d = os.path.join(main.gitNoteNoteHome, eachone)
643 | if os.path.isdir(eachone_d) and eachone[0] != '.':
644 | item = QTreeWidgetItem(self.treeWidget_tree)
645 | countMd = self.countMdFiles(eachone_d)
646 | dirName = eachone
647 | if countMd > 0:
648 | dirName = eachone + " (" + str(countMd) + ")"
649 | item.setText(0, dirName)
650 | item.setText(1, eachone_d)
651 | item.setIcon(0, self.dirIcon)
652 | self.showDirs(eachone_d, item)
653 | self.treeWidget_tree.expandAll()
654 |
655 | def showDirs(self, filepath, item):
656 | files = os.listdir(filepath)
657 | for eachone in files:
658 | eachone_d = os.path.join(filepath, eachone)
659 | if os.path.isdir(eachone_d) and eachone[0] != '.':
660 | childitem = QTreeWidgetItem(item)
661 | countMd = self.countMdFiles(eachone_d)
662 | dirName = eachone
663 | if countMd > 0:
664 | dirName = eachone + " (" + str(countMd) + ")"
665 | childitem.setText(0, dirName)
666 | childitem.setText(1, eachone_d)
667 | childitem.setIcon(0, self.dirIcon)
668 | self.showDirs(eachone_d, childitem)
669 |
670 | def updateTreeItemName(self):
671 | baseName = self.treeItem.text(0).split('(')[0]
672 | countMd = self.countMdFiles(self.treeItem.text(1))
673 | dirName = baseName
674 | if countMd > 0:
675 | dirName = dirName + " (" + str(countMd) + ")"
676 | self.treeItem.setText(0, dirName)
677 |
678 | def countMdFiles(self, filepath):
679 | files = os.listdir(filepath)
680 | number = 0
681 | for eachone in files:
682 | eachone_d = os.path.join(filepath, eachone)
683 | if not os.path.isdir(eachone_d) and eachone_d[-3:] == ".md":
684 | number = number + 1
685 | return number
686 |
687 | def onTreeClicked(self, qmodelindex):
688 | self.treeItem = self.treeWidget_tree.currentItem()
689 | if self.treeItem.text(1) != self.listfileDir:
690 | self.listfileDir = self.treeItem.text(1)
691 | self.updateListView(self.listfileDir)
692 |
693 | def updateListView(self, fileDir):
694 | self.listWidget_list.clear()
695 | if fileDir == main.gitNoteNoteHome:
696 | return
697 | self.fileList = self.traverseDir(fileDir)
698 | for eachone in self.fileList:
699 | tmpitem = QListWidgetItem(eachone[0])
700 | #if len(eachone[2]) > 1:
701 | # tmpitem.setIcon(QIcon(eachone[2]))
702 | #tmpitem.setTextAlignment(Qt.AlignLeft)
703 | #tmpitem.setSizeHint(QSize(150, 100))
704 | self.listWidget_list.addItem(tmpitem)
705 |
706 | def traverseDir(self, filepath):
707 | files = os.listdir(filepath)
708 | fileList = []
709 | for eachone in files:
710 | eachone_d = os.path.join(filepath, eachone)
711 | if not os.path.isdir(eachone_d) and eachone_d[-3:] == ".md":
712 | tmpfileinfo = []
713 | tmpfileinfo.append(eachone[:-3] + "\n" + self.read20words(eachone_d))
714 | tmpfileinfo.append(os.path.getmtime(eachone_d))
715 | #tmpfileinfo.append(self.addPictureToList(eachone_d))
716 | fileList.append(tmpfileinfo)
717 | if len(fileList) > 1:
718 | fileList.sort(key=operator.itemgetter(1), reverse=True)
719 | return fileList
720 |
721 | def addPictureToList(self, filepath):
722 | returnStr = " "
723 | readHandle = open(filepath, "r", encoding='UTF-8')
724 | while True:
725 | oneline = readHandle.readline()
726 | if oneline:
727 | if "" in oneline.split("[1]:
728 | shotfile = (oneline.split("[1]).split(")")[0]
729 | realfile = os.path.join(self.listfileDir, shotfile)
730 | if os.path.exists(realfile):
731 | returnStr = realfile
732 | else:
733 | break
734 | readHandle.close()
735 | return returnStr
736 |
737 | def read20words(self, filepath):
738 | returnStr = ""
739 | readHandle = open(filepath, "r", encoding='UTF-8')
740 | while True:
741 | oneline = readHandle.readline()
742 | returnStr = returnStr + oneline.strip()
743 | if oneline and len(returnStr) <20:
744 | oneline = readHandle.readline()
745 | returnStr = returnStr + oneline.strip()
746 | else:
747 | break
748 | readHandle.close()
749 | if len(returnStr) > 10:
750 | returnStr = returnStr[:10] + "\n" + returnStr[10:]
751 | returnStr = returnStr + "\n" + self.timeStampToTime(os.path.getmtime(filepath))
752 | return returnStr
753 |
754 | def timeStampToTime(self, timestamp):
755 | timeStruct = time.localtime(timestamp)
756 | return time.strftime("%Y-%m-%d %H:%M:%S", timeStruct)
757 |
--------------------------------------------------------------------------------
/GitNote.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Form_note
4 |
5 |
6 |
7 | 0
8 | 0
9 | 1105
10 | 789
11 |
12 |
13 |
14 |
15 | 0
16 | 0
17 |
18 |
19 |
20 | 笔记
21 |
22 |
23 | -
24 |
25 | -
26 |
27 |
28 |
29 |
30 |
31 |
32 | 16
33 | 16
34 |
35 |
36 |
37 |
38 | -
39 |
40 |
41 | Qt::Horizontal
42 |
43 |
44 | QSizePolicy::Minimum
45 |
46 |
47 |
48 | 0
49 | 0
50 |
51 |
52 |
53 |
54 | -
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | -
64 |
65 |
66 | Qt::Horizontal
67 |
68 |
69 | false
70 |
71 |
72 |
73 | Qt::Horizontal
74 |
75 |
76 | false
77 |
78 |
79 |
80 |
81 | 10
82 | 0
83 |
84 |
85 |
86 |
87 | 200
88 | 16777215
89 |
90 |
91 |
92 |
93 | 0
94 | 0
95 |
96 |
97 |
98 |
99 | 0
100 | 0
101 |
102 |
103 |
104 | Qt::CustomContextMenu
105 |
106 |
107 | false
108 |
109 |
110 |
111 | 1
112 |
113 |
114 |
115 |
116 |
117 |
118 | 10
119 | 0
120 |
121 |
122 |
123 |
124 | 150
125 | 16777215
126 |
127 |
128 |
129 | Qt::CustomContextMenu
130 |
131 |
132 |
133 | 0
134 | 0
135 |
136 |
137 |
138 | Qt::ElideMiddle
139 |
140 |
141 | QListView::LeftToRight
142 |
143 |
144 | true
145 |
146 |
147 | QListView::Adjust
148 |
149 |
150 | 5
151 |
152 |
153 | QListView::ListMode
154 |
155 |
156 |
157 |
158 |
159 | -
160 |
161 | -
162 |
163 |
164 |
165 |
166 |
167 |
168 | 20
169 | 20
170 |
171 |
172 |
173 |
174 | -
175 |
176 |
177 | true
178 |
179 |
180 |
181 | -
182 |
183 |
184 |
185 |
186 |
187 |
188 | 20
189 | 20
190 |
191 |
192 |
193 |
194 | -
195 |
196 |
197 |
198 |
199 |
200 |
201 | 20
202 | 20
203 |
204 |
205 |
206 | QToolButton::MenuButtonPopup
207 |
208 |
209 |
210 |
211 |
212 | -
213 |
214 | -
215 |
216 |
217 | true
218 |
219 |
220 | QAbstractScrollArea::AdjustToContents
221 |
222 |
223 |
224 | -
225 |
226 |
227 | true
228 |
229 |
230 | true
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 | treeWidget_tree
244 | listWidget_list
245 | lineEdit_title
246 | plainTextEdit_markdown
247 | textEdit_show
248 | pushButton_update
249 | pushButton_save
250 |
251 |
252 |
253 |
254 |
--------------------------------------------------------------------------------
/GitNoteUi.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'GitNote.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.12.1
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 | from PyQt5 import QtCore, QtGui, QtWidgets
10 |
11 |
12 | class Ui_Form_note(object):
13 | def setupUi(self, Form_note):
14 | Form_note.setObjectName("Form_note")
15 | Form_note.resize(1105, 789)
16 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
17 | sizePolicy.setHorizontalStretch(0)
18 | sizePolicy.setVerticalStretch(0)
19 | sizePolicy.setHeightForWidth(Form_note.sizePolicy().hasHeightForWidth())
20 | Form_note.setSizePolicy(sizePolicy)
21 | self.verticalLayout_2 = QtWidgets.QVBoxLayout(Form_note)
22 | self.verticalLayout_2.setObjectName("verticalLayout_2")
23 | self.horizontalLayout = QtWidgets.QHBoxLayout()
24 | self.horizontalLayout.setObjectName("horizontalLayout")
25 | self.pushButton_update = QtWidgets.QPushButton(Form_note)
26 | self.pushButton_update.setText("")
27 | self.pushButton_update.setIconSize(QtCore.QSize(16, 16))
28 | self.pushButton_update.setObjectName("pushButton_update")
29 | self.horizontalLayout.addWidget(self.pushButton_update)
30 | spacerItem = QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
31 | self.horizontalLayout.addItem(spacerItem)
32 | self.toolButton_config = QtWidgets.QToolButton(Form_note)
33 | self.toolButton_config.setText("")
34 | self.toolButton_config.setObjectName("toolButton_config")
35 | self.horizontalLayout.addWidget(self.toolButton_config)
36 | self.horizontalLayout.setStretch(1, 1)
37 | self.verticalLayout_2.addLayout(self.horizontalLayout)
38 | self.splitter_2 = QtWidgets.QSplitter(Form_note)
39 | self.splitter_2.setOrientation(QtCore.Qt.Horizontal)
40 | self.splitter_2.setChildrenCollapsible(False)
41 | self.splitter_2.setObjectName("splitter_2")
42 | self.splitter = QtWidgets.QSplitter(self.splitter_2)
43 | self.splitter.setOrientation(QtCore.Qt.Horizontal)
44 | self.splitter.setChildrenCollapsible(False)
45 | self.splitter.setObjectName("splitter")
46 | self.treeWidget_tree = QtWidgets.QTreeWidget(self.splitter)
47 | self.treeWidget_tree.setMinimumSize(QtCore.QSize(10, 0))
48 | self.treeWidget_tree.setMaximumSize(QtCore.QSize(200, 16777215))
49 | self.treeWidget_tree.setSizeIncrement(QtCore.QSize(0, 0))
50 | self.treeWidget_tree.setBaseSize(QtCore.QSize(0, 0))
51 | self.treeWidget_tree.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
52 | self.treeWidget_tree.setObjectName("treeWidget_tree")
53 | self.treeWidget_tree.headerItem().setText(0, "1")
54 | self.treeWidget_tree.header().setVisible(False)
55 | self.listWidget_list = QtWidgets.QListWidget(self.splitter)
56 | self.listWidget_list.setMinimumSize(QtCore.QSize(10, 0))
57 | self.listWidget_list.setMaximumSize(QtCore.QSize(150, 16777215))
58 | self.listWidget_list.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
59 | self.listWidget_list.setIconSize(QtCore.QSize(0, 0))
60 | self.listWidget_list.setTextElideMode(QtCore.Qt.ElideMiddle)
61 | self.listWidget_list.setFlow(QtWidgets.QListView.LeftToRight)
62 | self.listWidget_list.setProperty("isWrapping", True)
63 | self.listWidget_list.setResizeMode(QtWidgets.QListView.Adjust)
64 | self.listWidget_list.setViewMode(QtWidgets.QListView.ListMode)
65 | self.listWidget_list.setObjectName("listWidget_list")
66 | self.layoutWidget = QtWidgets.QWidget(self.splitter_2)
67 | self.layoutWidget.setObjectName("layoutWidget")
68 | self.verticalLayout = QtWidgets.QVBoxLayout(self.layoutWidget)
69 | self.verticalLayout.setContentsMargins(0, 0, 0, 0)
70 | self.verticalLayout.setObjectName("verticalLayout")
71 | self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
72 | self.horizontalLayout_3.setObjectName("horizontalLayout_3")
73 | self.pushButton_save = QtWidgets.QPushButton(self.layoutWidget)
74 | self.pushButton_save.setText("")
75 | self.pushButton_save.setIconSize(QtCore.QSize(20, 20))
76 | self.pushButton_save.setObjectName("pushButton_save")
77 | self.horizontalLayout_3.addWidget(self.pushButton_save)
78 | self.lineEdit_title = QtWidgets.QLineEdit(self.layoutWidget)
79 | self.lineEdit_title.setReadOnly(True)
80 | self.lineEdit_title.setObjectName("lineEdit_title")
81 | self.horizontalLayout_3.addWidget(self.lineEdit_title)
82 | self.pushButton_addpicture = QtWidgets.QPushButton(self.layoutWidget)
83 | self.pushButton_addpicture.setText("")
84 | self.pushButton_addpicture.setIconSize(QtCore.QSize(20, 20))
85 | self.pushButton_addpicture.setObjectName("pushButton_addpicture")
86 | self.horizontalLayout_3.addWidget(self.pushButton_addpicture)
87 | self.toolButton_functions = QtWidgets.QToolButton(self.layoutWidget)
88 | self.toolButton_functions.setText("")
89 | self.toolButton_functions.setIconSize(QtCore.QSize(20, 20))
90 | self.toolButton_functions.setPopupMode(QtWidgets.QToolButton.MenuButtonPopup)
91 | self.toolButton_functions.setObjectName("toolButton_functions")
92 | self.horizontalLayout_3.addWidget(self.toolButton_functions)
93 | self.verticalLayout.addLayout(self.horizontalLayout_3)
94 | self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
95 | self.horizontalLayout_2.setObjectName("horizontalLayout_2")
96 | self.plainTextEdit_markdown = QtWidgets.QPlainTextEdit(self.layoutWidget)
97 | self.plainTextEdit_markdown.setEnabled(True)
98 | self.plainTextEdit_markdown.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
99 | self.plainTextEdit_markdown.setObjectName("plainTextEdit_markdown")
100 | self.horizontalLayout_2.addWidget(self.plainTextEdit_markdown)
101 | self.textEdit_show = QtWidgets.QTextEdit(self.layoutWidget)
102 | self.textEdit_show.setReadOnly(True)
103 | self.textEdit_show.setOverwriteMode(True)
104 | self.textEdit_show.setObjectName("textEdit_show")
105 | self.horizontalLayout_2.addWidget(self.textEdit_show)
106 | self.verticalLayout.addLayout(self.horizontalLayout_2)
107 | self.verticalLayout_2.addWidget(self.splitter_2)
108 |
109 | self.retranslateUi(Form_note)
110 | QtCore.QMetaObject.connectSlotsByName(Form_note)
111 | Form_note.setTabOrder(self.treeWidget_tree, self.listWidget_list)
112 | Form_note.setTabOrder(self.listWidget_list, self.lineEdit_title)
113 | Form_note.setTabOrder(self.lineEdit_title, self.plainTextEdit_markdown)
114 | Form_note.setTabOrder(self.plainTextEdit_markdown, self.textEdit_show)
115 | Form_note.setTabOrder(self.textEdit_show, self.pushButton_update)
116 | Form_note.setTabOrder(self.pushButton_update, self.pushButton_save)
117 |
118 | def retranslateUi(self, Form_note):
119 | _translate = QtCore.QCoreApplication.translate
120 | Form_note.setWindowTitle(_translate("Form_note", "笔记"))
121 |
122 |
123 |
--------------------------------------------------------------------------------
/GitNote_back.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Form_note
4 |
5 |
6 |
7 | 0
8 | 0
9 | 1105
10 | 779
11 |
12 |
13 |
14 | 笔记
15 |
16 |
17 |
18 | app.ico app.ico
19 |
20 |
21 | -
22 |
23 | -
24 |
25 |
26 | 更新
27 |
28 |
29 |
30 | -
31 |
32 |
33 | 新建
34 |
35 |
36 |
37 | -
38 |
39 |
40 | 编辑
41 |
42 |
43 |
44 | -
45 |
46 |
47 | Qt::Horizontal
48 |
49 |
50 | QSizePolicy::Minimum
51 |
52 |
53 |
54 | 0
55 | 0
56 |
57 |
58 |
59 |
60 |
61 |
62 | -
63 |
64 |
65 | Qt::Horizontal
66 |
67 |
68 | false
69 |
70 |
71 | 1
72 |
73 |
74 | false
75 |
76 |
77 |
78 |
79 | 100
80 | 0
81 |
82 |
83 |
84 |
85 | 200
86 | 16777215
87 |
88 |
89 |
90 |
91 | 250
92 | 0
93 |
94 |
95 |
96 |
97 | 250
98 | 0
99 |
100 |
101 |
102 | false
103 |
104 |
105 |
106 | 1
107 |
108 |
109 |
110 |
111 |
112 |
113 | 100
114 | 0
115 |
116 |
117 |
118 |
119 | 150
120 | 16777215
121 |
122 |
123 |
124 | true
125 |
126 |
127 | QListView::Adjust
128 |
129 |
130 | 10
131 |
132 |
133 |
134 |
135 | true
136 |
137 |
138 |
139 |
140 | true
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
--------------------------------------------------------------------------------
/Init.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | # -*- coding: utf-8 -*-
3 |
4 | import sys, os, getpass
5 | import LogOn
6 | import main, FileAll, GitNote
7 | import pathlib
8 |
9 | class Init:
10 | def __init__(self):
11 | self.exist = True
12 | main.gitNoteHome = os.path.join(str(pathlib.Path.home()), ".GitNote")
13 | main.gitNoteNoteHome = os.path.join(main.gitNoteHome, "Notes")
14 | if not os.path.exists(main.gitNoteHome):
15 | self.exist = False
16 | os.makedirs(main.gitNoteHome)
17 | os.makedirs(main.gitNoteNoteHome)
18 | print("No .GitNOte")
19 | if not os.path.exists(main.gitNoteNoteHome):
20 | main.gitExist = False
21 | os.makedirs(main.gitNoteNoteHome)
22 | print("No Notes")
23 | if not os.path.exists(os.path.join(main.gitNoteHome, "config")):
24 | self.exist = False
25 | print("NO config:" + os.path.join(main.gitNoteHome, "config"))
26 | if not os.path.exists(os.path.join(main.gitNoteNoteHome, ".git")):
27 | main.gitExist = False
28 | if not self.exist:
29 | self.logWin = LogOn.LogOn()
30 | else:
31 | FileAll.readConfig()
32 | main.setGitEnv()
33 | main.myGitNote = GitNote.GitNote()
--------------------------------------------------------------------------------
/LogOn.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | # -*- coding: utf-8 -*-
3 |
4 | from PyQt5.QtWidgets import QWidget, QApplication, QMessageBox, QLineEdit
5 | from LogOnUi import *
6 | import main, FileAll, GitNote
7 | import os, git
8 |
9 | class LogOn(QWidget, Ui_LogOn):
10 | def __init__(self, parent=None):
11 | super(LogOn, self).__init__(parent)
12 | self.setupUi(self)
13 | self.initUi()
14 | self.show()
15 |
16 | def initUi(self):
17 | self.lineEdit_password.setEchoMode(QLineEdit.Password)
18 | self.pushButton_logOn.clicked.connect(self.logOn)
19 |
20 | def logOn(self):
21 | if len(self.lineEdit_userName.text()) < 2:
22 | QMessageBox.information(self, "警告", "请输入有效的用户名", QMessageBox.Ok)
23 | return
24 | if len(self.lineEdit_password.text()) < 2:
25 | QMessageBox.information(self, "警告", "请输入有效的密码", QMessageBox.Ok)
26 | return
27 | if (self.lineEdit_gitUrl.text())[-3:] != "git":
28 | QMessageBox.information(self, "警告", "请输入有效的Git地址", QMessageBox.Ok)
29 | return
30 | main.userName = self.lineEdit_userName.text()
31 | main.password = self.lineEdit_password.text()
32 | main.gitUrl = self.lineEdit_gitUrl.text()
33 | FileAll.storeConfig()
34 | self.close()
35 | main.setGitEnv()
36 | main.myGitNote = GitNote.GitNote()
--------------------------------------------------------------------------------
/LogOn.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | LogOn
4 |
5 |
6 |
7 | 0
8 | 0
9 | 388
10 | 150
11 |
12 |
13 |
14 | 登录
15 |
16 |
17 | -
18 |
19 |
20 | 用户名:
21 |
22 |
23 |
24 | -
25 |
26 |
27 | -
28 |
29 |
30 | 密码:
31 |
32 |
33 |
34 | -
35 |
36 |
37 | -
38 |
39 |
40 | Git地址:
41 |
42 |
43 |
44 | -
45 |
46 |
47 | -
48 |
49 |
50 | 登录
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/LogOnUi.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'LogOn.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.12.1
6 | #
7 | # WARNING! All changes made in this file will be lost!
8 |
9 | from PyQt5 import QtCore, QtGui, QtWidgets
10 |
11 |
12 | class Ui_LogOn(object):
13 | def setupUi(self, LogOn):
14 | LogOn.setObjectName("LogOn")
15 | LogOn.resize(388, 150)
16 | self.formLayout = QtWidgets.QFormLayout(LogOn)
17 | self.formLayout.setObjectName("formLayout")
18 | self.label = QtWidgets.QLabel(LogOn)
19 | self.label.setObjectName("label")
20 | self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label)
21 | self.lineEdit_userName = QtWidgets.QLineEdit(LogOn)
22 | self.lineEdit_userName.setObjectName("lineEdit_userName")
23 | self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.lineEdit_userName)
24 | self.label_2 = QtWidgets.QLabel(LogOn)
25 | self.label_2.setObjectName("label_2")
26 | self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_2)
27 | self.lineEdit_password = QtWidgets.QLineEdit(LogOn)
28 | self.lineEdit_password.setObjectName("lineEdit_password")
29 | self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.lineEdit_password)
30 | self.label_3 = QtWidgets.QLabel(LogOn)
31 | self.label_3.setObjectName("label_3")
32 | self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_3)
33 | self.lineEdit_gitUrl = QtWidgets.QLineEdit(LogOn)
34 | self.lineEdit_gitUrl.setObjectName("lineEdit_gitUrl")
35 | self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.lineEdit_gitUrl)
36 | self.pushButton_logOn = QtWidgets.QPushButton(LogOn)
37 | self.pushButton_logOn.setObjectName("pushButton_logOn")
38 | self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.pushButton_logOn)
39 |
40 | self.retranslateUi(LogOn)
41 | QtCore.QMetaObject.connectSlotsByName(LogOn)
42 |
43 | def retranslateUi(self, LogOn):
44 | _translate = QtCore.QCoreApplication.translate
45 | LogOn.setWindowTitle(_translate("LogOn", "登录"))
46 | self.label.setText(_translate("LogOn", "用户名:"))
47 | self.label_2.setText(_translate("LogOn", "密码:"))
48 | self.label_3.setText(_translate("LogOn", "Git地址:"))
49 | self.pushButton_logOn.setText(_translate("LogOn", "登录"))
50 |
51 |
52 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GitNote
2 | ---------------------------------------
3 | 使用Git作为存储仓库的MarkDown云笔记。
4 |
5 | 安装必要环境,安装并配置Git
6 |
7 | 如果需要生成pdf,需要安装wkhtmltopdf
8 |
9 | ```
10 | sudo apt install wkhtmltopdf
11 | 或者
12 | yum install wkhtmltopdf
13 | Windows下直接下载安装文件安装(https://wkhtmltopdf.org/downloads.html),将可执行文件的路径加入系统环境变量path中
14 | ```
15 |
16 | ```
17 | sudo apt install python3-pip
18 | pip3 install pyqt5 gitpython mistune pdfkit
19 | ```
20 |
21 | ### 现在已完成基本功能,包括
22 | - 克隆
23 | - 更新,包括自动pull和push
24 | - markdown查看和编辑
25 | - 另存为pdf文件
26 |
27 | ### 其他功能开发中...
28 |
29 | 以下是一些现有功能截图
30 | 
31 |
32 | 
33 |
--------------------------------------------------------------------------------
/__pycache__/FileAll.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/__pycache__/FileAll.cpython-36.pyc
--------------------------------------------------------------------------------
/__pycache__/GitNote.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/__pycache__/GitNote.cpython-36.pyc
--------------------------------------------------------------------------------
/__pycache__/GitNoteUi.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/__pycache__/GitNoteUi.cpython-36.pyc
--------------------------------------------------------------------------------
/__pycache__/Init.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/__pycache__/Init.cpython-36.pyc
--------------------------------------------------------------------------------
/__pycache__/LogOn.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/__pycache__/LogOn.cpython-36.pyc
--------------------------------------------------------------------------------
/__pycache__/LogOnUi.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/__pycache__/LogOnUi.cpython-36.pyc
--------------------------------------------------------------------------------
/__pycache__/main.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/__pycache__/main.cpython-36.pyc
--------------------------------------------------------------------------------
/addpicture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/addpicture.png
--------------------------------------------------------------------------------
/app.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/app.ico
--------------------------------------------------------------------------------
/askpass.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | #
3 | # Short & sweet script for use with git clone and fetch credentials.
4 | # Requires GIT_USERNAME and GIT_PASSWORD environment variables,
5 | # intended to be called by Git via GIT_ASKPASS.
6 | #
7 |
8 | from sys import argv
9 | from os import environ
10 |
11 | if 'username' in argv[1].lower():
12 | print(environ['GIT_USERNAME'])
13 | exit()
14 |
15 | if 'password' in argv[1].lower():
16 | print(environ['GIT_PASSWORD'])
17 | exit()
18 |
19 | exit(1)
--------------------------------------------------------------------------------
/blackdir.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/blackdir.ico
--------------------------------------------------------------------------------
/config.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/config.ico
--------------------------------------------------------------------------------
/convert.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/convert.ico
--------------------------------------------------------------------------------
/dir.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/dir.ico
--------------------------------------------------------------------------------
/dir_back.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/dir_back.ico
--------------------------------------------------------------------------------
/edit.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/edit.ico
--------------------------------------------------------------------------------
/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/loading.gif
--------------------------------------------------------------------------------
/loading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/loading.png
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 | # -*- coding: utf-8 -*-
3 |
4 | import sys, os
5 | import git
6 | from PyQt5.QtWidgets import QApplication
7 | import Init, GitNote
8 |
9 | gitNoteHome = ""
10 | gitNoteNoteHome = ""
11 |
12 | userName = ""
13 | password = ""
14 | gitUrl = ""
15 |
16 | gitExist = True
17 |
18 | myGitNote = ""
19 | updateStatus = False
20 |
21 | def setGitEnv():
22 | os.environ['GIT_ASKPASS'] = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'askpass.py')
23 | os.environ['GIT_USERNAME'] = userName
24 | os.environ['GIT_PASSWORD'] = password
25 |
26 | if __name__ == '__main__':
27 | app = QApplication(sys.argv)
28 | myInit = Init.Init()
29 | sys.exit(app.exec_())
--------------------------------------------------------------------------------
/pictures/gitnote-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/pictures/gitnote-1.png
--------------------------------------------------------------------------------
/pictures/gitnote-10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/pictures/gitnote-10.png
--------------------------------------------------------------------------------
/pictures/gitnote-11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/pictures/gitnote-11.png
--------------------------------------------------------------------------------
/pictures/gitnote-12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/pictures/gitnote-12.png
--------------------------------------------------------------------------------
/pictures/gitnote-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/pictures/gitnote-2.png
--------------------------------------------------------------------------------
/pictures/gitnote-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/pictures/gitnote-3.png
--------------------------------------------------------------------------------
/pictures/gitnote-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/pictures/gitnote-4.png
--------------------------------------------------------------------------------
/pictures/gitnote-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/pictures/gitnote-5.png
--------------------------------------------------------------------------------
/pictures/gitnote-6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/pictures/gitnote-6.png
--------------------------------------------------------------------------------
/pictures/gitnote-7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/pictures/gitnote-7.png
--------------------------------------------------------------------------------
/pictures/gitnote-8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/pictures/gitnote-8.png
--------------------------------------------------------------------------------
/pictures/gitnote-9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/pictures/gitnote-9.png
--------------------------------------------------------------------------------
/save.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pluohust/GitNote/8a32a5463b2b670130e4d475e035cf1d1809625e/save.ico
--------------------------------------------------------------------------------