PropertyEditor.js 62 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741
  1. /**
  2. * Copyright (c) 2011-2018 by Andrew Mustun. All rights reserved.
  3. *
  4. * This file is part of the QCAD project.
  5. *
  6. * QCAD is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * QCAD is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with QCAD.
  18. */
  19. include("scripts/EAction.js");
  20. include("scripts/sprintf.js");
  21. include("scripts/WidgetFactory.js");
  22. /**
  23. * Internal helper class. Notified when properties are changed.
  24. */
  25. function PropertyWatcher(propertyEditor, sender, propertyType) {
  26. this.propertyEditor = propertyEditor;
  27. this.sender = sender;
  28. this.propertyType = propertyType;
  29. }
  30. /**
  31. * Called when a property has been changed by the user. Triggers
  32. * a transaction to change the property of all selected entities
  33. * that match the current entity type filter.
  34. */
  35. PropertyWatcher.prototype.propertyChanged = function(value) {
  36. // TODO:
  37. // only do something if the value has actually changed
  38. // remember edited status of widgets
  39. // qDebug("propertyChanged:", value);
  40. // qDebug("propertyChanged: sender: ", this.sender);
  41. var attributes = this.propertyEditor.getPropertyAttributes(this.propertyType);
  42. var typeHint = RS.UnknownType;
  43. // value is a list property (e.g. x coordinate of a vertex of a polyline):
  44. if (attributes.isList()) {
  45. var indexControlObjectName =
  46. PropertyEditorImpl.getIndexControlObjectName(this.propertyType.getPropertyGroupTitle());
  47. var indexControl = this.propertyEditor.widget.findChild(indexControlObjectName);
  48. var index = indexControl.value;
  49. value = this.sender.getValue();
  50. if (!isNumber(value)) {
  51. return;
  52. }
  53. this.propertyEditor.listPropertyChanged(this.propertyType, index, value);
  54. return;
  55. }
  56. // value comes from a combo box:
  57. else if (isComboBox(this.sender)) {
  58. // value is index of combo box:
  59. if (isNumber(value)) {
  60. if (this.sender.itemData(value)===PropertyEditor.varies) {
  61. return;
  62. }
  63. this.propertyEditor.propertyChanged(this.propertyType,
  64. this.sender.itemData(value));
  65. return;
  66. }
  67. if (value===PropertyEditor.varies) {
  68. return;
  69. }
  70. }
  71. // value is string from a line edit (e.g. text contents):
  72. else if (isOfType(this.sender, QLineEdit)) {
  73. value = this.sender.text;
  74. if (value===PropertyEditor.varies) {
  75. return;
  76. }
  77. }
  78. // value is number from a math line edit:
  79. else if (isOfType(this.sender, RMathLineEdit)) {
  80. if (this.sender.text===this.sender.originalText) {
  81. return;
  82. }
  83. this.sender.setProperty("originalText", this.sender.text);
  84. value = this.sender.getValue();
  85. if (isNaN(value)) {
  86. this.propertyEditor.updateGui(true);
  87. return;
  88. }
  89. if (this.sender.isInteger()) {
  90. typeHint = RS.Int;
  91. }
  92. }
  93. // value is number from a math combo box:
  94. else if (isOfType(this.sender, RMathComboBox)) {
  95. if (this.sender.currentText===this.sender.originalText) {
  96. return;
  97. }
  98. this.sender.setProperty("originalText", this.sender.text);
  99. value = this.sender.getValue();
  100. if (isNaN(value)) {
  101. this.propertyEditor.updateGui(true);
  102. return;
  103. }
  104. }
  105. this.propertyEditor.propertyChanged(this.propertyType, value, typeHint);
  106. };
  107. /**
  108. * Called when a custom property has been deleted by the user. Triggers
  109. * a transaction to delete the property from all selected entities
  110. * that match the current entity type filter.
  111. */
  112. PropertyWatcher.prototype.propertyRemoved = function() {
  113. if (RSettings.getQtVersion() >= 0x060000) {
  114. this.propertyEditor.propertyChanged(this.propertyType, new QVariant());
  115. }
  116. else {
  117. this.propertyEditor.propertyChanged(this.propertyType, null);
  118. }
  119. this.propertyEditor.onlyChangesOverride = false;
  120. };
  121. /**
  122. * Internal helper class. Notified when indices of list properties are changed.
  123. */
  124. function IndexWatcher(propertyEditor, sender, propertyType) {
  125. this.propertyEditor = propertyEditor;
  126. this.sender = sender;
  127. this.propertyType = propertyType;
  128. }
  129. /**
  130. * Called when the index of a list property has changed and the list value
  131. * needs to be changed to show the list entry at the new index.
  132. */
  133. IndexWatcher.prototype.indexChanged = function(index) {
  134. var objectName = PropertyEditorImpl.getControlObjectName(this.propertyType);
  135. var control = this.propertyEditor.widget.findChild(objectName);
  136. this.propertyEditor.initNumberControls(objectName, this.propertyType, true, control, index);
  137. var indexControlObjectName =
  138. PropertyEditorImpl.getIndexControlObjectName(this.propertyType.getPropertyGroupTitle());
  139. var indexControl = this.propertyEditor.widget.findChild(indexControlObjectName);
  140. if (isNull(indexControl.controlNames)) {
  141. return;
  142. }
  143. var di = EAction.getDocumentInterface();
  144. if (isNull(di)) {
  145. return;
  146. }
  147. if (isNull(indexControl.controlNames[0]) || isNull(indexControl.controlNames[1])) {
  148. return;
  149. }
  150. var controlX = this.propertyEditor.widget.findChild(indexControl.controlNames[0]);
  151. var controlY = this.propertyEditor.widget.findChild(indexControl.controlNames[1]);
  152. if (isNull(controlX) || isNull(controlY)) {
  153. return;
  154. }
  155. var x = controlX.getValue();
  156. var y = controlY.getValue();
  157. var view = di.getLastKnownViewWithFocus();
  158. if (isNull(view)) {
  159. return;
  160. }
  161. // preview position in drawing:
  162. di.clearPreview();
  163. var r = view.mapDistanceFromView(10);
  164. di.addAuxShapeToPreview(new RCircle(new RVector(x, y), r));
  165. di.addAuxShapeToPreview(new RLine(new RVector(x-r, y), new RVector(x+r, y)));
  166. di.addAuxShapeToPreview(new RLine(new RVector(x, y-r), new RVector(x, y+r)));
  167. di.repaintViews();
  168. };
  169. /**
  170. * \class PropertyEditorImpl
  171. * \brief Property editor implementation.
  172. * \ingroup ecma_widgets
  173. */
  174. function PropertyEditorImpl(basePath) {
  175. RPropertyEditor.call(this);
  176. if (isNull(basePath)) {
  177. // only used to initialize prototype for derived class:
  178. return;
  179. }
  180. this.setEntityTypeFilter(RS.EntityAll);
  181. this.widget = WidgetFactory.createWidget(basePath, "PropertyEditor.ui");
  182. this.basePath = basePath;
  183. this.colon = qsTr(":");
  184. this.widget.findChild("LabelLayer").text = RSettings.translate("REntity", "Layer") + this.colon;
  185. this.widget.findChild("LabelColor").text = RSettings.translate("REntity", "Color") + this.colon;
  186. this.widget.findChild("LabelLineweight").text = RSettings.translate("REntity", "Lineweight") + this.colon;
  187. this.widget.findChild("LabelLinetype").text = RSettings.translate("REntity", "Linetype") + this.colon;
  188. this.widget.findChild("LabelLinetypeScale").text = RSettings.translate("REntity", "Linetype Scale") + this.colon;
  189. this.widget.findChild("LabelDrawOrder").text = RSettings.translate("REntity", "Draw Order") + this.colon;
  190. this.widget.findChild("LabelHandle").text = RSettings.translate("REntity", "Handle") + this.colon;
  191. this.widget.findChild("LabelProtected").text = RSettings.translate("REntity", "Protected") + this.colon;
  192. var selectionCombo = this.widget.findChild("Selection");
  193. selectionCombo["activated(int)"].connect(this, this.filterChanged);
  194. selectionCombo.installEventFilter(new REventFilter(QEvent.Wheel.valueOf(), true));
  195. selectionCombo.focusPolicy = Qt.ClickFocus;
  196. // initialize fixed general properties at the top:
  197. var layerCombo = this.widget.findChild("Layer");
  198. if (RSettings.isQt(6)) {
  199. var pw = new PropertyWatcher(this, layerCombo, REntity.PropertyLayer);
  200. layerCombo.textActivated.connect(pw, pw.propertyChanged);
  201. }
  202. else {
  203. layerCombo['activated(QString)'].connect(
  204. new PropertyWatcher(this, layerCombo, REntity.PropertyLayer),
  205. 'propertyChanged');
  206. }
  207. layerCombo.installEventFilter(new REventFilter(QEvent.Wheel.valueOf(), true));
  208. layerCombo.focusPolicy = Qt.ClickFocus;
  209. var colorCombo = this.widget.findChild("Color");
  210. if (RSettings.isQt(6)) {
  211. var pw = new PropertyWatcher(this, colorCombo, REntity.PropertyColor);
  212. colorCombo['activated(int)'].connect(pw, pw.propertyChanged);
  213. }
  214. else {
  215. colorCombo['activated(int)'].connect(
  216. new PropertyWatcher(this, colorCombo, REntity.PropertyColor),
  217. 'propertyChanged');
  218. }
  219. colorCombo.installEventFilter(new REventFilter(QEvent.Wheel.valueOf(), true));
  220. colorCombo.focusPolicy = Qt.ClickFocus;
  221. var lineweightCombo = this.widget.findChild("Lineweight");
  222. if (RSettings.isQt(6)) {
  223. var pw = new PropertyWatcher(this, lineweightCombo, REntity.PropertyLineweight);
  224. lineweightCombo['activated(int)'].connect(pw, pw.propertyChanged);
  225. }
  226. else {
  227. lineweightCombo['activated(int)'].connect(
  228. new PropertyWatcher(this, lineweightCombo, REntity.PropertyLineweight),
  229. 'propertyChanged');
  230. }
  231. lineweightCombo.installEventFilter(new REventFilter(QEvent.Wheel.valueOf(), true));
  232. lineweightCombo.focusPolicy = Qt.ClickFocus;
  233. var linetypeCombo = this.widget.findChild("Linetype");
  234. if (RSettings.isQt(6)) {
  235. var pw = new PropertyWatcher(this, linetypeCombo, REntity.PropertyLinetype);
  236. linetypeCombo['activated(int)'].connect(pw, pw.propertyChanged);
  237. }
  238. else {
  239. linetypeCombo['activated(int)'].connect(
  240. new PropertyWatcher(this, linetypeCombo, REntity.PropertyLinetype),
  241. 'propertyChanged');
  242. }
  243. linetypeCombo.installEventFilter(new REventFilter(QEvent.Wheel.valueOf(), true));
  244. linetypeCombo.focusPolicy = Qt.ClickFocus;
  245. //var itemDelegate = new QStyledItemDelegate();
  246. //linetypeCombo.setItemDelegate(itemDelegate);
  247. // linetypeCombo.styleSheet = ""
  248. // + "QComboBox QAbstractItemView::text "
  249. // + "{ "
  250. // + " image-position: bottom center; "
  251. // + " image: url(:/scripts/Pro/File/SvgExport/SvgExport.svg)"
  252. // + "}"
  253. // + "QComboBox QAbstractItemView::item "
  254. // + "{ "
  255. // + " min-height: 50px; "
  256. // + " image-position: bottom center; "
  257. // + " image: url(:/scripts/Pro/File/SvgExport/SvgExport.svg)"
  258. // + "}";
  259. var linetypeScaleEdit = this.widget.findChild("LinetypeScale");
  260. if (RSettings.isQt(6)) {
  261. var pw = new PropertyWatcher(this, linetypeScaleEdit, REntity.PropertyLinetypeScale);
  262. linetypeScaleEdit.editingFinished.connect(pw, pw.propertyChanged);
  263. }
  264. else {
  265. linetypeScaleEdit.editingFinished.connect(
  266. new PropertyWatcher(this, linetypeScaleEdit, REntity.PropertyLinetypeScale),
  267. 'propertyChanged');
  268. }
  269. var drawOrderEdit = this.widget.findChild("DrawOrder");
  270. if (RSettings.isQt(6)) {
  271. var pw = new PropertyWatcher(this, drawOrderEdit, REntity.PropertyDrawOrder);
  272. drawOrderEdit.editingFinished.connect(pw, pw.propertyChanged);
  273. }
  274. else {
  275. drawOrderEdit.editingFinished.connect(
  276. new PropertyWatcher(this, drawOrderEdit, REntity.PropertyDrawOrder),
  277. 'propertyChanged');
  278. }
  279. this.geometryGroup = undefined;
  280. this.childGroup = undefined;
  281. this.customGroup = undefined;
  282. this.onlyChangesOverride = undefined;
  283. }
  284. PropertyEditorImpl.prototype = new RPropertyEditor();
  285. /**
  286. * Implementation from RPropertyEditor to update the property editor GUI.
  287. */
  288. PropertyEditorImpl.prototype.updateGui = function(onlyChanges) {
  289. var row;
  290. // if (!isNull(entityTypeFilter)) {
  291. // this.entityTypeFilter=entityTypeFilter;
  292. // }
  293. // if (isNull(this.entityTypeFilter)) {
  294. // debugger;
  295. // }
  296. if (!isNull(this.onlyChangesOverride)) {
  297. onlyChanges = this.onlyChangesOverride;
  298. this.onlyChangesOverride = undefined;
  299. }
  300. this.widget.updatesEnabled = false;
  301. if (!onlyChanges) {
  302. if (!isNull(this.geometryGroup)) {
  303. destr(this.geometryGroup);
  304. this.geometryGroup = undefined;
  305. }
  306. if (!isNull(this.childGroup)) {
  307. destr(this.childGroup);
  308. this.childGroup = undefined;
  309. }
  310. if (!isNull(this.customGroup)) {
  311. destr(this.customGroup);
  312. this.customGroup = undefined;
  313. }
  314. }
  315. var selectionCombo = this.widget.findChild("Selection");
  316. var generalGroup = this.widget.findChild("General");
  317. var layerCombo = this.widget.findChild("Layer");
  318. var colorCombo = this.widget.findChild("Color");
  319. var lineweightCombo = this.widget.findChild("Lineweight");
  320. var linetypeCombo = this.widget.findChild("Linetype");
  321. var doc = EAction.getDocument();
  322. linetypeCombo.init(isNull(doc) ? null : doc);
  323. var linetypeScaleEdit = this.widget.findChild("LinetypeScale");
  324. var drawOrderEdit = this.widget.findChild("DrawOrder");
  325. var handleEdit = this.widget.findChild("Handle");
  326. this.makeReadOnly(handleEdit);
  327. var protectedLabel = this.widget.findChild("LabelProtected");
  328. var protectedCombo = this.widget.findChild("Protected");
  329. this.makeReadOnly(protectedCombo);
  330. // comment out to to inspect protected property (debugging):
  331. protectedLabel.visible = false;
  332. protectedCombo.visible = false;
  333. var scrollArea = this.widget.findChild("ScrollArea");
  334. var layout = scrollArea.layout();
  335. //if (!onlyChanges) {
  336. selectionCombo.clear();
  337. // TODO: add 'no selection' item to choose current pen:
  338. //selectionCombo.addItem(qsTr("No Selection"), -2);
  339. //}
  340. var groups = this.getGroupTitles();
  341. // no properties to show or 'No Selection' chosen:
  342. if (groups.length===0 /*|| selectionCombo.currentIndex===0*/) {
  343. selectionCombo.clear();
  344. selectionCombo.insertItem(0, qsTr("No Selection"));
  345. layerCombo.clear();
  346. colorCombo.currentIndex = 0;
  347. lineweightCombo.currentIndex = 0;
  348. linetypeCombo.currentIndex = 0;
  349. linetypeScaleEdit.text = "";
  350. drawOrderEdit.text = "";
  351. handleEdit.text = "";
  352. protectedCombo.clear();
  353. generalGroup.enabled = false;
  354. this.widget.updatesEnabled = true;
  355. return;
  356. }
  357. var gridLayoutGeometry = undefined;
  358. var gridLayoutChild = undefined;
  359. var gridLayoutCustom = undefined;
  360. if (!onlyChanges) {
  361. // create geometry group box with grid layout:
  362. this.geometryGroup = new QGroupBox(qsTr("Specific Properties"), this.widget);
  363. this.geometryGroup.objectName = "GeometryGroup";
  364. layout.insertWidget(2, this.geometryGroup);
  365. // grid layout with three columns and N rows for N property controls:
  366. gridLayoutGeometry = new QGridLayout(this.geometryGroup);
  367. gridLayoutGeometry.setVerticalSpacing(2);
  368. gridLayoutGeometry.setHorizontalSpacing(2);
  369. // label:
  370. gridLayoutGeometry.setColumnStretch(0,0);
  371. // control:
  372. gridLayoutGeometry.setColumnStretch(1,1);
  373. // control or additional controls (e.g. clear button for dimension label):
  374. gridLayoutGeometry.setColumnStretch(2,1);
  375. this.geometryGroup.setLayout(gridLayoutGeometry);
  376. // child properties
  377. // (block attributes shown when block reference is selected):
  378. // create child property group box with grid layout:
  379. this.childGroup = new QGroupBox(qsTr("Dependent Entities"), this.widget);
  380. this.childGroup.objectName = "ChildGroup";
  381. layout.insertWidget(3, this.childGroup);
  382. // grid layout with four columns and N rows for N property controls:
  383. // (the fourth column is for the 'remove property' button)
  384. gridLayoutChild = new QGridLayout(this.childGroup);
  385. gridLayoutChild.setVerticalSpacing(2);
  386. gridLayoutChild.setColumnStretch(0,0);
  387. gridLayoutChild.setColumnStretch(1,1);
  388. gridLayoutChild.setColumnStretch(2,0);
  389. gridLayoutChild.setColumnStretch(3,0);
  390. this.childGroup.setLayout(gridLayoutChild);
  391. this.childGroup.visible = false;
  392. // custom properties:
  393. if (RSettings.isXDataEnabled()) {
  394. // create custom property group box with grid layout:
  395. this.customGroup = new QGroupBox(qsTr("Custom"), this.widget);
  396. //this.customGroup.objectName = "CustomGroup";
  397. layout.insertWidget(4, this.customGroup);
  398. // grid layout with four columns and N rows for N property controls:
  399. // (the fourth column is for the 'remove property' button)
  400. gridLayoutCustom = new QGridLayout(this.customGroup);
  401. gridLayoutCustom.setVerticalSpacing(2);
  402. gridLayoutCustom.setColumnStretch(0,0);
  403. gridLayoutCustom.setColumnStretch(1,1);
  404. gridLayoutCustom.setColumnStretch(2,0);
  405. gridLayoutCustom.setColumnStretch(3,0);
  406. this.customGroup.setLayout(gridLayoutCustom);
  407. }
  408. }
  409. else {
  410. if (!isNull(this.geometryGroup)) {
  411. gridLayoutGeometry = this.geometryGroup.layout();
  412. }
  413. if (!isNull(this.childGroup)) {
  414. gridLayoutChild = this.childGroup.layout();
  415. }
  416. if (!isNull(this.customGroup)) {
  417. gridLayoutCustom = this.customGroup.layout();
  418. }
  419. }
  420. // clear custom property group and child (block attributes) groups:
  421. // these are always rebuilt:
  422. var groupsToClear = [this.customGroup, this.childGroup];
  423. for (var gtci=0; gtci<groupsToClear.length; gtci++) {
  424. var groupToClear = groupsToClear[gtci];
  425. if (!isNull(groupToClear)) {
  426. var children = groupToClear.children();
  427. for (var i=0; i<children.length; i++) {
  428. var child = children[i];
  429. if (isNull(child)) {
  430. // don't destroy wrapper attached to the group box (QGroupBox_Wrapper):
  431. continue;
  432. }
  433. if (isOfType(child, QGridLayout)) {
  434. // don't destroy layout:
  435. continue;
  436. }
  437. destr(child);
  438. }
  439. }
  440. }
  441. var firstEntry = true;
  442. var gotLayerProperty = false;
  443. var gotLinetypeScaleProperty = false;
  444. var gotDrawOrderProperty = false;
  445. // for all property groups:
  446. for (var gi=0; gi<groups.length; ++gi) {
  447. var group = groups[gi];
  448. //qDebug("group: ", group);
  449. // for all properties in that group:
  450. var titles = this.getPropertyTitles(group);
  451. for (var pi=0; pi<titles.length; ++pi) {
  452. var title = titles[pi];
  453. //qDebug("title: ", title);
  454. var value = this.getPropertyValue(group, title);
  455. //qDebug("value: ", value);
  456. var attributes = this.getPropertyAttributes(group, title);
  457. //var propertyTypeId = attributes.getPropertyTypeId();
  458. var propertyTypeId = RPropertyTypeId.getPropertyTypeId(group, title);
  459. var onlyChangesProp = onlyChanges;
  460. // don't use isCustom here:
  461. if (propertyTypeId.getId()===-1) {
  462. // property is custom property
  463. // make sure it knows it's titles, etc:
  464. propertyTypeId.setCustomPropertyTitle(group);
  465. propertyTypeId.setCustomPropertyName(title);
  466. onlyChangesProp = false;
  467. }
  468. //qDebug("isMixed: ", attributes.isMixed());
  469. if (isNull(value)) {
  470. // invalid value means no property found:
  471. continue;
  472. }
  473. // qDebug("\tproperty: ", title, ": ", value);
  474. // qDebug("\tproperty type id: ", propertyTypeId);
  475. // if (attributes.hasEnumChoices()) {
  476. // var ec = attributes.getEnumChoices();
  477. // qDebug("enumChoices: ", ec.length);
  478. // qDebug("enumChoices: ", ec[0]);
  479. // qDebug("enumChoices: ", ec[1]);
  480. // qDebug("enumChoices: ", ec[2]);
  481. // debugger;
  482. // }
  483. // ignore entity type:
  484. if (propertyTypeId.getId()===REntity.PropertyType.getId()) {
  485. // ignore
  486. }
  487. // ignore block ID:
  488. else if (propertyTypeId.getId()===REntity.PropertyBlock.getId()) {
  489. // ignore
  490. }
  491. // layer:
  492. else if (propertyTypeId.getId()===REntity.PropertyLayer.getId()) {
  493. this.initControls(propertyTypeId, true, layerCombo);
  494. gotLayerProperty = true;
  495. }
  496. // color:
  497. else if (propertyTypeId.getId()===REntity.PropertyColor.getId()) {
  498. this.initControls(propertyTypeId, true, colorCombo);
  499. }
  500. // lineweight:
  501. else if (propertyTypeId.getId()===REntity.PropertyLineweight.getId()) {
  502. this.initControls(propertyTypeId, true, lineweightCombo);
  503. }
  504. // linetype:
  505. else if (propertyTypeId.getId()===REntity.PropertyLinetype.getId()) {
  506. this.initControls(propertyTypeId, true, linetypeCombo);
  507. }
  508. // linetype scale:
  509. else if (propertyTypeId.getId()===REntity.PropertyLinetypeScale.getId()) {
  510. this.initControls(propertyTypeId, true, linetypeScaleEdit);
  511. gotLinetypeScaleProperty = true;
  512. }
  513. // draw order:
  514. else if (propertyTypeId.getId()===REntity.PropertyDrawOrder.getId()) {
  515. this.initControls(propertyTypeId, true, drawOrderEdit);
  516. gotDrawOrderProperty = true;
  517. }
  518. // handle:
  519. else if (propertyTypeId.getId()===RObject.PropertyHandle.getId()) {
  520. this.initControls(propertyTypeId, true, handleEdit);
  521. }
  522. // protected:
  523. else if (propertyTypeId.getId()===RObject.PropertyProtected.getId()) {
  524. this.initControls(propertyTypeId, true, protectedCombo);
  525. }
  526. // other properties:
  527. else {
  528. var gridLayout = undefined;
  529. var groupBox = undefined;
  530. if (propertyTypeId.isCustom()) {
  531. // block reference attributes:
  532. if (propertyTypeId.getCustomPropertyTitle()==="Attributes") {
  533. gridLayout = gridLayoutChild;
  534. groupBox = this.childGroup;
  535. // only show group with dependent entities if needed:
  536. if (!isNull(this.childGroup)) {
  537. this.childGroup.visible = true;
  538. }
  539. }
  540. // custom properties:
  541. else {
  542. gridLayout = gridLayoutCustom;
  543. groupBox = this.customGroup;
  544. }
  545. }
  546. // geometric properties:
  547. else {
  548. gridLayout = gridLayoutGeometry;
  549. groupBox = this.geometryGroup;
  550. }
  551. // for the first property of a new property group,
  552. // add group title and index controls if the property is a list:
  553. if (pi===0 && !isNull(gridLayout) && !isNull(groupBox)) {
  554. // create group label:
  555. if (!onlyChangesProp && group.length!==0 &&
  556. // situation with two splines, one with fit points,
  557. // one with control points: no group label for fit points:
  558. attributes.isList()===isArray(value)) {
  559. var groupLabel = new QLabel(RSettings.translate("REntity", group), groupBox);
  560. groupLabel.styleSheet = "margin-bottom:0px;font-weight:bold;";
  561. if (!firstEntry) {
  562. groupLabel.styleSheet += "margin-top:0px;";
  563. firstEntry = false;
  564. }
  565. gridLayout.addWidget(groupLabel, gridLayout.rowCount(),0, 1,3);
  566. }
  567. // if property is a list, add list index control:
  568. if (!onlyChangesProp && attributes.isList()) {
  569. row = gridLayout.rowCount();
  570. var indexLabel = new QLabel(qsTr("Index"), groupBox);
  571. indexLabel.alignment = Qt.AlignRight | Qt.AlignVCenter;
  572. gridLayout.addWidget(indexLabel, row,0);
  573. var indexControl = new QSpinBox(groupBox);
  574. indexControl.setRange(0, value.length-1);
  575. indexControl.objectName = PropertyEditorImpl.getIndexControlObjectName(group);
  576. //gridLayout.addWidget(indexControl, row,1, 1,2);
  577. gridLayout.addWidget(indexControl, row,1);
  578. var totalLabel = new QLabel("(%1)".arg(value.length), groupBox);
  579. gridLayout.addWidget(totalLabel, row,2);
  580. }
  581. }
  582. var controls = undefined;
  583. if (!isNull(gridLayout)) {
  584. // don't display any Z values or polyline elevation:
  585. var hide = false;
  586. if (!propertyTypeId.isCustom()) {
  587. if (RSettings.getBoolValue("PropertyEditor/ShowZCoordinates", false)===false) {
  588. if (title===RPolylineEntity.PropertyVertexNZ.getPropertyTitle() ||
  589. title===RPolylineEntity.PropertyElevation.getPropertyTitle()) {
  590. hide = true;
  591. }
  592. }
  593. }
  594. if (hide) {
  595. controls = undefined;
  596. }
  597. else {
  598. controls = this.initControls(propertyTypeId, onlyChangesProp);
  599. }
  600. }
  601. // add property name and controls to layout:
  602. if (!onlyChangesProp) {
  603. if (!isNull(controls) && !isNull(gridLayout)) {
  604. row = gridLayout.rowCount();
  605. var localTitle = title;
  606. if (propertyTypeId.isCustom() && group!==RSettings.getAppId() &&
  607. propertyTypeId.getCustomPropertyTitle()!=="Attributes") {
  608. var pos = title.indexOf("_");
  609. if (pos!==-1) {
  610. localTitle = title.mid(pos+1);
  611. }
  612. }
  613. else {
  614. localTitle = RSettings.translate("REntity", title);
  615. }
  616. var l = attributes.getLabel();
  617. if (l.length>0) {
  618. localTitle = l;
  619. }
  620. var label = new QLabel(localTitle + this.colon, groupBox);
  621. label.textInteractionFlags = Qt.TextSelectableByMouse;
  622. label.alignment = Qt.AlignRight | Qt.AlignVCenter;
  623. gridLayout.addWidget(label, row,0);
  624. if (controls.length===1) {
  625. gridLayout.addWidget(controls[0], row,1, 1,2);
  626. }
  627. else if (controls.length===2) {
  628. gridLayout.addWidget(controls[0], row,1);
  629. gridLayout.addWidget(controls[1], row,2);
  630. }
  631. else {
  632. debugger;
  633. }
  634. // 'remove custom property' button:
  635. if (propertyTypeId.isCustom() && !isNull(gridLayoutCustom) &&
  636. group===RSettings.getAppId() && !attributes.isUndeletable()) {
  637. var removeCustomPropertyButton = new QToolButton(this.widget);
  638. removeCustomPropertyButton.icon = new QIcon(autoPath(this.basePath + "/RemoveCustomProperty.svg"));
  639. removeCustomPropertyButton.iconSize = new QSize(12,12);
  640. removeCustomPropertyButton.toolTip = qsTr("Remove this property from selected objects");
  641. var name = propertyTypeId.getCustomPropertyName();
  642. removeCustomPropertyButton.objectName = "DeleteCustomProperty" + name;
  643. //qDebug("adding button to remove custom property named: ", name);
  644. var propertyEditor = this;
  645. var pw = new PropertyWatcher(this, removeCustomPropertyButton, propertyTypeId);
  646. removeCustomPropertyButton.clicked.connect(pw, pw.propertyRemoved);
  647. gridLayoutCustom.addWidget(removeCustomPropertyButton, row,3);
  648. }
  649. firstEntry = false;
  650. }
  651. }
  652. }
  653. }
  654. }
  655. // enable / disable used / unused fixed controls
  656. var w;
  657. this.widget.findChild("LabelLayer").enabled = gotLayerProperty;
  658. w = this.widget.findChild("Layer");
  659. w.enabled = gotLayerProperty;
  660. if (!gotLayerProperty) {
  661. w.currentIndex = -1;
  662. }
  663. var gl = this.widget.findChild("General");
  664. if (!isNull(gl)) {
  665. var l = gl.layout();
  666. if (!isNull(l)) {
  667. var li = l.itemAtPosition(0, 2);
  668. if (!isNull(li)) {
  669. w = li.widget();
  670. if (!isNull(w)) {
  671. w.enabled = gotLayerProperty;
  672. }
  673. }
  674. }
  675. }
  676. this.widget.findChild("LabelLinetypeScale").enabled = gotLinetypeScaleProperty;
  677. w = this.widget.findChild("LinetypeScale");
  678. w.enabled = gotLinetypeScaleProperty;
  679. w.setTextColor(false);
  680. if (!gotLinetypeScaleProperty) {
  681. w.text = "";
  682. }
  683. this.widget.findChild("LabelDrawOrder").enabled = gotDrawOrderProperty;
  684. w = this.widget.findChild("DrawOrder");
  685. w.enabled = gotDrawOrderProperty;
  686. if (!gotDrawOrderProperty) {
  687. w.text = "";
  688. }
  689. // update selection combo box at the top for entity filters:
  690. //if (!onlyChanges) {
  691. var types = this.getTypes();
  692. var totalCount = 0;
  693. for (var ti=0; ti<types.length; ti++) {
  694. var type = types[ti];
  695. var typeCount = this.getTypeCount(type);
  696. totalCount += typeCount;
  697. //qDebug("type: ", type, " / count: ", typeCount);
  698. selectionCombo.addItem(entityTypeToString(type) + " [" + typeCount + "]", type);
  699. }
  700. if (types.length!==1) {
  701. // TODO: add at 0 if 'no selection' item present at 0:
  702. selectionCombo.insertItem(0, qsTr("All") + " (" + totalCount + ")", RS.EntityAll);
  703. }
  704. var index = selectionCombo.findData(this.getEntityTypeFilter());
  705. if (index===-1) {
  706. // TODO: change to 1 if 'no selection' item present at 0:
  707. selectionCombo.currentIndex = 0;
  708. }
  709. else {
  710. selectionCombo.currentIndex = index;
  711. }
  712. generalGroup.enabled = true;
  713. if (!isNull(this.geometryGroup)) {
  714. this.geometryGroup.enabled = true;
  715. }
  716. //}
  717. // add custom property button:
  718. if (!isNull(gridLayoutCustom)) {
  719. if (RSettings.isXDataEnabled() && RSettings.getBoolValue("PropertyEditor/AddCustomProperties", true)!==false) {
  720. var addCustomPropertyButton = new QToolButton(this.widget);
  721. addCustomPropertyButton.icon = new QIcon(autoPath(this.basePath + "/AddCustomProperty.svg"));
  722. addCustomPropertyButton.iconSize = new QSize(12,12);
  723. addCustomPropertyButton.toolTip = qsTr("Add custom property to selected objects");
  724. addCustomPropertyButton.objectName = "AddCustomProperty";
  725. addCustomPropertyButton.clicked.connect(this, this.addCustomProperty);
  726. gridLayoutCustom.addWidget(addCustomPropertyButton, gridLayoutCustom.rowCount(),3, 1,1);
  727. }
  728. }
  729. this.widget.updatesEnabled = true;
  730. };
  731. /**
  732. * Initializes a control for the given property.
  733. *
  734. * \param propertyTypeId The property the returned control edits.
  735. * \param onlyChanges Control already exists and only need to be re-initialized.
  736. * \param control The control to initialize if it is already known by the caller.
  737. *
  738. * \return The control(s) as array.
  739. */
  740. PropertyEditorImpl.prototype.initControls = function(propertyTypeId, onlyChanges, control) {
  741. var value = this.getAdjustedPropertyValue(propertyTypeId);
  742. var attributes = this.getPropertyAttributes(propertyTypeId);
  743. var controls;
  744. // used for custom properties only:
  745. // invisible flag of other properties is handled in RPropertyEditor:
  746. if (attributes.isInvisible()) {
  747. return undefined;
  748. }
  749. var objectName = PropertyEditorImpl.getControlObjectName(propertyTypeId);
  750. if (isNull(control) && onlyChanges) {
  751. // find existing control:
  752. control = this.widget.findChild(objectName);
  753. if (isNull(control)) {
  754. // no control available for this property (e.g. fit point of spline with control points):
  755. return undefined;
  756. }
  757. }
  758. // property available on request:
  759. // add button to request all properties:
  760. if (attributes.isOnRequest()) {
  761. var requestAllButton = new QToolButton(this.geometryGroup);
  762. requestAllButton.objectName = objectName + "_request";
  763. requestAllButton.text = qsTr("Show");
  764. requestAllButton.toolTip = qsTr("Show all properties");
  765. requestAllButton.clicked.connect(this, this.requestAllProperties);
  766. requestAllButton.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Preferred);
  767. return new Array(requestAllButton);
  768. }
  769. // Layer:
  770. // if (propertyTypeId.getId()===REntity.PropertyLayer.getId()) {
  771. // WidgetFactory.initLayerCombo(control, EAction.getDocument());
  772. // }
  773. // Horizontal alignment: combo box:
  774. //else
  775. if (propertyTypeId.getId()===RTextEntity.PropertyHAlign.getId()) {
  776. controls = this.initChoiceControls(
  777. objectName, propertyTypeId, onlyChanges, control, false, true);
  778. }
  779. // Vertical alignment: combo box:
  780. else if (propertyTypeId.getId()===RTextEntity.PropertyVAlign.getId()) {
  781. controls = this.initChoiceControls(
  782. objectName, propertyTypeId, onlyChanges, control, false, true);
  783. }
  784. // Polyline orientation: combo box:
  785. else if (propertyTypeId.getId()===RPolylineEntity.PropertyOrientation.getId()) {
  786. controls = this.initChoiceControls(
  787. objectName, propertyTypeId, onlyChanges, control, false, true);
  788. }
  789. // Arc dimension arc symbol type: combo box:
  790. else if (propertyTypeId.getId()===RDimArcLengthEntity.PropertyDimArcSymbolType.getId()) {
  791. controls = this.initChoiceControls(
  792. objectName, propertyTypeId, onlyChanges, control, false, true);
  793. }
  794. // DIMLUNIT: combo box with DIMLUNIT choices:
  795. else if (propertyTypeId.getId()===RDimensionEntity.PropertyDimlunit.getId() ||
  796. propertyTypeId.getId()===RDimensionEntity.PropertyDimtad.getId() ||
  797. //propertyTypeId.getId()===RDimensionEntity.PropertyDimdsep.getId() ||
  798. propertyTypeId.getId()===RDimensionEntity.PropertyDimzin.getId() ||
  799. propertyTypeId.getId()===RDimensionEntity.PropertyDimdec.getId() ||
  800. propertyTypeId.getId()===RDimensionEntity.PropertyDimaunit.getId() ||
  801. propertyTypeId.getId()===RDimensionEntity.PropertyDimazin.getId() ||
  802. propertyTypeId.getId()===RDimensionEntity.PropertyDimadec.getId()) {
  803. controls = this.initChoiceControls(
  804. objectName, propertyTypeId, onlyChanges, control, false, true);
  805. }
  806. else if (propertyTypeId.getId()===RDimensionEntity.PropertyDimdsep.getId()) {
  807. controls = this.initStringControls(objectName, propertyTypeId, onlyChanges, control);
  808. //controls[0].maxLength = 1;
  809. }
  810. // Hatch pattern: combo box with hatch names:
  811. else if (propertyTypeId.getId()===RHatchEntity.PropertyPatternName.getId()) {
  812. var patternNames = undefined;
  813. if (RUnit.isMetric(EAction.getDocument().getUnit())) {
  814. patternNames = RPatternListMetric.getNames();
  815. }
  816. else {
  817. patternNames = RPatternListImperial.getNames();
  818. }
  819. controls = this.initChoiceControls(
  820. objectName, propertyTypeId, onlyChanges, control,
  821. patternNames);
  822. }
  823. // Font: combo box with font names:
  824. else if (propertyTypeId.getId()===RTextEntity.PropertyFontName.getId()) {
  825. // var fontNames = undefined;
  826. // if (RUnit.isMetric(EAction.getDocument().getUnit())) {
  827. // patternNames = RPatternListMetric.getNames();
  828. // }
  829. // else {
  830. // patternNames = RPatternListImperial.getNames();
  831. // }
  832. controls = this.initChoiceControls(
  833. objectName, propertyTypeId, onlyChanges, control);
  834. }
  835. // List:
  836. else if (getTypeOf(value)==="array") {
  837. var indexControlObjectName = PropertyEditorImpl.getIndexControlObjectName(propertyTypeId.getPropertyGroupTitle());
  838. var indexControl = this.widget.findChild(indexControlObjectName);
  839. if (!isNull(indexControl)) {
  840. var index = indexControl.value;
  841. controls = this.initNumberControls(objectName, propertyTypeId, onlyChanges, control, index);
  842. if (!onlyChanges) {
  843. var a;
  844. if (isNull(indexControl['controlNames'])) {
  845. a = new Array(objectName);
  846. }
  847. else {
  848. a = indexControl['controlNames'];
  849. a.push(objectName);
  850. }
  851. indexControl.setProperty('controlNames', a);
  852. var iw = new IndexWatcher(this, indexControl, propertyTypeId)
  853. indexControl["valueChanged(int)"].connect(iw, iw.indexChanged);
  854. }
  855. else {
  856. // make sure that the values for the current list index are updated:
  857. indexControl.valueChanged(index);
  858. }
  859. }
  860. }
  861. // Number: math line edit:
  862. else if (!isComboBox(control) && typeof(value)==="number") {
  863. // TODO: handle int / double differently:
  864. controls = this.initNumberControls(objectName, propertyTypeId, onlyChanges, control);
  865. }
  866. // Boolean: combo box with Yes, No, *VARIES*:
  867. else if (typeof(value)==="boolean") {
  868. controls = this.initBooleanControls(objectName, propertyTypeId, onlyChanges, control);
  869. }
  870. // Choices: combo box:
  871. else if (attributes.hasChoices() || isComboBox(control)) {
  872. controls = this.initChoiceControls(objectName, propertyTypeId, onlyChanges, control);
  873. }
  874. // String: line edit:
  875. else if (typeof(value)==="string") {
  876. controls = this.initStringControls(objectName, propertyTypeId, onlyChanges, control);
  877. if (!onlyChanges) {
  878. if (attributes.isDimensionLabel()) {
  879. WidgetFactory.initLineEdit(controls[0], true);
  880. controls[0].placeholderText = qsTr("Auto");
  881. }
  882. else if (attributes.isLabel()) {
  883. if (!attributes.isReadOnly()) {
  884. WidgetFactory.initLineEdit(controls[0], false);
  885. }
  886. }
  887. }
  888. }
  889. if (isNull(controls) || controls.length===0) {
  890. return undefined;
  891. }
  892. control = controls[0];
  893. if (attributes.isReadOnly()) {
  894. this.makeReadOnly(control);
  895. }
  896. else {
  897. this.makeReadWrite(control);
  898. }
  899. return controls;
  900. };
  901. /**
  902. * Initializes a number control (RMathLineEdit) for the given property.
  903. * \internal
  904. */
  905. PropertyEditorImpl.prototype.initNumberControls = function(objectName, propertyTypeId, onlyChanges, control, index) {
  906. var document = EAction.getDocument();
  907. var value = this.getAdjustedPropertyValue(propertyTypeId);
  908. if (isNumber(index)) {
  909. value = value[index];
  910. }
  911. var attributes = this.getPropertyAttributes(propertyTypeId);
  912. if (isNull(control)) {
  913. if (attributes.isScaleType() && !isNull(document)) {
  914. control = new RMathComboBox(this.geometryGroup);
  915. control.setScale(true, document.getUnit());
  916. }
  917. else {
  918. control = new RMathLineEdit(this.geometryGroup);
  919. if (attributes.isAngleType()) {
  920. control.setAngle(true);
  921. }
  922. }
  923. control.objectName = objectName;
  924. }
  925. var newText = "";
  926. if (attributes.isMixed()) {
  927. newText = PropertyEditor.varies;
  928. }
  929. else {
  930. if (!isNull(value)) {
  931. if (attributes.isAngleType()) {
  932. value = RMath.rad2deg(value);
  933. }
  934. var decimals = RSettings.getIntValue("PropertyEditor/Decimals", 8);
  935. if (decimals<0) {
  936. decimals = 0;
  937. }
  938. if (decimals>8) {
  939. decimals = 8;
  940. }
  941. if (RSettings.getBoolValue("PropertyEditor/FormatAsDecimal", false)!==true &&
  942. !attributes.isAngleType() &&
  943. !attributes.isAreaType() &&
  944. !attributes.isUnitLess() &&
  945. !attributes.isPercentage() &&
  946. !attributes.isScaleType()
  947. /*&&
  948. (document.getLinearFormat()===RS.Fractional ||
  949. document.getLinearFormat()===RS.FractionalStacked)*/) {
  950. newText = RUnit.getLabel(value, document, decimals);
  951. if (document.getLinearFormat()===RS.Architectural ||
  952. document.getLinearFormat()===RS.ArchitecturalStacked ||
  953. document.getLinearFormat()===RS.Engineering) {
  954. // show 3'-4" as 3' 4" to avoid ambiguous expressions:
  955. newText = newText.replace("'-", "' ");
  956. }
  957. }
  958. else {
  959. newText = sprintf("%." + decimals + "f", value);
  960. }
  961. }
  962. }
  963. if (isOfType(control, RMathLineEdit) || isOfType(control, QLineEdit)) {
  964. if (control.text!==newText) {
  965. control.text = newText;
  966. control.setProperty("originalText", newText);
  967. if (isFunction(control.clearError)) {
  968. control.clearError();
  969. }
  970. }
  971. }
  972. if (isOfType(control, RMathComboBox)) {
  973. if (control.currentText!==newText) {
  974. // TODO: try to set scale value
  975. // (note that 1" = 2" is the same as 6" = 1', so the conversion from scale notation to value is irreversible)
  976. // if (!isNull(value)) {
  977. // control.setValue(value);
  978. // }
  979. // else {
  980. control.currentText = newText;
  981. // }
  982. control.setProperty("originalText", newText);
  983. if (isFunction(control.lineEdit().clearError)) {
  984. control.lineEdit().clearError();
  985. }
  986. }
  987. }
  988. if (attributes.isInteger()) {
  989. if (isOfType(control, RMathLineEdit)) {
  990. control.setInteger(true);
  991. }
  992. }
  993. if (!onlyChanges) {
  994. var lineEdit;
  995. if (isOfType(control, RMathComboBox)) {
  996. lineEdit = control.lineEdit();
  997. // don't trigger change on text changes (makes editing impossible):
  998. // control.editTextChanged.connect(
  999. // new PropertyWatcher(this, control, propertyTypeId),
  1000. // 'propertyChanged');
  1001. }
  1002. else {
  1003. lineEdit = control;
  1004. }
  1005. var pw = new PropertyWatcher(this, control, propertyTypeId);
  1006. lineEdit.editingFinished.connect(pw, pw.propertyChanged);
  1007. }
  1008. // move cursor to start if field is not being edited:
  1009. if (!control.focus) {
  1010. if (isOfType(control, RMathLineEdit)) {
  1011. control.cursorPosition = 0;
  1012. }
  1013. }
  1014. return new Array(control);
  1015. };
  1016. /**
  1017. * Initializes a string control (QLineEdit) for the given property.
  1018. * \internal
  1019. */
  1020. PropertyEditorImpl.prototype.initStringControls = function(objectName, propertyTypeId, onlyChanges, control) {
  1021. var value = this.getAdjustedPropertyValue(propertyTypeId);
  1022. var attributes = this.getPropertyAttributes(propertyTypeId);
  1023. //var editAsRichTextButton;
  1024. var clearButton = undefined;
  1025. if (isNull(control)) {
  1026. control = new QLineEdit(value, this.geometryGroup);
  1027. control.objectName = objectName;
  1028. /*if (attributes.isRichText()) {
  1029. editAsRichTextButton = new QToolButton(this.geometryGroup);
  1030. editAsRichTextButton.iconSize = new QSize(12,12);
  1031. var action = RGuiAction.getByScriptFile("scripts/Modify/EditText/EditText.js");
  1032. action.setProperty("");
  1033. editAsRichTextButton.setDefaultAction(action);
  1034. }*/
  1035. }
  1036. if (attributes.isMixed()) {
  1037. control.text = PropertyEditor.varies;
  1038. // TODO: make sure that the start of the text is shown:
  1039. //control.home(false);
  1040. }
  1041. else {
  1042. if (control.text!=value) {
  1043. control.text = value;
  1044. }
  1045. }
  1046. if (!onlyChanges && attributes.isDimensionLabel()) {
  1047. clearButton = new QToolButton(this.geometryGroup);
  1048. clearButton.objectName = objectName + "_clear";
  1049. clearButton.iconSize = new QSize(12,12);
  1050. clearButton.icon = new QIcon(autoPath(this.basePath + "/Clear.svg"));
  1051. clearButton.toolTip = qsTr("Use auto measurement");
  1052. clearButton.clicked.connect(function() {
  1053. control.text = "";
  1054. control.editingFinished();
  1055. });
  1056. }
  1057. if (!onlyChanges) {
  1058. var pw = new PropertyWatcher(this, control, propertyTypeId);
  1059. control.editingFinished.connect(pw, pw.propertyChanged);
  1060. }
  1061. // move cursor to start if field is not being edited:
  1062. if (!control.focus) {
  1063. control.cursorPosition = 0;
  1064. }
  1065. if (isNull(clearButton)) {
  1066. return new Array(control);
  1067. }
  1068. else {
  1069. return new Array(control, clearButton);
  1070. }
  1071. };
  1072. /**
  1073. * Initializes a boolean control (combo box with yes / no) for the given property.
  1074. * \internal
  1075. */
  1076. PropertyEditorImpl.prototype.initBooleanControls = function(objectName, propertyTypeId, onlyChanges, control) {
  1077. var value = this.getAdjustedPropertyValue(propertyTypeId);
  1078. var attributes = this.getPropertyAttributes(propertyTypeId);
  1079. if (isNull(control)) {
  1080. control = new QComboBox(this.geometryGroup);
  1081. control.objectName = objectName;
  1082. control.installEventFilter(new REventFilter(QEvent.Wheel.valueOf(), true));
  1083. control.focusPolicy = Qt.ClickFocus;
  1084. control.minimumWidth = 50;
  1085. control.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Preferred);
  1086. }
  1087. if (control.count<2) {
  1088. control.addItem(qsTr("Yes"), true);
  1089. control.addItem(qsTr("No"), false);
  1090. }
  1091. if (attributes.isMixed()) {
  1092. if (!onlyChanges) {
  1093. control.insertItem(0, PropertyEditor.varies, PropertyEditor.varies);
  1094. }
  1095. control.currentIndex = 0;
  1096. }
  1097. else {
  1098. // not varies anymore:
  1099. var variesIndex = control.findText(PropertyEditor.varies);
  1100. if (variesIndex!==-1) {
  1101. control.removeItem(variesIndex);
  1102. }
  1103. control.currentIndex = control.findData(value);
  1104. }
  1105. // read only:
  1106. if (attributes.isReadOnly()) {
  1107. control.enabled = false;
  1108. }
  1109. if (!onlyChanges) {
  1110. var pw = new PropertyWatcher(this, control, propertyTypeId);
  1111. control['activated(int)'].connect(pw, pw.propertyChanged);
  1112. }
  1113. return new Array(control);
  1114. };
  1115. /**
  1116. * Initializes a choice control (combo box) for the given property.
  1117. * \internal
  1118. */
  1119. PropertyEditorImpl.prototype.initChoiceControls = function(
  1120. objectName, propertyTypeId, onlyChanges, control, choices, choicesData) {
  1121. var i;
  1122. var value = this.getAdjustedPropertyValue(propertyTypeId);
  1123. var attributes = this.getPropertyAttributes(propertyTypeId);
  1124. if (isNull(control)) {
  1125. //if (propertyTypeId.getId()===RTextEntity.PropertyFontName.getId()) {
  1126. if (attributes.isStyle()) {
  1127. // control = new QComboBox(this.geometryGroup);
  1128. control = new QFontComboBox(this.geometryGroup);
  1129. //control.sizeAdjustPolicy = QComboBox.AdjustToContentsOnFirstShow;
  1130. control.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Preferred);
  1131. //control.maxWidth = 100;
  1132. control.editable = false;
  1133. control.installEventFilter(new REventFilter(QEvent.Wheel.valueOf(), true));
  1134. control.focusPolicy = Qt.ClickFocus;
  1135. initFontComboBox(control);
  1136. }
  1137. else {
  1138. control = new QComboBox(this.geometryGroup);
  1139. control.installEventFilter(new REventFilter(QEvent.Wheel.valueOf(), true));
  1140. control.focusPolicy = Qt.ClickFocus;
  1141. control.minimumWidth = 50;
  1142. control.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Preferred);
  1143. }
  1144. control.objectName = objectName;
  1145. if (isNull(choicesData)/* && propertyTypeId.getId()!==REntity.PropertyLayer.getId()*/) {
  1146. var pw = new PropertyWatcher(this, control, propertyTypeId)
  1147. if (RSettings.getQtVersion() >= 0x060000) {
  1148. control.textActivated.connect(pw, pw.propertyChanged);
  1149. }
  1150. else {
  1151. control['activated(QString)'].connect(pw, pw.propertyChanged);
  1152. }
  1153. }
  1154. else {
  1155. var pw = new PropertyWatcher(this, control, propertyTypeId);
  1156. if (RSettings.getQtVersion() >= 0x060000) {
  1157. control.activated.connect(pw, pw.propertyChanged);
  1158. }
  1159. else {
  1160. control['activated(int)'].connect(pw, pw.propertyChanged);
  1161. }
  1162. }
  1163. }
  1164. if (propertyTypeId.getId()===REntity.PropertyLayer.getId()) {
  1165. WidgetFactory.initLayerCombo(control, EAction.getDocument());
  1166. }
  1167. else if (propertyTypeId.getId()===RTextEntity.PropertyHAlign.getId()) {
  1168. WidgetFactory.initHAlignCombo(control);
  1169. }
  1170. else if (propertyTypeId.getId()===RTextEntity.PropertyVAlign.getId()) {
  1171. WidgetFactory.initVAlignCombo(control);
  1172. }
  1173. else if (propertyTypeId.getId()===RDimensionEntity.PropertyDimlunit.getId()) {
  1174. WidgetFactory.initDimlunitCombo(control);
  1175. }
  1176. else if (propertyTypeId.getId()===RDimensionEntity.PropertyDimtad.getId()) {
  1177. WidgetFactory.initDimtadCombo(control);
  1178. }
  1179. else if (propertyTypeId.getId()===RDimensionEntity.PropertyDimzin.getId()) {
  1180. WidgetFactory.initDimzinCombo(control);
  1181. }
  1182. else if (propertyTypeId.getId()===RDimensionEntity.PropertyDimdec.getId()) {
  1183. WidgetFactory.initDimdecCombo(control);
  1184. }
  1185. else if (propertyTypeId.getId()===RDimensionEntity.PropertyDimaunit.getId()) {
  1186. WidgetFactory.initDimaunitCombo(control);
  1187. }
  1188. else if (propertyTypeId.getId()===RDimensionEntity.PropertyDimazin.getId()) {
  1189. WidgetFactory.initDimazinCombo(control);
  1190. }
  1191. else if (propertyTypeId.getId()===RDimensionEntity.PropertyDimadec.getId()) {
  1192. WidgetFactory.initDimadecCombo(control);
  1193. }
  1194. else if (propertyTypeId.getId()===RPolylineEntity.PropertyOrientation.getId()) {
  1195. WidgetFactory.initOrientationCombo(control);
  1196. }
  1197. else if (propertyTypeId.getId()===RDimArcLengthEntity.PropertyDimArcSymbolType.getId()) {
  1198. WidgetFactory.initArcSymbolTypeCombo(control);
  1199. }
  1200. else if (isOfType(control, QComboBox) /*&& propertyTypeId.getId()!==REntity.PropertyLayer.getId()*/) {
  1201. control.clear();
  1202. if (isNull(choices)) {
  1203. if (attributes.isNumericallySorted()) {
  1204. var cs = attributes.getChoices();
  1205. cs.sort(function(a,b) { return parseInt(a) - parseInt(b) });
  1206. control.addItems(cs);
  1207. }
  1208. else {
  1209. control.addItems(attributes.getChoices());
  1210. control.model().sort(0);
  1211. }
  1212. }
  1213. else {
  1214. if (isNull(choicesData)) {
  1215. control.addItems(choices);
  1216. }
  1217. else {
  1218. for (i=0; i<choices.length && i<choicesData.length; ++i) {
  1219. control.addItem(choices[i], choicesData[i]);
  1220. }
  1221. }
  1222. }
  1223. }
  1224. // mixed:
  1225. var variesIndex = control.findText(PropertyEditor.varies);
  1226. if (attributes.isMixed()) {
  1227. if (variesIndex!==-1) {
  1228. control.currentIndex = variesIndex;
  1229. }
  1230. else {
  1231. control.insertItem(0, PropertyEditor.varies, PropertyEditor.varies);
  1232. control.currentIndex = 0;
  1233. }
  1234. return new Array(control);
  1235. }
  1236. // not mixed anymore, remove mixed option:
  1237. if (variesIndex!==-1) {
  1238. control.removeItem(variesIndex);
  1239. }
  1240. var index = -1;
  1241. if (typeof(value)==="string") {
  1242. index = control.findText(value);
  1243. if (index===-1) {
  1244. control.addItem(value);
  1245. index = control.findText(value);
  1246. }
  1247. }
  1248. else {
  1249. for (i=0; i<control.count; ++i) {
  1250. var data = control.itemData(i);
  1251. var match = false;
  1252. // for some types (e.g. RColor, RLinetype), we have to use equals here:
  1253. if (!isNull(data) && isFunction(data.equals)) {
  1254. if (data.equals(value)) {
  1255. match = true;
  1256. }
  1257. }
  1258. else {
  1259. if (data===value) {
  1260. match = true;
  1261. }
  1262. }
  1263. if (match) {
  1264. index = i;
  1265. break;
  1266. }
  1267. }
  1268. }
  1269. if (index===-1) {
  1270. // handle custom color:
  1271. if (isOfType(control, RColorCombo)) {
  1272. control.setColor(value);
  1273. }
  1274. else if (isOfType(control, QFontComboBox)) {
  1275. activateFont(control, value);
  1276. }
  1277. else if (isOfType(control, RLineweightCombo)) {
  1278. // custom lineweight: default to ByLayer:
  1279. control.currentIndex = 0;
  1280. }
  1281. else if (isOfType(control, RLinetypeCombo)) {
  1282. // custom linetype: default to ByLayer:
  1283. control.currentIndex = 0;
  1284. }
  1285. else {
  1286. // custom something, cannot handle this:
  1287. debugger;
  1288. }
  1289. }
  1290. else {
  1291. control.currentIndex = index;
  1292. }
  1293. return [ control ];
  1294. };
  1295. PropertyEditorImpl.getControlObjectName = function(propertyTypeId) {
  1296. if (propertyTypeId.isCustom()) {
  1297. return "Control" + propertyTypeId.getCustomPropertyName();
  1298. }
  1299. else {
  1300. return "Control" + propertyTypeId.getId();
  1301. }
  1302. };
  1303. PropertyEditorImpl.getIndexControlObjectName = function(group) {
  1304. return "IndexControl" + group.replace(" ", "_");
  1305. };
  1306. /**
  1307. * Called when user changes entity filter at the top of the property editor.
  1308. */
  1309. PropertyEditorImpl.prototype.filterChanged = function() {
  1310. var doc = EAction.getDocument();
  1311. if (isNull(doc)) {
  1312. return;
  1313. }
  1314. var selectionCombo = this.widget.findChild("Selection");
  1315. var entityTypeFilter = selectionCombo.itemData(selectionCombo.currentIndex);
  1316. if (isNull(entityTypeFilter)) {
  1317. entityTypeFilter = RS.EntityAll;
  1318. }
  1319. this.updateFromDocument(doc, false, entityTypeFilter, true);
  1320. };
  1321. /**
  1322. * Called when the user requests all properties to be shown.
  1323. */
  1324. PropertyEditorImpl.prototype.requestAllProperties = function() {
  1325. var doc = EAction.getDocument();
  1326. if (isNull(doc)) {
  1327. return;
  1328. }
  1329. var selectionCombo = this.widget.findChild("Selection");
  1330. var entityTypeFilter = selectionCombo.itemData(selectionCombo.currentIndex);
  1331. if (isNull(entityTypeFilter)) {
  1332. entityTypeFilter = RS.EntityAll;
  1333. }
  1334. this.updateFromDocument(doc, false, entityTypeFilter, true, true);
  1335. };
  1336. PropertyEditorImpl.prototype.getAdjustedPropertyValue = function(propertyTypeId) {
  1337. // show handle as hex representation (string):
  1338. if (propertyTypeId.getId()===RObject.PropertyHandle.getId()) {
  1339. var value = this.getPropertyValue(propertyTypeId);
  1340. if (value===RObject.INVALID_HANDLE) {
  1341. return "-";
  1342. }
  1343. return sprintf("0x%x", value);
  1344. }
  1345. return this.getPropertyValue(propertyTypeId);
  1346. };
  1347. /**
  1348. * Make given control read-only and more visibly so.
  1349. */
  1350. PropertyEditorImpl.prototype.makeReadOnly = function(control) {
  1351. if (isNull(control)) {
  1352. return;
  1353. }
  1354. RPropertyEditor.makeReadOnly(control, true);
  1355. /*
  1356. var p = control.palette;
  1357. if (isNull(control.property("oriPalette"))) {
  1358. control.setProperty("oriPalette", control.palette);
  1359. }
  1360. p.setColor(QPalette.Active, QPalette.Text, control.property("oriPalette").color(QPalette.Disabled, QPalette.WindowText));
  1361. p.setColor(QPalette.Inactive, QPalette.Text, control.property("oriPalette").color(QPalette.Disabled, QPalette.WindowText));
  1362. // if (RSettings.hasDarkGuiBackground()) {
  1363. // p.setColor(QPalette.Base, new QColor("#0a0a0a"));
  1364. // }
  1365. // else {
  1366. // p.setColor(QPalette.Base, new QColor("#eeeeee"));
  1367. // }
  1368. control.palette = p;
  1369. */
  1370. //control.readOnly = true;
  1371. // leave enabled to allow copy / page (20140411):
  1372. //control.enabled = false;
  1373. };
  1374. /**
  1375. * Make given control read-write again.
  1376. */
  1377. PropertyEditorImpl.prototype.makeReadWrite = function(control) {
  1378. if (isNull(control)) {
  1379. return;
  1380. }
  1381. RPropertyEditor.makeReadOnly(control, false);
  1382. // var p = control.palette;
  1383. // if (isNull(control.property("oriPalette"))) {
  1384. // control.setProperty("oriPalette", control.palette);
  1385. // }
  1386. // p.setColor(QPalette.Active, QPalette.Text, control.property("oriPalette").color(QPalette.Active, QPalette.WindowText));
  1387. // p.setColor(QPalette.Inactive, QPalette.Text, control.property("oriPalette").color(QPalette.Inactive, QPalette.WindowText));
  1388. //// //if (RSettings.hasDarkGuiBackground()) {
  1389. //// p.setColor(QPalette.Base, control.oriBase);
  1390. ////// }
  1391. ////// else {
  1392. ////// p.setColor(QPalette.Base, new QColor("#ffffff"));
  1393. ////// }
  1394. // control.palette = p;
  1395. //control.readOnly = false;
  1396. control.enabled = true;
  1397. };
  1398. PropertyEditorImpl.prototype.addCustomProperty = function() {
  1399. var dialog = WidgetFactory.createDialog(this.basePath, "AddCustomPropertyDialog.ui");
  1400. var buttonBox = dialog.findChild("ButtonBox");
  1401. buttonBox.button(QDialogButtonBox.Ok).enabled = false;
  1402. var nameEdit = dialog.findChild("Name");
  1403. var rx = new RegExp("[^<>\\\\\":;\?\*|,=`]{1,255}");
  1404. var validator = new QRegExpValidator(rx, nameEdit);
  1405. nameEdit.setValidator(validator);
  1406. nameEdit.textChanged.connect(
  1407. function(text) {
  1408. buttonBox.button(QDialogButtonBox.Ok).enabled = !text.isEmpty();
  1409. }
  1410. );
  1411. var valueEdit = dialog.findChild("Value");
  1412. if (!dialog.exec()) {
  1413. destr(dialog);
  1414. EAction.activateMainWindow();
  1415. return;
  1416. }
  1417. var name = nameEdit.text;
  1418. var value = valueEdit.text;
  1419. // trigger change property operation for custom property:
  1420. this.propertyChanged(new RPropertyTypeId(RSettings.getAppId(), name), value, this.getEntityTypeFilter());
  1421. this.onlyChangesOverride = false;
  1422. destr(dialog);
  1423. EAction.activateMainWindow();
  1424. };
  1425. function PropertyEditor(guiAction) {
  1426. EAction.call(this, guiAction);
  1427. }
  1428. PropertyEditor.prototype = new EAction();
  1429. PropertyEditor.varies = qsTr("*VARIES*");
  1430. PropertyEditor.getPreferencesCategory = function() {
  1431. return [ qsTr("Widgets"), qsTr("Property Editor") ];
  1432. };
  1433. PropertyEditor.applyPreferences = function(doc, mdiChild) {
  1434. var appWin = RMainWindowQt.getMainWindow();
  1435. appWin.notifyPropertyListeners(EAction.getDocument());
  1436. };
  1437. /**
  1438. * Shows / hides the property editor.
  1439. */
  1440. PropertyEditor.prototype.beginEvent = function() {
  1441. EAction.prototype.beginEvent.call(this);
  1442. var appWin = RMainWindowQt.getMainWindow();
  1443. var dock = appWin.findChild("PropertyEditorDock");
  1444. if (!RSettings.getOriginalArguments().contains("-no-show")) {
  1445. dock.visible = !dock.visible;
  1446. if (dock.visible) dock.raise();
  1447. }
  1448. var linetypeCombo = dock.findChild("Linetype");
  1449. linetypeCombo.init(EAction.getDocument());
  1450. appWin.notifyPropertyListeners(EAction.getDocument());
  1451. };
  1452. PropertyEditor.prototype.finishEvent = function() {
  1453. EAction.prototype.finishEvent.call(this);
  1454. var appWin = RMainWindowQt.getMainWindow();
  1455. var dock = appWin.findChild("PropertyEditorDock");
  1456. this.getGuiAction().setChecked(dock.visible);
  1457. };
  1458. /**
  1459. * Static function to get current entity filter (useful when triggering actions which change properties).
  1460. */
  1461. PropertyEditor.getEntityTypeFilter = function() {
  1462. var appWin = EAction.getMainWindow();
  1463. var widget = appWin.findChild("PropertyEditor");
  1464. var selectionCombo = widget.findChild("Selection");
  1465. return selectionCombo.itemData(selectionCombo.currentIndex);
  1466. };
  1467. /**
  1468. * Static function to get current layer displayed in the property editor.
  1469. */
  1470. PropertyEditor.getCurrentLayerName = function() {
  1471. var appWin = EAction.getMainWindow();
  1472. var widget = appWin.findChild("PropertyEditor");
  1473. var layerCombo = widget.findChild("Layer");
  1474. return layerCombo.itemText(layerCombo.currentIndex);
  1475. };
  1476. PropertyEditor.init = function(basePath) {
  1477. var appWin = EAction.getMainWindow();
  1478. var action = new RGuiAction(qsTr("Property Editor"), appWin);
  1479. action.setRequiresDocument(false);
  1480. action.setScriptFile(basePath + "/PropertyEditor.js");
  1481. action.setIcon(basePath + "/PropertyEditor.svg");
  1482. action.setDefaultShortcut(new QKeySequence("g,p"));
  1483. action.setDefaultCommands(["gp"]);
  1484. action.setGroupSortOrder(3700);
  1485. action.setSortOrder(100);
  1486. action.setWidgetNames(["ViewMenu", "WidgetsToolBar", "ViewToolsPanel", "WidgetsMatrixPanel"]);
  1487. var pe = new PropertyEditorImpl(basePath);
  1488. var dock = new RDockWidget(qsTr("Property Editor"), appWin);
  1489. dock.objectName = "PropertyEditorDock";
  1490. dock.setWidget(pe.widget);
  1491. appWin.addPropertyListener(pe);
  1492. if (RSettings.getQtVersion() >= 0x060000) {
  1493. appWin.addLayerListener(pe);
  1494. }
  1495. else {
  1496. appWin.addLayerListener(pe.getRLayerListener());
  1497. }
  1498. appWin.addDockWidget(Qt.RightDockWidgetArea, dock);
  1499. PropertyEditor.instance = pe;
  1500. dock.shown.connect(function() { action.setChecked(true); });
  1501. dock.hidden.connect(function() { action.setChecked(false); });
  1502. };