search.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. # -*- coding: utf-8 -*-
  2. import ftplib
  3. import inspect
  4. import os
  5. import shutil
  6. from typing import Optional
  7. from PyQt5 import QtCore, QtGui, QtWidgets
  8. from PyQt5.QtCore import QSize, QUrl
  9. from PyQt5.QtGui import QIcon
  10. from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QPushButton, QTreeWidget, QTreeWidgetItem, QMessageBox, \
  11. QInputDialog, QLineEdit, QWidget, QFileDialog
  12. from .FtpUitl import FtpOper
  13. from .FtpConfig import *
  14. from qgis.utils import iface
  15. current_directory = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) # 获取当前路径
  16. class Ui_SearchDockWidget(object):
  17. def setupUi(self, SearchDockWidget):
  18. # 设置主窗口的标题栏文字
  19. # iface.mainWindow().setWindowTitle("新标题 - QGIS")
  20. iface.mainWindow().setWindowTitle("新标题 - 四维数码")
  21. self.ftpOper = FtpOper()
  22. self.ftpOper.ftp.connect(ftpHost, ftpPort)
  23. self.ftpOper.ftp.login(ftpUsername, ftpPassword)
  24. self.fileItem = None
  25. self.ftpItem = None
  26. SearchDockWidget.setObjectName("SearchDockWidget")
  27. SearchDockWidget.resize(422, 303)
  28. font = QtGui.QFont()
  29. font.setFamily("微软雅黑")
  30. SearchDockWidget.setFont(font)
  31. self.dockWidgetContents = QtWidgets.QWidget()
  32. self.dockWidgetContents.setObjectName("dockWidgetContents")
  33. # 添加FTP管理界面
  34. self.mainLayout = QVBoxLayout(self.dockWidgetContents)
  35. self.layoutH = QHBoxLayout() # 按钮布局
  36. self.layoutV = QVBoxLayout() # 树结构的布局
  37. # 功能按钮区域
  38. self.uploadFileButton = QPushButton(self)
  39. self.uploadFileButton.setIcon(QIcon(os.path.join(current_directory + "\\icon", "文件上传.png")))
  40. self.uploadFileButton.setIconSize(QSize(32, 32))
  41. self.uploadFileButton.setFixedSize(36, 36)
  42. self.uploadFileButton.setToolTip("上传文件")
  43. self.uploadFileButton.clicked.connect(self.actionUploadHandler)
  44. self.layoutH.addWidget(self.uploadFileButton)
  45. self.uploadFolderButton = QPushButton(self)
  46. self.uploadFolderButton.setIcon(QIcon(os.path.join(current_directory + "\\icon", "文件夹上传.png")))
  47. self.uploadFolderButton.setIconSize(QSize(32, 32))
  48. self.uploadFolderButton.setFixedSize(36, 36)
  49. self.uploadFolderButton.setToolTip("上传文件夹")
  50. self.uploadFolderButton.clicked.connect(self.actionUploadDirHandler)
  51. self.layoutH.addWidget(self.uploadFolderButton)
  52. self.downloadButton = QPushButton(self)
  53. self.downloadButton.setIcon(QIcon(os.path.join(current_directory + "\\icon", "文件下载.png")))
  54. self.downloadButton.setIconSize(QSize(32, 32))
  55. self.downloadButton.setFixedSize(36, 36)
  56. self.downloadButton.setToolTip("下载")
  57. self.downloadButton.clicked.connect(self.actionDownloadHandler)
  58. self.layoutH.addWidget(self.downloadButton)
  59. self.createDirButton = QPushButton(self)
  60. self.createDirButton.setIcon(QIcon(os.path.join(current_directory + "\\icon", "新建文件夹.png")))
  61. self.createDirButton.setIconSize(QSize(32, 32))
  62. self.createDirButton.setFixedSize(36, 36)
  63. self.createDirButton.setToolTip("新建目录")
  64. self.createDirButton.clicked.connect(self.actionCreateHandler)
  65. self.layoutH.addWidget(self.createDirButton)
  66. self.renameButton = QPushButton(self)
  67. self.renameButton.setIcon(QIcon(os.path.join(current_directory + "\\icon", "文件重命名.png")))
  68. self.renameButton.setIconSize(QSize(32, 32))
  69. self.renameButton.setFixedSize(36, 36)
  70. self.renameButton.setToolTip("重命名")
  71. self.renameButton.clicked.connect(self.actionRenameHandler)
  72. self.layoutH.addWidget(self.renameButton)
  73. self.deleteButton = QPushButton(self)
  74. self.deleteButton.setIcon(QIcon(os.path.join(current_directory + "\\icon", "文件删除.png")))
  75. self.deleteButton.setIconSize(QSize(32, 32))
  76. self.deleteButton.setFixedSize(36, 36)
  77. self.deleteButton.setToolTip("删除")
  78. self.deleteButton.clicked.connect(self.actionDeleteHandler)
  79. self.layoutH.addWidget(self.deleteButton)
  80. self.modelViewButton = QPushButton(self)
  81. self.modelViewButton.setIcon(QIcon(os.path.join(current_directory + "\\icon", "模型查看.png")))
  82. self.modelViewButton.setIconSize(QSize(32, 32))
  83. self.modelViewButton.setFixedSize(36, 36)
  84. self.modelViewButton.setToolTip("查看模型")
  85. self.modelViewButton.clicked.connect(self.action3DHandler)
  86. self.layoutH.addWidget(self.modelViewButton)
  87. self.openFileButton = QPushButton(self)
  88. self.openFileButton.setIcon(QIcon(os.path.join(current_directory + "\\icon", "文件查看.png")))
  89. self.openFileButton.setIconSize(QSize(32, 32))
  90. self.openFileButton.setFixedSize(36, 36)
  91. self.openFileButton.setToolTip("查看文件")
  92. self.openFileButton.clicked.connect(self.actionFileOpenHandler)
  93. self.layoutH.addWidget(self.openFileButton)
  94. # 目录树结构区
  95. self.treeWidget = QTreeWidget() # QTreeWidget组件定义
  96. self.treeWidget.headerItem().setText(0, "列表") # FTP服务器节点树
  97. self.treeWidget.headerItem().setText(1, "类型") # 节点对应的类型:文件,文件夹
  98. self.treeWidget.headerItem().setText(2, "路径") # 当前节点在FTP服务器中的路径,方便文件操作时获取服务器中路径,为隐藏列
  99. self.treeWidget.setColumnWidth(0, 375) # 给第1列设置列宽
  100. self.rootItem = QTreeWidgetItem()
  101. self.rootItem.setText(0, "文件结构树") # 给根节点增加文本
  102. self.treeWidget.addTopLevelItem(self.rootItem) # 增加根节点
  103. self.layoutV.addWidget(self.treeWidget) # 将组件添加到布局中
  104. self.treeWidget.setColumnHidden(2, True) # 隐藏路径列
  105. self.mainLayout.addLayout(self.layoutH)
  106. self.mainLayout.addLayout(self.layoutV) # 为窗体添加布局
  107. SearchDockWidget.setWidget(self.dockWidgetContents)
  108. self.retranslateUi(SearchDockWidget)
  109. QtCore.QMetaObject.connectSlotsByName(SearchDockWidget)
  110. self.traverseFTPDirectory(self.ftpOper.ftp, '/', self.rootItem) # 遍历构建树
  111. def retranslateUi(self, SearchDockWidget):
  112. _translate = QtCore.QCoreApplication.translate
  113. SearchDockWidget.setWindowTitle(_translate("SearchDockWidget", "文件服务器"))
  114. def actionUploadHandler(self):
  115. if self.treeWidget.currentItem():
  116. self.currentItem = self.treeWidget.currentItem()
  117. if self.currentItem.text(1) == '文件': # 如果选中文件节点则获取此节点的父节点
  118. self.ftp_path = self.currentItem.parent().text(2)
  119. self.ftpItem = self.currentItem.parent()
  120. elif self.currentItem.text(1) == '文件夹':
  121. self.ftp_path = self.currentItem.text(2)
  122. self.ftpItem = self.currentItem
  123. file_paths, _ = QFileDialog.getOpenFileNames(None, '选择文件', '', 'All Files (*)')
  124. if len(file_paths) > 0:
  125. for file_path in file_paths:
  126. self.file_name = os.path.basename(file_path)
  127. self.ftpOper.uploadfile(file_path, self.ftp_path)
  128. self.fileItem = QTreeWidgetItem()
  129. self.fileItem.setText(0, self.file_name)
  130. self.fileItem.setText(1, '文件')
  131. self.fileItem.setText(2, self.ftp_path + '/' + self.file_name)
  132. # 已有同名节点不再增加此名称的节点
  133. havesame = self.findTreeSameNode(self.ftpItem, self.file_name)
  134. if not havesame:
  135. self.ftpItem.addChild(self.fileItem)
  136. else:
  137. QMessageBox.information(self, "提示信息", "请选择树节点")
  138. # 文件上传时查找目录树此节点的子节点中是否已有此名称
  139. def findTreeSameNode(self, thisitem, filename):
  140. for i in range(thisitem.childCount()):
  141. child = thisitem.child(i)
  142. if child.text(0) == filename:
  143. return True
  144. else:
  145. return False
  146. # 文件夹上传操作
  147. def actionUploadDirHandler(self):
  148. if self.treeWidget.currentItem():
  149. self.currentItem = self.treeWidget.currentItem()
  150. if self.currentItem.text(1) == '文件': # 如果选中文件节点则获取此节点的父节点
  151. self.ftp_path = self.currentItem.parent().text(2)
  152. self.ftpItem = self.currentItem.parent()
  153. else:
  154. self.ftp_path = self.currentItem.text(2)
  155. self.ftpItem = self.currentItem
  156. dir_path = QFileDialog.getExistingDirectory(None, "选择文件夹", "")
  157. if dir_path:
  158. self.ftpOper.uploaddir(dir_path, self.ftp_path)
  159. dirname = os.path.split(dir_path)[-1] # 文件夹名称
  160. rootchildItem = QTreeWidgetItem()
  161. rootchildItem.setText(0, dirname)
  162. rootchildItem.setText(1, '文件夹')
  163. rootchildItem.setText(2, self.ftp_path + '/' + dirname)
  164. self.ftpItem.addChild(rootchildItem)
  165. self.traverseLocalDirectory(dir_path, rootchildItem, self.ftp_path + '/' + dirname)
  166. else:
  167. QMessageBox.information(self, "提示信息", "请选择树节点")
  168. # 遍历本地目录,构建可视化树结构
  169. def traverseLocalDirectory(self, dirpath, item, ftppath):
  170. for file in os.listdir(dirpath):
  171. src = os.path.join(dirpath, file)
  172. childItem = QTreeWidgetItem()
  173. childItem.setText(0, file)
  174. if os.path.isfile(src):
  175. childItem.setText(1, '文件')
  176. childItem.setText(2, ftppath + '/' + file)
  177. item.addChild(childItem)
  178. elif os.path.isdir(src):
  179. childItem.setText(1, '文件夹')
  180. childItem.setText(2, ftppath + '/' + file)
  181. item.addChild(childItem)
  182. # 递归调用自身
  183. self.traverseLocalDirectory(src, childItem, ftppath + '/' + file)
  184. # 文件下载操作
  185. def actionDownloadHandler(self):
  186. if self.treeWidget.currentItem():
  187. self.currentItem = self.treeWidget.currentItem()
  188. dir_path = QFileDialog.getExistingDirectory(None, "选择文件夹", "")
  189. if dir_path:
  190. if self.currentItem.text(1) == '文件':
  191. localfilepath = dir_path + '/' + self.currentItem.text(0)
  192. reomtefilepath = self.currentItem.text(2)
  193. self.ftpOper.downloadfile(localfilepath, reomtefilepath)
  194. else:
  195. localdirpath = dir_path + '/' + self.currentItem.text(0)
  196. remotedirpath = self.currentItem.text(2)
  197. self.ftpOper.downloaddir(localdirpath, remotedirpath)
  198. else:
  199. QMessageBox.information(self, "提示信息", "请选择树节点")
  200. # 文件删除操作
  201. def actionDeleteHandler(self):
  202. if self.treeWidget.currentItem():
  203. self.currentItem = self.treeWidget.currentItem()
  204. questiontext = '是否要删除所选中的:【' + self.currentItem.text(0) + '】?'
  205. question = QMessageBox.question(None, '删除确认', questiontext)
  206. if question == QMessageBox.Yes:
  207. reomtefilepath = self.currentItem.text(2)
  208. if self.currentItem.text(1) == '文件':
  209. remotepath, remotefile_name = os.path.split(reomtefilepath)
  210. self.ftpOper.deletfile(remotefile_name, remotepath) # 删除FTP服务端文件
  211. self.currentItem.parent().removeChild(self.currentItem) # 删除目录树对应的节点
  212. else:
  213. self.ftpOper.deletedir(reomtefilepath)
  214. self.currentItem.parent().removeChild(self.currentItem) # 删除目录树对应的节点
  215. else:
  216. QMessageBox.information(self, "提示信息", "请选择树节点")
  217. # 创建文件夹操作
  218. def actionCreateHandler(self):
  219. if self.treeWidget.currentItem():
  220. self.currentItem = self.treeWidget.currentItem()
  221. dirname, ok = QInputDialog.getText(QWidget(), '新建文件夹', '请输入文件夹名称:')
  222. if ok:
  223. if self.currentItem.text(1):
  224. if self.currentItem.text(1) == '文件': # 如果选中文件节点则获取此节点的父节点
  225. self.dirpath = self.currentItem.parent().text(2)
  226. self.ftpItem = self.currentItem.parent()
  227. else:
  228. self.dirpath = self.currentItem.text(2)
  229. self.ftpItem = self.currentItem
  230. else:
  231. self.dirpath = ''
  232. self.ftpItem = self.currentItem
  233. self.newdirpath = self.dirpath + '/' + dirname
  234. self.rusulttext = self.ftpOper.makedir(dirname, self.dirpath, self.newdirpath)
  235. if self.rusulttext == '文件夹创建成功':
  236. self.fileItem = QTreeWidgetItem()
  237. self.fileItem.setText(0, dirname)
  238. self.fileItem.setText(1, '文件夹')
  239. self.fileItem.setText(2, self.newdirpath)
  240. self.ftpItem.addChild(self.fileItem)
  241. else:
  242. QMessageBox.information(self, "提示信息", "请选择树节点")
  243. # 重命名操作
  244. def actionRenameHandler(self):
  245. if self.treeWidget.currentItem():
  246. self.currentItem = self.treeWidget.currentItem()
  247. extension = None
  248. oldname = None
  249. oldpath = None
  250. if self.currentItem.text(1) == '文件':
  251. oldname, oldextension = os.path.splitext(self.currentItem.text(0))
  252. elif self.currentItem.text(1) == '文件夹':
  253. oldname = self.currentItem.text(0)
  254. newname, ok = QInputDialog.getText(QWidget(), '重命名', '请输入新名称', QLineEdit.Normal, oldname)
  255. if ok:
  256. if self.currentItem.text(1) == '文件':
  257. oldpath = self.currentItem.text(2)
  258. pathparent, name1 = os.path.split(oldpath)
  259. name2, extension = os.path.splitext(name1)
  260. newpath = pathparent + '/' + newname + extension
  261. else:
  262. oldpath = self.currentItem.text(2)
  263. if not (self.currentItem.parent().text(1)): # 根目录
  264. newpath = '/' + newname
  265. else:
  266. pathparent, name1 = os.path.split(oldpath)
  267. newpath = pathparent + '/' + newname
  268. result = self.ftpOper.rename(oldpath, newpath)
  269. if result:
  270. if extension:
  271. self.currentItem.setText(0, newname + extension)
  272. else:
  273. self.currentItem.setText(0, newname)
  274. self.currentItem.setText(2, newpath)
  275. else:
  276. QMessageBox.information(self, "提示信息", "请选择树节点")
  277. # 查看三维模型操作
  278. def action3DHandler(self):
  279. if self.treeWidget.currentItem():
  280. self.currentItem = self.treeWidget.currentItem()
  281. if (self.currentItem.text(1) == '文件'):
  282. modelUrl = modelViewerUri + modelBaseUri + self.currentItem.text(2)
  283. self.modelWebView = ModelWebView(weburi=modelUrl, title='数管系统三维模型浏览')
  284. self.modelWebView.show()
  285. else:
  286. QMessageBox.information(self, "提示信息", "请选择文件类型树节点")
  287. else:
  288. QMessageBox.information(self, "提示信息", "请选择树节点")
  289. # 打开文件操作
  290. def actionFileOpenHandler(self):
  291. if self.treeWidget.currentItem():
  292. self.currentItem = self.treeWidget.currentItem()
  293. if (self.currentItem.text(1) == '文件'):
  294. localdir = os.path.abspath(os.curdir)
  295. localtempdir = localdir + '/temp'
  296. if os.path.exists(localtempdir):
  297. if self.currentItem.text(1) == '文件':
  298. localfilepath = localtempdir + '/' + self.currentItem.text(0)
  299. reomtefilepath = self.currentItem.text(2)
  300. if os.path.exists(localfilepath):
  301. try:
  302. os.startfile(localfilepath) # 打开本地文件
  303. except Exception as e:
  304. print(e)
  305. else:
  306. self.ftpOper.downloadfile(localfilepath, reomtefilepath) # 下载到本地临时文件夹
  307. try:
  308. os.startfile(localfilepath) # 打开本地文件
  309. except Exception as e:
  310. print(e)
  311. else:
  312. QMessageBox.information(self, "提示信息", "请选择文件类型树节点")
  313. else:
  314. QMessageBox.information(self, "提示信息", "请选择树节点")
  315. # 创建本地文件临时文件夹
  316. def createTempDir(self):
  317. localdir = os.path.abspath(os.curdir)
  318. localtempdir = localdir + '/temp'
  319. if not (os.path.exists(localtempdir)): # 如不存在,创建本地临时文件夹
  320. os.makedirs(localtempdir)
  321. else: # 如存在,删除后重新创建本地临时文件夹
  322. shutil.rmtree(localtempdir)
  323. os.mkdir(localtempdir)
  324. # 遍历FTP服务端目录,构建可视化树结构
  325. def traverseFTPDirectory(self, ftp, path, item):
  326. ftp.cwd(path)
  327. file_list = ftp.nlst()
  328. for file in file_list:
  329. try:
  330. ftp.cwd(path + '/' + file) # 尝试切换到子目录
  331. # 添加子节点
  332. childItem = QTreeWidgetItem()
  333. childItem.setText(0, file)
  334. childItem.setText(1, '文件夹')
  335. childItem.setText(2, (path + '/' + file).replace('//', '/'))
  336. item.addChild(childItem)
  337. # 递归调用自身
  338. self.traverseFTPDirectory(ftp, (path + '/' + file).replace('//', '/'), childItem)
  339. ftp.cwd('..') # 返回到上一级目录
  340. except ftplib.error_perm:
  341. # 添加子节点
  342. childItem = QTreeWidgetItem()
  343. childItem.setText(0, file)
  344. childItem.setText(1, '文件')
  345. childItem.setText(2, (path + '/' + file).replace('//', '/'))
  346. item.addChild(childItem)
  347. class ModelWebView():
  348. def __init__(
  349. self,
  350. weburi: str,
  351. title: Optional[str] = "自定义窗口",
  352. windowW: Optional[int] = 1200,
  353. windowH: Optional[int] = 800,
  354. ):
  355. print("")