WizardDialog.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. #
  2. # This file is part of the LibreOffice project.
  3. #
  4. # This Source Code Form is subject to the terms of the Mozilla Public
  5. # License, v. 2.0. If a copy of the MPL was not distributed with this
  6. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
  7. #
  8. # This file incorporates work covered by the following license notice:
  9. #
  10. # Licensed to the Apache Software Foundation (ASF) under one or more
  11. # contributor license agreements. See the NOTICE file distributed
  12. # with this work for additional information regarding copyright
  13. # ownership. The ASF licenses this file to you under the Apache
  14. # License, Version 2.0 (the "License"); you may not use this file
  15. # except in compliance with the License. You may obtain a copy of
  16. # the License at http://www.apache.org/licenses/LICENSE-2.0 .
  17. #
  18. import uno
  19. import traceback
  20. from abc import ABCMeta, abstractmethod
  21. from .UnoDialog2 import UnoDialog2, Desktop, PropertyNames, UIConsts, \
  22. ItemListenerProcAdapter
  23. from ..common.HelpIds import HelpIds
  24. from ..common.FileAccess import FileAccess
  25. from com.sun.star.lang import NoSuchMethodException
  26. from com.sun.star.frame import TerminationVetoException
  27. from com.sun.star.awt.PushButtonType import HELP, STANDARD
  28. from com.sun.star.awt.FontWeight import BOLD
  29. import sys, os
  30. if sys.version_info < (3,4):
  31. import imp
  32. imp.load_source('strings', os.path.join(os.path.dirname(__file__), '../common/strings.hrc'))
  33. import strings
  34. elif sys.version_info < (3,7):
  35. # imp is deprecated since Python v.3.4
  36. from importlib.machinery import SourceFileLoader
  37. SourceFileLoader('strings', os.path.join(os.path.dirname(__file__), '../common/strings.hrc')).load_module()
  38. import strings
  39. else:
  40. # have to jump through hoops since 3.7, partly because python does not like loading modules that do have a .py extension
  41. import importlib
  42. import importlib.util
  43. import importlib.machinery
  44. module_name = 'strings'
  45. path = os.path.join(os.path.dirname(__file__), '../common/strings.hrc')
  46. spec = importlib.util.spec_from_loader(
  47. module_name,
  48. importlib.machinery.SourceFileLoader(module_name, path)
  49. )
  50. module = importlib.util.module_from_spec(spec)
  51. spec.loader.exec_module(module)
  52. sys.modules[module_name] = module
  53. strings = module
  54. class WizardDialog(UnoDialog2):
  55. __metaclass__ = ABCMeta
  56. __NEXT_ACTION_PERFORMED = "gotoNextAvailableStep"
  57. __BACK_ACTION_PERFORMED = "gotoPreviousAvailableStep"
  58. __FINISH_ACTION_PERFORMED = "finishWizard_1"
  59. __CANCEL_ACTION_PERFORMED = "cancelWizard_1"
  60. __HELP_ACTION_PERFORMED = None
  61. '''
  62. Creates a new instance of WizardDialog
  63. the hid is used as following :
  64. "HID:(hid)" - the dialog
  65. "HID:(hid+1) - the help button
  66. "HID:(hid+2)" - the back button
  67. "HID:(hid+3)" - the next button
  68. "HID:(hid+4)" - the create button
  69. "HID:(hid+5)" - the cancel button
  70. @param xMSF
  71. @param hid_
  72. '''
  73. def __init__(self, xMSF, hid_):
  74. super(WizardDialog,self).__init__(xMSF)
  75. self.__hid = hid_
  76. self.iButtonWidth = 50
  77. self.nNewStep = 1
  78. self.nOldStep = 1
  79. self.nMaxStep = 1
  80. self.bTerminateListenermustberemoved = True
  81. self.oRoadmap = None
  82. self.terminateListener = None
  83. def activate(self):
  84. try:
  85. self.xUnoDialog.toFront()
  86. except Exception:
  87. pass
  88. # do nothing;
  89. def itemStateChanged(self, itemEvent):
  90. try:
  91. self.nNewStep = itemEvent.ItemId
  92. self.nOldStep = int(self.xDialogModel.Step)
  93. if self.nNewStep != self.nOldStep:
  94. self.switchToStep()
  95. except Exception:
  96. traceback.print_exc()
  97. def setDialogProperties(self, closeable, height, moveable, position_x,
  98. position_Y, step, tabIndex, title, width):
  99. uno.invoke(self.xDialogModel, "setPropertyValues",
  100. ((PropertyNames.PROPERTY_CLOSEABLE,
  101. PropertyNames.PROPERTY_HEIGHT,
  102. PropertyNames.PROPERTY_MOVEABLE,
  103. PropertyNames.PROPERTY_POSITION_X,
  104. PropertyNames.PROPERTY_POSITION_Y,
  105. PropertyNames.PROPERTY_STEP,
  106. PropertyNames.PROPERTY_TABINDEX,
  107. PropertyNames.PROPERTY_TITLE,
  108. PropertyNames.PROPERTY_WIDTH),
  109. (closeable, height, moveable, position_x, position_Y, step,
  110. tabIndex, title, width)))
  111. def setRoadmapInteractive(self, _bInteractive):
  112. self.oRoadmap.Activated = _bInteractive
  113. def setRoadmapComplete(self, bComplete):
  114. self.oRoadmap.Complete = bComplete
  115. def isRoadmapComplete(self):
  116. try:
  117. return bool(self.oRoadmap.Complete)
  118. except Exception:
  119. traceback.print_exc()
  120. return False
  121. def setCurrentRoadmapItemID(self, ID):
  122. if self.oRoadmap is not None:
  123. nCurItemID = self.getCurrentRoadmapItemID()
  124. if nCurItemID != ID:
  125. self.oRoadmap.CurrentItemID = ID
  126. def getCurrentRoadmapItemID(self):
  127. try:
  128. return int(self.oRoadmap.CurrentItemID)
  129. except Exception:
  130. traceback.print_exc()
  131. return -1
  132. def initializePaths(self):
  133. xPropertySet = \
  134. self.xMSF.createInstance("com.sun.star.util.PathSettings")
  135. self.sUserTemplatePath = \
  136. xPropertySet.getPropertyValue("Template_writable")
  137. myFA = FileAccess(self.xMSF)
  138. aInternalPaths = xPropertySet.getPropertyValue("Template_internal")
  139. self.sTemplatePath = ""
  140. for path in aInternalPaths:
  141. if myFA.exists(path + "/wizard", False):
  142. self.sTemplatePath = path
  143. break
  144. if self.sTemplatePath == "":
  145. raise Exception("could not find wizard templates")
  146. def addRoadmap(self):
  147. try:
  148. iDialogHeight = self.xDialogModel.Height
  149. # the roadmap control has got no real TabIndex ever
  150. # that is not correct, but changing this would need time,
  151. # so it is used without TabIndex as before
  152. xRoadmapControl = self.insertControlModel(
  153. "com.sun.star.awt.UnoControlRoadmapModel",
  154. "rdmNavi",
  155. (PropertyNames.PROPERTY_HEIGHT,
  156. PropertyNames.PROPERTY_POSITION_X,
  157. PropertyNames.PROPERTY_POSITION_Y,
  158. PropertyNames.PROPERTY_STEP,
  159. PropertyNames.PROPERTY_TABINDEX, "Tabstop",
  160. PropertyNames.PROPERTY_WIDTH),
  161. ((iDialogHeight - 26), 0, 0, 0,
  162. 0, True, 85))
  163. self.oRoadmap = xRoadmapControl.Model
  164. method = getattr(self, "itemStateChanged")
  165. xRoadmapControl.addItemListener(
  166. ItemListenerProcAdapter(method))
  167. self.oRoadmap.Text = strings.RID_COMMON_START_16
  168. except NoSuchMethodException:
  169. from com.sun.star.awt.VclWindowPeerAttribute import OK
  170. from .SystemDialog import SystemDialog
  171. sError = "The files required could not be found.\n" + \
  172. "Please start the LibreOffice Setup and choose 'Repair'."
  173. SystemDialog.showMessageBox(super().xMSF, "ErrorBox", OK, sError)
  174. except Exception:
  175. traceback.print_exc()
  176. def getRoadmapItemByID(self, _ID):
  177. try:
  178. getByIndex = self.oRoadmap.getByIndex
  179. for i in list(range(self.oRoadmap.Count)):
  180. CurRoadmapItem = getByIndex(i)
  181. CurID = int(CurRoadmapItem.ID)
  182. if CurID == _ID:
  183. return CurRoadmapItem
  184. return None
  185. except Exception:
  186. traceback.print_exc()
  187. return None
  188. def switchToStep(self,_nOldStep=None, _nNewStep=None):
  189. if _nOldStep is not None and _nNewStep is not None:
  190. self.nOldStep = _nOldStep
  191. self.nNewStep = _nNewStep
  192. self.leaveStep(self.nOldStep, self.nNewStep)
  193. if self.nNewStep != self.nOldStep:
  194. if self.nNewStep == self.nMaxStep:
  195. self.xDialogModel.btnWizardNext.DefaultButton = False
  196. self.xDialogModel.btnWizardFinish.DefaultButton = True
  197. else:
  198. self.xDialogModel.btnWizardNext.DefaultButton = True
  199. self.xDialogModel.btnWizardFinish.DefaultButton = False
  200. self.changeToStep(self.nNewStep)
  201. self.enterStep(self.nOldStep, self.nNewStep)
  202. return True
  203. return False
  204. @abstractmethod
  205. def leaveStep(self, nOldStep, nNewStep):
  206. pass
  207. @abstractmethod
  208. def enterStep(self, nOldStep, nNewStep):
  209. pass
  210. def changeToStep(self, nNewStep):
  211. self.xDialogModel.Step = nNewStep
  212. self.setCurrentRoadmapItemID(nNewStep)
  213. self.enableNextButton(self.getNextAvailableStep() > 0)
  214. self.enableBackButton(nNewStep != 1)
  215. def drawNaviBar(self):
  216. try:
  217. curtabindex = UIConsts.SOFIRSTWIZARDNAVITABINDEX
  218. iButtonWidth = self.iButtonWidth
  219. iButtonHeight = 14
  220. iCurStep = 0
  221. iDialogHeight = self.xDialogModel.Height
  222. iDialogWidth = self.xDialogModel.Width
  223. iHelpPosX = 8
  224. iBtnPosY = iDialogHeight - iButtonHeight - 6
  225. iCancelPosX = iDialogWidth - self.iButtonWidth - 6
  226. iFinishPosX = iCancelPosX - 6 - self.iButtonWidth
  227. iNextPosX = iFinishPosX - 6 - self.iButtonWidth
  228. iBackPosX = iNextPosX - 3 - self.iButtonWidth
  229. self.insertControlModel(
  230. "com.sun.star.awt.UnoControlFixedLineModel",
  231. "lnNaviSep",
  232. (PropertyNames.PROPERTY_HEIGHT, "Orientation",
  233. PropertyNames.PROPERTY_POSITION_X,
  234. PropertyNames.PROPERTY_POSITION_Y,
  235. PropertyNames.PROPERTY_STEP,
  236. PropertyNames.PROPERTY_WIDTH),
  237. (1, 0, 0, iDialogHeight - 26, iCurStep, iDialogWidth))
  238. self.insertControlModel(
  239. "com.sun.star.awt.UnoControlFixedLineModel",
  240. "lnRoadSep",
  241. (PropertyNames.PROPERTY_HEIGHT,
  242. "Orientation",
  243. PropertyNames.PROPERTY_POSITION_X,
  244. PropertyNames.PROPERTY_POSITION_Y,
  245. PropertyNames.PROPERTY_STEP,
  246. PropertyNames.PROPERTY_WIDTH),
  247. (iBtnPosY - 6, 1, 85, 0, iCurStep, 1))
  248. propNames = (PropertyNames.PROPERTY_ENABLED,
  249. PropertyNames.PROPERTY_HEIGHT,
  250. PropertyNames.PROPERTY_HELPURL,
  251. PropertyNames.PROPERTY_LABEL,
  252. PropertyNames.PROPERTY_POSITION_X,
  253. PropertyNames.PROPERTY_POSITION_Y,
  254. "PushButtonType",
  255. PropertyNames.PROPERTY_STEP,
  256. PropertyNames.PROPERTY_TABINDEX,
  257. PropertyNames.PROPERTY_WIDTH)
  258. self.xDialogModel.HelpURL = HelpIds.getHelpIdString(self.__hid)
  259. self.insertButton("btnWizardHelp",
  260. WizardDialog.__HELP_ACTION_PERFORMED,
  261. (PropertyNames.PROPERTY_ENABLED,
  262. PropertyNames.PROPERTY_HEIGHT,
  263. PropertyNames.PROPERTY_LABEL,
  264. PropertyNames.PROPERTY_POSITION_X,
  265. PropertyNames.PROPERTY_POSITION_Y,
  266. "PushButtonType",
  267. PropertyNames.PROPERTY_STEP,
  268. PropertyNames.PROPERTY_TABINDEX,
  269. PropertyNames.PROPERTY_WIDTH),
  270. (True, iButtonHeight,
  271. strings.RID_COMMON_START_15,
  272. iHelpPosX, iBtnPosY,
  273. uno.Any("short",HELP), iCurStep,
  274. uno.Any("short",(curtabindex + 1)), iButtonWidth), self)
  275. self.insertButton("btnWizardBack",
  276. WizardDialog.__BACK_ACTION_PERFORMED, propNames,
  277. (False, iButtonHeight, HelpIds.getHelpIdString(self.__hid + 2),
  278. strings.RID_COMMON_START_13,
  279. iBackPosX, iBtnPosY, uno.Any("short",STANDARD), iCurStep,
  280. uno.Any("short",(curtabindex + 1)), iButtonWidth), self)
  281. self.insertButton("btnWizardNext",
  282. WizardDialog.__NEXT_ACTION_PERFORMED, propNames,
  283. (True, iButtonHeight, HelpIds.getHelpIdString(self.__hid + 3),
  284. strings.RID_COMMON_START_14,
  285. iNextPosX, iBtnPosY, uno.Any("short",STANDARD), iCurStep,
  286. uno.Any("short",(curtabindex + 1)), iButtonWidth), self)
  287. self.insertButton("btnWizardFinish",
  288. WizardDialog.__FINISH_ACTION_PERFORMED, propNames,
  289. (True, iButtonHeight, HelpIds.getHelpIdString(self.__hid + 4),
  290. strings.RID_COMMON_START_12,
  291. iFinishPosX, iBtnPosY, uno.Any("short",STANDARD),
  292. iCurStep,
  293. uno.Any("short",(curtabindex + 1)),
  294. iButtonWidth), self)
  295. self.insertButton("btnWizardCancel",
  296. WizardDialog.__CANCEL_ACTION_PERFORMED, propNames,
  297. (True, iButtonHeight, HelpIds.getHelpIdString(self.__hid + 5),
  298. strings.RID_COMMON_START_11,
  299. iCancelPosX, iBtnPosY, uno.Any("short",STANDARD), iCurStep,
  300. uno.Any("short",(curtabindex + 1)),
  301. iButtonWidth), self)
  302. self.xDialogModel.btnWizardNext.DefaultButton = True
  303. except Exception:
  304. traceback.print_exc()
  305. def insertRoadMapItems(self, items, enabled):
  306. for index, item in enumerate(items):
  307. try:
  308. oRoadmapItem = self.oRoadmap.createInstance()
  309. oRoadmapItem.Label = item
  310. oRoadmapItem.Enabled = enabled[index]
  311. oRoadmapItem.ID = index + 1
  312. self.oRoadmap.insertByIndex(index, oRoadmapItem)
  313. except Exception:
  314. traceback.print_exc()
  315. def enableBackButton(self, enabled):
  316. self.xDialogModel.btnWizardBack.Enabled = enabled
  317. def enableNextButton(self, enabled):
  318. self.xDialogModel.btnWizardNext.Enabled = enabled
  319. def enableFinishButton(self, enabled):
  320. self.xDialogModel.btnWizardFinish.Enabled = enabled
  321. def isStepEnabled(self, _nStep):
  322. try:
  323. xRoadmapItem = self.getRoadmapItemByID(_nStep)
  324. # Todo: In this case an exception should be thrown
  325. if xRoadmapItem is None:
  326. return False
  327. bIsEnabled = bool(xRoadmapItem.Enabled)
  328. return bIsEnabled
  329. except Exception:
  330. traceback.print_exc()
  331. return False
  332. def gotoPreviousAvailableStep(self):
  333. try:
  334. if self.nNewStep > 1:
  335. self.nOldStep = self.nNewStep
  336. self.nNewStep -= 1
  337. while self.nNewStep > 0:
  338. bIsEnabled = self.isStepEnabled(self.nNewStep)
  339. if bIsEnabled:
  340. break;
  341. self.nNewStep -= 1
  342. if (self.nNewStep == 0):
  343. self.nNewStep = self.nOldStep
  344. self.switchToStep()
  345. except Exception:
  346. traceback.print_exc()
  347. def getNextAvailableStep(self):
  348. if self.isRoadmapComplete():
  349. i = self.nNewStep + 1
  350. while i <= self.nMaxStep:
  351. if self.isStepEnabled(i):
  352. return i
  353. i += 1
  354. return -1
  355. def gotoNextAvailableStep(self):
  356. try:
  357. self.nOldStep = self.nNewStep
  358. self.nNewStep = self.getNextAvailableStep()
  359. if self.nNewStep > -1:
  360. self.switchToStep()
  361. except Exception:
  362. traceback.print_exc()
  363. @abstractmethod
  364. def finishWizard(self):
  365. pass
  366. def finishWizard_1(self):
  367. '''This function will call
  368. if the finish button is pressed on the UI'''
  369. try:
  370. self.enableFinishButton(False)
  371. success = False
  372. try:
  373. success = self.finishWizard()
  374. finally:
  375. if not success:
  376. self.enableFinishButton(True)
  377. if success:
  378. self.removeTerminateListener()
  379. except Exception:
  380. traceback.print_exc()
  381. def getCurrentStep(self):
  382. try:
  383. return int(self.xDialogModel.Step)
  384. except Exception:
  385. traceback.print_exc()
  386. return -1
  387. def cancelWizard(self):
  388. #can be overwritten by extending class
  389. self.xUnoDialog.endExecute()
  390. def removeTerminateListener(self):
  391. if self.bTerminateListenermustberemoved:
  392. Desktop.getDesktop(self.xMSF).removeTerminateListener(self.terminateListener)
  393. self.bTerminateListenermustberemoved = False
  394. '''
  395. called by the cancel button and
  396. by the window hidden event.
  397. if this method was not called before,
  398. perform a cancel.
  399. '''
  400. def cancelWizard_1(self):
  401. try:
  402. self.cancelWizard()
  403. self.removeTerminateListener()
  404. except Exception:
  405. traceback.print_exc()
  406. def windowHidden(self):
  407. self.cancelWizard_1()
  408. def queryTermination(self):
  409. self.activate()
  410. raise TerminationVetoException()
  411. def disposing(self, arg0):
  412. self.cancelWizard_1()
  413. def optCreateFromTemplateItemChanged(self):
  414. self.bEditTemplate = False
  415. def optMakeChangesItemChanged(self):
  416. self.bEditTemplate = True