dialog.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. from qgis.PyQt import QtWidgets
  2. from qgis.PyQt.QtCore import QThread, pyqtSignal, QTimer
  3. from qgis.PyQt.QtGui import QClipboard
  4. from qgis.PyQt.QtWidgets import QApplication
  5. from .mapmanager import MapManager
  6. from ...ui.setting import Ui_SettingDialog
  7. from ...utils import (
  8. tianditu_map_url,
  9. check_url_status,
  10. check_subdomains,
  11. PluginConfig,
  12. PluginDir,
  13. )
  14. def check_key_format(key: str) -> object:
  15. """检查key格式
  16. Args:
  17. key (str): 天地图key
  18. Returns:
  19. object:
  20. "key_length_error": key的长度有误,
  21. "has_special_character": 含有除字母数字外的其他字符
  22. """
  23. correct_length = 32
  24. key_length = len(key)
  25. key_length_error = False
  26. if key_length != correct_length:
  27. key_length_error = True
  28. return {
  29. "key_length_error": key_length_error,
  30. "has_special_character": not key.isalnum(),
  31. }
  32. class CheckThread(QThread):
  33. check_finished = pyqtSignal(str)
  34. def __init__(self, conf):
  35. super().__init__()
  36. self.conf = conf
  37. self.key = ""
  38. def run(self):
  39. url = tianditu_map_url("vec", self.key, "t0")
  40. tile_url = url.format(x=0, y=0, z=0)
  41. check_msg = check_url_status(tile_url)
  42. if check_msg["code"] == 0:
  43. self.check_finished.emit("正常")
  44. self.conf.set_value("Tianditu/keyisvalid", True)
  45. else:
  46. error_msg = f"{check_msg['msg']}: {check_msg['resolve']}"
  47. self.check_finished.emit(error_msg)
  48. self.conf.set_value("Tianditu/keyisvalid", False)
  49. class PingUrlThread(QThread):
  50. ping_finished = pyqtSignal(list)
  51. def __init__(self, key):
  52. super().__init__()
  53. self.key = key
  54. def run(self):
  55. subdomain_list = ["t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7"]
  56. urls = [
  57. tianditu_map_url("vec", self.key, subdomain) for subdomain in subdomain_list
  58. ]
  59. status = check_subdomains(urls)
  60. self.ping_finished.emit(status)
  61. class SettingDialog(QtWidgets.QDialog, Ui_SettingDialog):
  62. def __init__(self, toolbar):
  63. super().__init__()
  64. self.check_thread = None
  65. self.mapm = None
  66. self.toolbar = toolbar
  67. # 读取配置
  68. self.conf = PluginConfig()
  69. self.subdomain_list = [f"t{i}" for i in range(8)]
  70. # 设置 status label 的定时器
  71. self.timer = QTimer(self)
  72. self.timer.timeout.connect(self.clear_status_label)
  73. # 设置界面
  74. self.setupUi(self)
  75. self.initUI()
  76. def initUI(self):
  77. self.init_keyCombo()
  78. # 如果key输入框是空白的,则禁用保存按钮
  79. if len(self.mLineEdit_key.text()) == 0:
  80. self.saveButton.setEnabled(False)
  81. # 给控件添加事件
  82. self.mLineEdit_key.textChanged.connect(self.on_key_LineEdit_changed)
  83. self.saveButton.clicked.connect(self.save_key)
  84. self.pushButton_copy.clicked.connect(self.copy_key)
  85. self.pushButton_delete.clicked.connect(self.del_key)
  86. self.keyComboBox.currentIndexChanged.connect(self.select_key)
  87. # 是否启用key随机
  88. if self.conf.get_bool_value("Tianditu/random_key"):
  89. self.checkBox_key_rand.setChecked(True)
  90. self.keyComboBox.setEnabled(False)
  91. self.pushButton_copy.setEnabled(False)
  92. self.pushButton_delete.setEnabled(False)
  93. self.checkBox_key_rand.stateChanged.connect(self.enable_key_random)
  94. # subdomain 选择
  95. self.checkBox_domain_rand.setChecked(
  96. self.conf.get_bool_value("Tianditu/random")
  97. )
  98. self.checkBox_domain_rand.stateChanged.connect(self.enable_random)
  99. # subdomian 设置
  100. self.subdomainComboBox.addItems(self.subdomain_list)
  101. self.subdomainComboBox.setCurrentIndex(
  102. self.subdomain_list.index(self.conf.get_value("Tianditu/subdomain"))
  103. )
  104. self.subdomainComboBox.setEnabled(not self.conf.get_value("Tianditu/random"))
  105. self.subdomainComboBox.currentIndexChanged.connect(self.select_subdomain)
  106. # init map manager
  107. map_folder = PluginDir.joinpath("maps")
  108. self.mapm = MapManager(map_folder=map_folder, parent=self.tab_map)
  109. self.verticalLayout_6.addWidget(self.mapm)
  110. self.pushButton_2.clicked.connect(self.mapm.check_update)
  111. #
  112. self.tabWidget.currentChanged.connect(self.adjust_tab_height)
  113. def adjust_tab_height(self):
  114. current_index = self.tabWidget.currentIndex()
  115. if current_index == 0:
  116. self.setFixedHeight(312)
  117. else:
  118. self.setFixedHeight(500) # 根据内容计算高度
  119. def set_status_label(self, text: str):
  120. """
  121. 创建提示
  122. """
  123. self.info_status.setText(text)
  124. self.timer.start(2000)
  125. def clear_status_label(self):
  126. self.info_status.clear()
  127. self.timer.stop()
  128. def get_key_by_masked(self, masked):
  129. key_list = self.conf.get_key_list()
  130. filtered_items = [key for key in key_list if key.startswith(masked[:8])]
  131. if len(filtered_items) > 0:
  132. return filtered_items[0]
  133. return ""
  134. def init_keyCombo(self):
  135. self.keyComboBox.clear() # 先清除
  136. # 如果 key 列表中没有值, keyComboBox 添加提示
  137. key_list = self.conf.get_key_list()
  138. if len(key_list) == 0:
  139. self.keyComboBox.addItem("请添加 key")
  140. self.pushButton_delete.setEnabled(False)
  141. self.pushButton_copy.setEnabled(False)
  142. else:
  143. self.keyComboBox.addItems([f"{key[:8]}****" for key in key_list])
  144. # 将 keyComboBox 的当前值改为当前选用的 key
  145. current_key = self.conf.get_key()
  146. index = key_list.index(current_key)
  147. self.keyComboBox.setCurrentIndex(index)
  148. self.pushButton_delete.setEnabled(True)
  149. self.pushButton_copy.setEnabled(True)
  150. def copy_key(self):
  151. current_key = self.keyComboBox.currentText()
  152. full_key = self.get_key_by_masked(current_key)
  153. clipboard = QApplication.clipboard()
  154. clipboard.setText(full_key, QClipboard.Clipboard)
  155. self.set_status_label(f"已复制{current_key}到剪贴板")
  156. def save_key(self):
  157. key = self.mLineEdit_key.text()
  158. key_list = self.conf.get_key_list()
  159. if key not in key_list:
  160. url = tianditu_map_url("vec", key, "t0")
  161. tile_url = url.format(x=0, y=0, z=0)
  162. check_msg = check_url_status(tile_url)
  163. if check_msg["code"] == 0:
  164. if self.keyComboBox.itemText(0) == "请添加 key":
  165. self.keyComboBox.removeItem(0)
  166. self.mLineEdit_key.setText("")
  167. key_list.append(key)
  168. self.conf.save_key_list(key_list)
  169. self.saveButton.setEnabled(False)
  170. self.set_status_label("保存成功")
  171. self.init_keyCombo()
  172. else:
  173. error_msg = f"{check_msg['msg']}: {check_msg['resolve']}"
  174. self.set_status_label(error_msg)
  175. else:
  176. self.set_status_label("key 已存在")
  177. def select_key(self):
  178. if self.keyComboBox.count() > 0:
  179. masked_key = self.keyComboBox.currentText()
  180. key = self.get_key_by_masked(masked_key)
  181. self.conf.set_key(key)
  182. self.set_status_label(f"设置当前 key 为{masked_key}")
  183. def del_key(self):
  184. current_index = self.keyComboBox.currentIndex()
  185. key_list = self.conf.get_key_list()
  186. del key_list[current_index]
  187. self.conf.save_key_list(key_list)
  188. self.set_status_label("已删除")
  189. self.init_keyCombo()
  190. def handle_ping_finished(self, status):
  191. min_time = min(status)
  192. min_index = status.index(min_time)
  193. for i in range(8):
  194. self.comboBox.setItemText(i, f"t{i} {status[i]}")
  195. self.comboBox.setItemText(min_index, f"t{min_index} {status[min_index]}*")
  196. def on_key_LineEdit_changed(self):
  197. current_text = self.mLineEdit_key.text()
  198. # 删除key中的空格以及非打印字符
  199. filtered_text = "".join(
  200. [c for c in current_text if c.isprintable() and not c.isspace()]
  201. )
  202. if filtered_text != current_text:
  203. self.mLineEdit_key.setText(filtered_text)
  204. # 检查key格式
  205. if len(self.mLineEdit_key.text()) > 0:
  206. key_format = check_key_format(self.mLineEdit_key.text())
  207. if key_format["key_length_error"]:
  208. self.info_status.setText("无效key: 格式错误(长度不对)")
  209. self.saveButton.setEnabled(False)
  210. elif key_format["has_special_character"]:
  211. self.info_status.setText("无效key: 含非常规字符")
  212. self.saveButton.setEnabled(False)
  213. else:
  214. self.info_status.setText("点击保存")
  215. self.saveButton.setEnabled(True)
  216. else:
  217. self.info_status.clear()
  218. def select_subdomain(self):
  219. selected_index = self.subdomainComboBox.currentIndex()
  220. selected_domain = self.subdomain_list[selected_index]
  221. self.conf.set_value("Tianditu/subdomain", selected_domain)
  222. self.set_status_label(f"设置 subdomain 为 {selected_domain}")
  223. def enable_random(self):
  224. if self.checkBox_domain_rand.isChecked():
  225. self.conf.set_value("Tianditu/random", True)
  226. self.subdomainComboBox.setEnabled(False)
  227. self.set_status_label("设置 subdomain 为 随机")
  228. else:
  229. self.conf.set_value("Tianditu/random", False)
  230. self.subdomainComboBox.setEnabled(True)
  231. def enable_key_random(self):
  232. if self.checkBox_key_rand.isChecked():
  233. self.conf.set_value("Tianditu/random_key", True)
  234. self.keyComboBox.setEnabled(False)
  235. self.pushButton_copy.setEnabled(False)
  236. self.pushButton_delete.setEnabled(False)
  237. self.set_status_label("设置 key 为 随机")
  238. else:
  239. self.conf.set_value("Tianditu/random_key", False)
  240. self.keyComboBox.setEnabled(True)
  241. self.pushButton_copy.setEnabled(True)
  242. self.pushButton_delete.setEnabled(True)
  243. def closeEvent(self, event):
  244. # 在对话框关闭时触发的事件
  245. self.mapm.update_map_enable_state()
  246. self.toolbar.add_button.setup_action()
  247. event.accept() # 接受关闭事件,关闭对话框