From 5532b34c587e19dad6025b62f30ce67518168e70 Mon Sep 17 00:00:00 2001 From: sunmondong Date: Tue, 23 May 2017 17:16:53 +0800 Subject: [PATCH 01/41] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E6=9E=84=E5=BB=BA?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- designer_form/build.9.0.gradle | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/designer_form/build.9.0.gradle b/designer_form/build.9.0.gradle index 5c14f78a49..1decff56b9 100644 --- a/designer_form/build.9.0.gradle +++ b/designer_form/build.9.0.gradle @@ -38,11 +38,20 @@ dependencies{ testCompile 'junit:junit:4.12' } //复制非.java文件到classes文件夹下参与打包 + +//指明无法编译文件所在路径 +def dataContent ={def dir -> + copySpec{ + from ("${dir}"){ + exclude '**/.setting/**','.classpath','.project','**/*.java','**/*.db','**/*.g','**/package.html' + } + } +} + task copyFile(type:Copy,dependsOn:compileJava){ copy{ - from ("${srcDir}/src"){ - exclude '**/.setting/**','.classpath','.project','**/*.java','**/*.db','**/*.g','**/package.html' - } + with dataContent.call("${srcDir}/src") + with dataContent.call("${srcDir}/../designer/src") into 'build/classes/main' } @@ -61,6 +70,10 @@ task compressJS{ include (name:'**/*.js') include (name:'**/*.css') } + fileset (dir:"${srcDir}/../designer/src"){ + include (name:'**/*.js') + include (name:'**/*.css') + } } } From d1494dc20b29311e840f4cacfdcf9795b125224d Mon Sep 17 00:00:00 2001 From: XiaXiang Date: Wed, 24 May 2017 15:08:24 +0800 Subject: [PATCH 02/41] bug fix --- .../mainframe/alphafine/images/alphafine0.png | Bin 369 -> 0 bytes .../mainframe/alphafine/images/alphafine1.png | Bin 372 -> 418 bytes .../mainframe/alphafine/images/alphafine2.png | Bin 248 -> 372 bytes .../mainframe/alphafine/images/alphafine3.png | Bin 418 -> 248 bytes .../mainframe/alphafine/images/alphafine4.png | Bin 237 -> 369 bytes .../mainframe/alphafine/images/alphafine5.png | Bin 0 -> 237 bytes .../manager/RecommendSearchManager.java | 54 ++++++++++-------- .../AlphaFine/AlphafineConfigManager.java | 14 ++--- .../help/AlphaFine/AlphafineConfigPane.java | 18 +++--- .../design/locale/designer_zh_CN.properties | 2 +- 10 files changed, 46 insertions(+), 42 deletions(-) delete mode 100644 designer/src/com/fr/design/mainframe/alphafine/images/alphafine0.png create mode 100644 designer/src/com/fr/design/mainframe/alphafine/images/alphafine5.png diff --git a/designer/src/com/fr/design/mainframe/alphafine/images/alphafine0.png b/designer/src/com/fr/design/mainframe/alphafine/images/alphafine0.png deleted file mode 100644 index e23a33ab542ea640bb96bbd86d609624a7fd87e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 369 zcmV-%0gnEOP)_OaZPf)Q->&My_7?6NkeSLuTq(Z= P00000NkvXXu0mjfh`61) diff --git a/designer/src/com/fr/design/mainframe/alphafine/images/alphafine1.png b/designer/src/com/fr/design/mainframe/alphafine/images/alphafine1.png index aae79cb065f47bb3a700dd4941308fc908ed2ba2..8d5464a6d2575cb7d45471e4fda5e9ef09f324d6 100644 GIT binary patch delta 370 zcmV-&0ge9j0-^(uIe%11L_t(I%cYaCQN%D1MW1iTbyUDz2QWCtR{`$eM6BdGz#VV_ zj#L5!BoIe0agVj;ENH)LxPf(wEI`P|F5!f9Qn^WNe_7)R=^&(2HpWHR|Q-F z&w%yL93v)+736hT0v|w75(}IuE+|O_7~s@9GfXQumo275y}%ln}LwhFxQ&NO))3ZPTJk%PiJ z)8}=tz=Q7Fg}^Pa_RchNGy(^mjVeSjYhkvF2uP(#*xxA-NgKI2>JefBtDfU}mE9-p zJx=Du#ssZ`-fPrfd^t=ws06kma|^WDIF3<;PWrCAGs8rMMt4gfs_~^lGKmH71Z=!B zhq<|*ifjx67fDUZuo-vMKZ9@Yb@|ED;8TBYFRC4a+?g+HMl&Ed+;sEdpcyR`JlK1=_Qc8?TDh16TPZtpi zFy?)fhHQ|Stjv5uk#o2 WJ$Fkeu_s^v0000Wyv5QRS&A}68)(}6v6Du51b=bkZ+mAHf} zf#8(iRd99%hFrnX0oQ?40ZtZ=jCIDhGYkUl&)c_ev(3)$ffxR715i7oJV3VD`N!|F$P+ZqP!!mDh>4@}s#ydxGc* zrawuLl7N!0E(or$JF~N6CkX%-@(Xy-7880245m_N@BGOMC$fhjhw2;Oe;m0000!|F$P+ZqP!!mDh>4@}s#ydxGc* zrawuLl7N!0E(or$JF~N6CkX%-@(Xy-7880245m_N@BGOMC$fhjhw2;Oe;m00007JAiwH=iN!Z^h5J?-kIqDH&0;`_mdX?QL z?LAKB#l{4!f^6Q@Uwk=CIH&}+B6AD0**K0-g--geyfec@g+_NvAgb}DLNbX3@C0nU zGl#jkpNp9rq#>D&GGYGPm#)A5!fu9xUw>hdNHa*^9=Mgg05;m+$*v<9;1i6+o{c+@ RquT%g002ovPDHLkV1kW1r_KNX diff --git a/designer/src/com/fr/design/mainframe/alphafine/images/alphafine4.png b/designer/src/com/fr/design/mainframe/alphafine/images/alphafine4.png index 064f0d8e8afba4e54ecfdbabf3e0cb0a278026da..e23a33ab542ea640bb96bbd86d609624a7fd87e4 100644 GIT binary patch delta 322 zcmV-I0loh10r3KmIDY{nNklZ%LHQhk$BVjkMY64(O` zpnwSUz`+|e=GY4YZDTEsuPny^wBD%WnLyh({q2e0#}{z8N3e%?`3d!qc*Z90H0#7J2$Lc<89RiC*Q8>!uA&K8<3gG ULtH7p1poj507*qoM6N<$g4ynuE&u=k delta 189 zcmV;u07C!q0__2iIDY`2Nkl2bgD$m-`GP!0}QBmfP8_06yknkClUGvoaiHOPi58O@M3708%^E z+>@L5Qa=gEKIYTb01GTY@-bgG_=72>{Pz#+0FpXRBV6>ZIW`8VXR2Wuwk}AYsKT}% rkY@Eh4b~fM)zgBcrx2R;2)6J5Z2(4Uity>Z00000NkvXXu0mjf$Z}Pg diff --git a/designer/src/com/fr/design/mainframe/alphafine/images/alphafine5.png b/designer/src/com/fr/design/mainframe/alphafine/images/alphafine5.png new file mode 100644 index 0000000000000000000000000000000000000000..064f0d8e8afba4e54ecfdbabf3e0cb0a278026da GIT binary patch literal 237 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GGLLkg|>2BR0px}H@ z7sn8b(`P3gFJnLPVPkUi%KyJwfL zF>vcRd@_tT|Iw_u^v`$xHw=@k{FGz9tg~cWnZ7DfYMY+N{1u0`$xlf8YR7v`I_K); jrX|Y-W_{(@_JJXn!7Z!n!^^!ur!siD`njxgN@xNAlSy2u literal 0 HcmV?d00001 diff --git a/designer/src/com/fr/design/mainframe/alphafine/search/manager/RecommendSearchManager.java b/designer/src/com/fr/design/mainframe/alphafine/search/manager/RecommendSearchManager.java index 9e23558556..44ce23ed32 100644 --- a/designer/src/com/fr/design/mainframe/alphafine/search/manager/RecommendSearchManager.java +++ b/designer/src/com/fr/design/mainframe/alphafine/search/manager/RecommendSearchManager.java @@ -1,5 +1,6 @@ package com.fr.design.mainframe.alphafine.search.manager; +import com.fr.design.DesignerEnvManager; import com.fr.design.mainframe.alphafine.cell.CellModelHelper; import com.fr.design.mainframe.alphafine.cell.model.AlphaCellModel; import com.fr.design.mainframe.alphafine.cell.model.MoreModel; @@ -19,7 +20,7 @@ public class RecommendSearchManager implements AlphaFineSearchProcessor { private static RecommendSearchManager recommendSearchManager = null; private SearchResult modelList; //todo:for test - private static final String SEARCHAPI = "http://localhost:8080/monitor/alphafine/search/recommend?searchKey="; + private static final String SEARCHAPI = "http://192.168.2.45:8080/monitor/alphafine/search/recommend?searchKey="; public synchronized static RecommendSearchManager getRecommendSearchManager() { if (recommendSearchManager == null) { @@ -29,35 +30,38 @@ public class RecommendSearchManager implements AlphaFineSearchProcessor { } @Override public synchronized SearchResult getLessSearchResult(String searchText) { - String result; - this.modelList = new SearchResult(); - HttpClient httpClient = new HttpClient(SEARCHAPI + CodeUtils.cjkEncode(searchText)); - httpClient.asGet(); - httpClient.setTimeout(5000); - if (!httpClient.isServerAlive()) { - return modelList; - } - result = httpClient.getResponseText(); - try { - JSONObject jsonObject = new JSONObject(result); - if (jsonObject.optString("status").equals("success")) { - JSONArray jsonArray = jsonObject.optJSONArray("result"); - if (jsonArray != null && jsonArray.length() > 0) { - for (int i = 0; i < jsonArray.length(); i++) { - AlphaCellModel alphaCellModel = CellModelHelper.getModelFromJson((JSONObject) jsonArray.get(i)); - if (!RecentSearchManager.getRecentSearchManger().getRecentModelList().contains(alphaCellModel)) { - this.modelList.add(alphaCellModel); + if (DesignerEnvManager.getEnvManager().getAlphafineConfigManager().isContainRecommend()) { + String result; + this.modelList = new SearchResult(); + HttpClient httpClient = new HttpClient(SEARCHAPI + CodeUtils.cjkEncode(searchText)); + httpClient.asGet(); + httpClient.setTimeout(5000); + if (!httpClient.isServerAlive()) { + return modelList; + } + result = httpClient.getResponseText(); + try { + JSONObject jsonObject = new JSONObject(result); + if (jsonObject.optString("status").equals("success")) { + JSONArray jsonArray = jsonObject.optJSONArray("result"); + if (jsonArray != null && jsonArray.length() > 0) { + for (int i = 0; i < jsonArray.length(); i++) { + AlphaCellModel alphaCellModel = CellModelHelper.getModelFromJson((JSONObject) jsonArray.get(i)); + if (!RecentSearchManager.getRecentSearchManger().getRecentModelList().contains(alphaCellModel)) { + this.modelList.add(alphaCellModel); + } } } } - } - } catch (JSONException e) { - FRLogger.getLogger().error(e.getMessage()); - } - if (modelList.size() > 0) { - modelList.add(0, new MoreModel(Inter.getLocText("FR-Designer_AlphaFine_Conclude"), false)); + } catch (JSONException e) { + FRLogger.getLogger().error("cloud server error! :" + e.getMessage()); + } + if (modelList.size() > 0) { + modelList.add(0, new MoreModel(Inter.getLocText("FR-Designer_AlphaFine_Conclude"), false)); + } } + return modelList; } diff --git a/designer_base/src/com/fr/design/actions/help/AlphaFine/AlphafineConfigManager.java b/designer_base/src/com/fr/design/actions/help/AlphaFine/AlphafineConfigManager.java index be1ff3386d..aa73d7afe9 100644 --- a/designer_base/src/com/fr/design/actions/help/AlphaFine/AlphafineConfigManager.java +++ b/designer_base/src/com/fr/design/actions/help/AlphaFine/AlphafineConfigManager.java @@ -35,7 +35,7 @@ public class AlphafineConfigManager implements XMLable { /** * 猜您需要 */ - private boolean isContainConclude; + private boolean isContainRecommend; /** * 设置 @@ -88,7 +88,7 @@ public class AlphafineConfigManager implements XMLable { this.setEnabled(reader.getAttrAsBoolean("isEnabled", true)); this.setContainPlugin(reader.getAttrAsBoolean("isContainDocument", true)); this.setContainDocument(reader.getAttrAsBoolean("isContainDocument", true)); - this.setContainConclude(reader.getAttrAsBoolean("isContainConclude", true)); + this.setContainRecommend(reader.getAttrAsBoolean("isContainRecommend", true)); this.setContainAction(reader.getAttrAsBoolean("isContainAction", true)); this.setContainTemplate(reader.getAttrAsBoolean("isContainTemplate", true)); this.setContainFileContent(reader.getAttrAsBoolean("isContainFileContent", false)); @@ -104,7 +104,7 @@ public class AlphafineConfigManager implements XMLable { writer.attr("isEnabled", this.isEnabled()) .attr("isSearchOnline", this.isSearchOnLine()) .attr("shortcuts", this.getShortcuts()) - .attr("isContainConclude", this.isContainConclude()) + .attr("isContainRecommend", this.isContainRecommend()) .attr("isContainAction", this.isContainAction()) .attr("isContainDocument", this.isContainDocument()) .attr("isContainTemplate", this.isContainTemplate()) @@ -176,12 +176,12 @@ public class AlphafineConfigManager implements XMLable { this.isContainPlugin = containPlugin; } - public boolean isContainConclude() { - return isContainConclude; + public boolean isContainRecommend() { + return isContainRecommend; } - public void setContainConclude(boolean containConclude) { - isContainConclude = containConclude; + public void setContainRecommend(boolean containConclude) { + isContainRecommend = containConclude; } public boolean isEnabled() { diff --git a/designer_base/src/com/fr/design/actions/help/AlphaFine/AlphafineConfigPane.java b/designer_base/src/com/fr/design/actions/help/AlphaFine/AlphafineConfigPane.java index 470d041969..5d4d75275c 100644 --- a/designer_base/src/com/fr/design/actions/help/AlphaFine/AlphafineConfigPane.java +++ b/designer_base/src/com/fr/design/actions/help/AlphaFine/AlphafineConfigPane.java @@ -53,7 +53,7 @@ public class AlphafineConfigPane extends BasicPane { private static final double COLUMN_GAP = 180; private static final double ROW_GAP = 25; private KeyStroke shortCutKeyStore = null; - private UICheckBox isEnabledCheckbox, isSearchOnlineCheckbox, isContainConcludeCheckbox, isContainActionCheckbox, isContainDocumentCheckbox, isContainTemplateCheckbox, isContainPluginCheckbox, isContainFileContentCheckbox; + private UICheckBox isEnabledCheckbox, isSearchOnlineCheckbox, isContainRecommendCheckbox, isContainActionCheckbox, isContainDocumentCheckbox, isContainTemplateCheckbox, isContainPluginCheckbox, isContainFileContentCheckbox; private UITextField shortcutsField; public AlphafineConfigPane() { @@ -73,7 +73,7 @@ public class AlphafineConfigPane extends BasicPane { private Component[][] initsearchRangeComponents() { Component[][] components = new Component[][]{ - new Component[]{isContainConcludeCheckbox, isContainActionCheckbox, isContainDocumentCheckbox}, + new Component[]{isContainRecommendCheckbox, isContainActionCheckbox, isContainDocumentCheckbox}, new Component[]{isContainTemplateCheckbox, isContainPluginCheckbox, isContainFileContentCheckbox} }; return components; @@ -85,7 +85,7 @@ public class AlphafineConfigPane extends BasicPane { double[] columnSize = {COLUMN_GAP, COLUMN_GAP, COLUMN_GAP}; JPanel northPane = FRGUIPaneFactory.createTitledBorderPane(Inter.getLocText("FR-Designer_AlphaFine_SearchRange")); - isContainConcludeCheckbox = new UICheckBox(Inter.getLocText("FR-Designer_AlphaFine_Conclude")); + isContainRecommendCheckbox = new UICheckBox(Inter.getLocText("FR-Designer_AlphaFine_Conclude")); isContainActionCheckbox = new UICheckBox(Inter.getLocText("FR-Designer_Set")); isContainPluginCheckbox = new UICheckBox(Inter.getLocText("FR-Designer-Plugin_Addon")); isContainDocumentCheckbox = new UICheckBox(Inter.getLocText("FR-Designer_COMMUNITY_HELP")); @@ -125,14 +125,14 @@ public class AlphafineConfigPane extends BasicPane { @Override public void actionPerformed(ActionEvent e) { if (!isSearchOnlineCheckbox.isSelected()) { - isContainConcludeCheckbox.setEnabled(false); + isContainRecommendCheckbox.setEnabled(false); isContainPluginCheckbox.setEnabled(false); isContainDocumentCheckbox.setEnabled(false); - isContainConcludeCheckbox.setSelected(false); + isContainRecommendCheckbox.setSelected(false); isContainPluginCheckbox.setSelected(false); isContainDocumentCheckbox.setSelected(false); } else { - isContainConcludeCheckbox.setEnabled(true); + isContainRecommendCheckbox.setEnabled(true); isContainPluginCheckbox.setEnabled(true); isContainDocumentCheckbox.setEnabled(true); } @@ -163,8 +163,8 @@ public class AlphafineConfigPane extends BasicPane { this.isContainDocumentCheckbox.setEnabled(alphafineConfigManager.isSearchOnLine()); this.isContainPluginCheckbox.setSelected(alphafineConfigManager.isContainPlugin() && alphafineConfigManager.isSearchOnLine()); this.isContainPluginCheckbox.setEnabled(alphafineConfigManager.isSearchOnLine()); - this.isContainConcludeCheckbox.setSelected(alphafineConfigManager.isContainConclude() && alphafineConfigManager.isSearchOnLine()); - this.isContainConcludeCheckbox.setEnabled(alphafineConfigManager.isSearchOnLine()); + this.isContainRecommendCheckbox.setSelected(alphafineConfigManager.isContainRecommend() && alphafineConfigManager.isSearchOnLine()); + this.isContainRecommendCheckbox.setEnabled(alphafineConfigManager.isSearchOnLine()); this.shortcutsField.setText(getDisplayShortCut(alphafineConfigManager.getShortcuts())); shortCutKeyStore = convert2KeyStroke(alphafineConfigManager.getShortcuts()); } @@ -175,7 +175,7 @@ public class AlphafineConfigPane extends BasicPane { alphafineConfigManager.setContainPlugin(this.isContainPluginCheckbox.isSelected()); alphafineConfigManager.setContainAction(this.isContainActionCheckbox.isSelected()); alphafineConfigManager.setContainDocument(this.isContainDocumentCheckbox.isSelected()); - alphafineConfigManager.setContainConclude(this.isContainConcludeCheckbox.isSelected()); + alphafineConfigManager.setContainRecommend(this.isContainRecommendCheckbox.isSelected()); alphafineConfigManager.setEnabled(this.isEnabledCheckbox.isSelected()); alphafineConfigManager.setSearchOnLine(this.isSearchOnlineCheckbox.isSelected()); alphafineConfigManager.setContainTemplate(this.isContainTemplateCheckbox.isSelected()); diff --git a/designer_base/src/com/fr/design/locale/designer_zh_CN.properties b/designer_base/src/com/fr/design/locale/designer_zh_CN.properties index 0da090b680..62caf9aebb 100644 --- a/designer_base/src/com/fr/design/locale/designer_zh_CN.properties +++ b/designer_base/src/com/fr/design/locale/designer_zh_CN.properties @@ -1999,6 +1999,6 @@ FR-Designer_Templates=\u6A21\u677F FR-Designer_Templates_Content=\u6A21\u677F\u5185\u5BB9 FR-Designer_AlphaFine_ShowAll=\u663E\u793A\u5168\u90E8 FR-Designer_AlphaFine_Conclude=\u731C\u60A8\u9700\u8981 -FR-Designer_AlphaFine_Latest=\u6700\u8FD1\u5E38\u7528 +FR-Designer_AlphaFine_Latest=\u672C\u5730\u5E38\u7528 FR-Designer_AlphaFine_ShowLess=\u6536\u8D77 FR-Designer_Alphafine=AlphaFine\u667A\u80FD\u641C\u7D22 \ No newline at end of file From 71f0274776959232abac787f21a8bbb9e94cb42a Mon Sep 17 00:00:00 2001 From: XiaXiang Date: Wed, 24 May 2017 16:58:36 +0800 Subject: [PATCH 03/41] bug fix --- .../alphafine/component/AlphaFineDialog.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/designer/src/com/fr/design/mainframe/alphafine/component/AlphaFineDialog.java b/designer/src/com/fr/design/mainframe/alphafine/component/AlphaFineDialog.java index 00e1744fc5..2c7519ac8f 100644 --- a/designer/src/com/fr/design/mainframe/alphafine/component/AlphaFineDialog.java +++ b/designer/src/com/fr/design/mainframe/alphafine/component/AlphaFineDialog.java @@ -248,11 +248,9 @@ public class AlphaFineDialog extends UIDialog { int selectedIndex = searchResultList.getSelectedIndex(); Object selectedValue = searchResultList.getSelectedValue(); if (e.getClickCount() == 2) { - final int i = searchResultList.locationToIndex(e.getPoint()); - searchResultList.setSelectedIndex(i); doNavigate(selectedIndex); if (selectedValue instanceof AlphaCellModel) { - saveHistory(searchText, (AlphaCellModel) selectedValue); + saveHistory((AlphaCellModel) selectedValue); } } else if (e.getClickCount() == 1) { if (selectedValue instanceof MoreModel && ((MoreModel) selectedValue).isNeedMore()) { @@ -277,7 +275,11 @@ public class AlphaFineDialog extends UIDialog { @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER) { + Object selectedValue = searchResultList.getSelectedValue(); doNavigate(searchResultList.getSelectedIndex()); + if (searchResultList.getSelectedValue() instanceof AlphaCellModel) { + saveHistory((AlphaCellModel) selectedValue); + } } } }); @@ -556,10 +558,10 @@ public class AlphaFineDialog extends UIDialog { /** * 保存本地(本地常用) - * @param searchText * @param cellModel */ - private void saveHistory(String searchText, AlphaCellModel cellModel) { + private void saveHistory(AlphaCellModel cellModel) { + String searchText = searchTextField.getText(); RecentSearchManager recentSearchManager = RecentSearchManager.getRecentSearchManger(); recentSearchManager.addRecentModel(searchText, cellModel); recentSearchManager.saveXMLFile(); From 0ed921bfd04c6969f13145faa8f79df661cb6f4b Mon Sep 17 00:00:00 2001 From: XiaXiang Date: Wed, 24 May 2017 17:12:23 +0800 Subject: [PATCH 04/41] bug fix --- .../alphafine/search/manager/RecommendSearchManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/designer/src/com/fr/design/mainframe/alphafine/search/manager/RecommendSearchManager.java b/designer/src/com/fr/design/mainframe/alphafine/search/manager/RecommendSearchManager.java index 44ce23ed32..b2707e5020 100644 --- a/designer/src/com/fr/design/mainframe/alphafine/search/manager/RecommendSearchManager.java +++ b/designer/src/com/fr/design/mainframe/alphafine/search/manager/RecommendSearchManager.java @@ -20,7 +20,7 @@ public class RecommendSearchManager implements AlphaFineSearchProcessor { private static RecommendSearchManager recommendSearchManager = null; private SearchResult modelList; //todo:for test - private static final String SEARCHAPI = "http://192.168.2.45:8080/monitor/alphafine/search/recommend?searchKey="; + private static final String SEARCHAPI = "http://localhost:8080/monitor/alphafine/search/recommend?searchKey="; public synchronized static RecommendSearchManager getRecommendSearchManager() { if (recommendSearchManager == null) { @@ -55,7 +55,7 @@ public class RecommendSearchManager implements AlphaFineSearchProcessor { } } catch (JSONException e) { - FRLogger.getLogger().error("cloud server error! :" + e.getMessage()); + FRLogger.getLogger().error("data transform error! :" + e.getMessage()); } if (modelList.size() > 0) { modelList.add(0, new MoreModel(Inter.getLocText("FR-Designer_AlphaFine_Conclude"), false)); From 9eba157623f2af396420280cbe7491fd2aed14db Mon Sep 17 00:00:00 2001 From: XiaXiang Date: Wed, 24 May 2017 18:47:11 +0800 Subject: [PATCH 05/41] bug fix --- .../alphafine/cell/model/ActionModel.java | 8 ++++- .../search/manager/ActionSearchManager.java | 8 +++-- .../mainframe/toolbar/ToolBarMenuDock.java | 24 +++++++++----- .../toolbar/UpdateActionManager.java | 8 ++--- .../mainframe/toolbar/UpdateActionModel.java | 32 +++++++++++++++++++ 5 files changed, 63 insertions(+), 17 deletions(-) create mode 100644 designer_base/src/com/fr/design/mainframe/toolbar/UpdateActionModel.java diff --git a/designer/src/com/fr/design/mainframe/alphafine/cell/model/ActionModel.java b/designer/src/com/fr/design/mainframe/alphafine/cell/model/ActionModel.java index f0f0e32f67..493c5ad103 100644 --- a/designer/src/com/fr/design/mainframe/alphafine/cell/model/ActionModel.java +++ b/designer/src/com/fr/design/mainframe/alphafine/cell/model/ActionModel.java @@ -11,7 +11,7 @@ import java.io.Serializable; /** * Created by XiaXiang on 2017/4/20. */ -public class ActionModel extends AlphaCellModel implements Serializable { +public class ActionModel extends AlphaCellModel { private Action action; private String actionName; @@ -38,6 +38,12 @@ public class ActionModel extends AlphaCellModel implements Serializable { return action != null ? action.hashCode() : 0; } + public ActionModel(String name, String description, Action action) { + super(name, null, CellType.ACTION); + this.action = action; + this.setDescription(description); + } + public ActionModel(String name, Action action) { super(name, null, CellType.ACTION); this.action = action; diff --git a/designer/src/com/fr/design/mainframe/alphafine/search/manager/ActionSearchManager.java b/designer/src/com/fr/design/mainframe/alphafine/search/manager/ActionSearchManager.java index 0200cdb241..12417f4d6b 100644 --- a/designer/src/com/fr/design/mainframe/alphafine/search/manager/ActionSearchManager.java +++ b/designer/src/com/fr/design/mainframe/alphafine/search/manager/ActionSearchManager.java @@ -8,6 +8,7 @@ import com.fr.design.mainframe.alphafine.cell.model.MoreModel; import com.fr.design.mainframe.alphafine.cell.model.ActionModel; import com.fr.design.mainframe.alphafine.model.SearchResult; import com.fr.design.mainframe.toolbar.UpdateActionManager; +import com.fr.design.mainframe.toolbar.UpdateActionModel; import com.fr.general.FRLogger; import com.fr.general.Inter; @@ -35,10 +36,11 @@ public class ActionSearchManager implements AlphaFineSearchProcessor { lessModelList = new SearchResult(); moreModelList = new SearchResult(); if (DesignerEnvManager.getEnvManager().getAlphafineConfigManager().isContainAction()) { - List updateActions = UpdateActionManager.getUpdateActionManager().getUpdateActions(); - for (UpdateAction updateAction : updateActions) { + List updateActions = UpdateActionManager.getUpdateActionManager().getUpdateActions(); + for (UpdateActionModel updateActionModel : updateActions) { + UpdateAction updateAction = updateActionModel.getAction(); if (updateAction.getName() != null && updateAction.getName().toLowerCase().contains(searchText.toLowerCase())) { - filterModelList.add(new ActionModel(updateAction.getName() ,updateAction)); + filterModelList.add(new ActionModel(updateAction.getName() ,updateActionModel.getParentName(), updateAction)); } } if (filterModelList != null && filterModelList.size() >0) { diff --git a/designer_base/src/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java b/designer_base/src/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java index 536f984ebf..ff49aa7b07 100644 --- a/designer_base/src/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java +++ b/designer_base/src/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java @@ -55,8 +55,7 @@ public abstract class ToolBarMenuDock { public static final int PANLE_HEIGNT = 26; private MenuDef[] menus; private ToolBarDef toolBarDef; - private ArrayList shortCuts; - + private List shortCutsList; /** * 更新菜单 */ @@ -145,27 +144,36 @@ public abstract class ToolBarMenuDock { addCommunityMenuDef(menuList); // 添加全部UpdateAction到actionmanager中 - getAllUpdateActions(menuList); - UpdateActionManager.getUpdateActionManager().setUpdateActions(shortCuts); + addAllUpdateActionsToList(menuList); + UpdateActionManager.getUpdateActionManager().setUpdateActions(shortCutsList); return menuList.toArray(new MenuDef[menuList.size()]); } - private List getAllUpdateActions(List menuList) { - shortCuts = new ArrayList<>(); + /** + * 获取所有actionmodel + * @param menuList + */ + private void addAllUpdateActionsToList(List menuList) { + shortCutsList = new ArrayList<>(); for (MenuDef menuDef : menuList) { addUpdateActionToList(menuDef); } - return shortCuts; } + /** + * 递归获取所有UpdateAction + * @param menuDef + */ private void addUpdateActionToList(MenuDef menuDef) { + + String ParentName = menuDef.getName(); if (menuDef instanceof OpenRecentReportMenuDef) { return; } for (ShortCut shortCut : menuDef.getShortcutList()) { if (shortCut instanceof UpdateAction) { - shortCuts.add((UpdateAction) shortCut); + shortCutsList.add(new UpdateActionModel(ParentName, (UpdateAction) shortCut)); } else if (shortCut instanceof MenuDef) { addUpdateActionToList((MenuDef) shortCut); } diff --git a/designer_base/src/com/fr/design/mainframe/toolbar/UpdateActionManager.java b/designer_base/src/com/fr/design/mainframe/toolbar/UpdateActionManager.java index 05cad8d984..47ae6101fa 100644 --- a/designer_base/src/com/fr/design/mainframe/toolbar/UpdateActionManager.java +++ b/designer_base/src/com/fr/design/mainframe/toolbar/UpdateActionManager.java @@ -1,7 +1,5 @@ package com.fr.design.mainframe.toolbar; -import com.fr.design.actions.UpdateAction; - import java.util.List; /** @@ -9,7 +7,7 @@ import java.util.List; */ public class UpdateActionManager { private static UpdateActionManager updateActionManager = null; - private List updateActions; + private List updateActions; public synchronized static UpdateActionManager getUpdateActionManager() { if (updateActionManager == null) { @@ -18,11 +16,11 @@ public class UpdateActionManager { return updateActionManager; } - public List getUpdateActions() { + public List getUpdateActions() { return updateActions; } - public void setUpdateActions(List updateActions) { + public void setUpdateActions(List updateActions) { this.updateActions = updateActions; } } diff --git a/designer_base/src/com/fr/design/mainframe/toolbar/UpdateActionModel.java b/designer_base/src/com/fr/design/mainframe/toolbar/UpdateActionModel.java new file mode 100644 index 0000000000..b142776184 --- /dev/null +++ b/designer_base/src/com/fr/design/mainframe/toolbar/UpdateActionModel.java @@ -0,0 +1,32 @@ +package com.fr.design.mainframe.toolbar; + +import com.fr.design.actions.UpdateAction; + +/** + * Created by XiaXiang on 2017/5/24. + */ +public class UpdateActionModel { + private String parentName; + private UpdateAction action; + + public UpdateActionModel(String parentName, UpdateAction action) { + this.parentName = parentName; + this.action = action; + } + + public String getParentName() { + return parentName; + } + + public void setParentName(String parentName) { + this.parentName = parentName; + } + + public UpdateAction getAction() { + return action; + } + + public void setAction(UpdateAction action) { + this.action = action; + } +} From 3ed13a85afe5584fb31704a085ca4062a641fa62 Mon Sep 17 00:00:00 2001 From: XiaXiang Date: Wed, 24 May 2017 19:24:55 +0800 Subject: [PATCH 06/41] bug fix --- .../alphafine/search/manager/ActionSearchManager.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/designer/src/com/fr/design/mainframe/alphafine/search/manager/ActionSearchManager.java b/designer/src/com/fr/design/mainframe/alphafine/search/manager/ActionSearchManager.java index 12417f4d6b..6c35624f22 100644 --- a/designer/src/com/fr/design/mainframe/alphafine/search/manager/ActionSearchManager.java +++ b/designer/src/com/fr/design/mainframe/alphafine/search/manager/ActionSearchManager.java @@ -39,8 +39,10 @@ public class ActionSearchManager implements AlphaFineSearchProcessor { List updateActions = UpdateActionManager.getUpdateActionManager().getUpdateActions(); for (UpdateActionModel updateActionModel : updateActions) { UpdateAction updateAction = updateActionModel.getAction(); - if (updateAction.getName() != null && updateAction.getName().toLowerCase().contains(searchText.toLowerCase())) { - filterModelList.add(new ActionModel(updateAction.getName() ,updateActionModel.getParentName(), updateAction)); + if (updateAction.getName() != null) { + if (updateAction.getName().toLowerCase().contains(searchText.toLowerCase()) || updateActionModel.getParentName().toLowerCase().contains(searchText.toLowerCase())) { + filterModelList.add(new ActionModel(updateAction.getName(), updateActionModel.getParentName(), updateAction)); + } } } if (filterModelList != null && filterModelList.size() >0) { From d91c0002e2c7b44f8556737e754495be1b3a8927 Mon Sep 17 00:00:00 2001 From: XiaXiang Date: Wed, 24 May 2017 19:31:38 +0800 Subject: [PATCH 07/41] bug fix --- .../mainframe/alphafine/search/manager/ActionSearchManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/designer/src/com/fr/design/mainframe/alphafine/search/manager/ActionSearchManager.java b/designer/src/com/fr/design/mainframe/alphafine/search/manager/ActionSearchManager.java index 6c35624f22..902ab430fe 100644 --- a/designer/src/com/fr/design/mainframe/alphafine/search/manager/ActionSearchManager.java +++ b/designer/src/com/fr/design/mainframe/alphafine/search/manager/ActionSearchManager.java @@ -45,7 +45,7 @@ public class ActionSearchManager implements AlphaFineSearchProcessor { } } } - if (filterModelList != null && filterModelList.size() >0) { + if (filterModelList != null && filterModelList.size() > 0) { final int length = Math.min(AlphaFineConstants.SHOW_SIZE, filterModelList.size()); for (int i = 0; i < length; i++) { lessModelList.add(filterModelList.get(i)); From fae529f30b079fae11ffd90d5481baa674dc2325 Mon Sep 17 00:00:00 2001 From: XiaXiang Date: Wed, 24 May 2017 19:40:27 +0800 Subject: [PATCH 08/41] bug fix --- .../alphafine/search/manager/ActionSearchManager.java | 7 +++---- .../fr/design/mainframe/toolbar/UpdateActionModel.java | 10 ++++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/designer/src/com/fr/design/mainframe/alphafine/search/manager/ActionSearchManager.java b/designer/src/com/fr/design/mainframe/alphafine/search/manager/ActionSearchManager.java index 902ab430fe..32b71eeb33 100644 --- a/designer/src/com/fr/design/mainframe/alphafine/search/manager/ActionSearchManager.java +++ b/designer/src/com/fr/design/mainframe/alphafine/search/manager/ActionSearchManager.java @@ -38,10 +38,9 @@ public class ActionSearchManager implements AlphaFineSearchProcessor { if (DesignerEnvManager.getEnvManager().getAlphafineConfigManager().isContainAction()) { List updateActions = UpdateActionManager.getUpdateActionManager().getUpdateActions(); for (UpdateActionModel updateActionModel : updateActions) { - UpdateAction updateAction = updateActionModel.getAction(); - if (updateAction.getName() != null) { - if (updateAction.getName().toLowerCase().contains(searchText.toLowerCase()) || updateActionModel.getParentName().toLowerCase().contains(searchText.toLowerCase())) { - filterModelList.add(new ActionModel(updateAction.getName(), updateActionModel.getParentName(), updateAction)); + if (updateActionModel.getActionName() != null) { + if (updateActionModel.getActionName().toLowerCase().contains(searchText.toLowerCase()) || updateActionModel.getParentName().toLowerCase().contains(searchText.toLowerCase())) { + filterModelList.add(new ActionModel(updateActionModel.getActionName(), updateActionModel.getParentName(), updateActionModel.getAction())); } } } diff --git a/designer_base/src/com/fr/design/mainframe/toolbar/UpdateActionModel.java b/designer_base/src/com/fr/design/mainframe/toolbar/UpdateActionModel.java index b142776184..8bfda2310e 100644 --- a/designer_base/src/com/fr/design/mainframe/toolbar/UpdateActionModel.java +++ b/designer_base/src/com/fr/design/mainframe/toolbar/UpdateActionModel.java @@ -7,11 +7,13 @@ import com.fr.design.actions.UpdateAction; */ public class UpdateActionModel { private String parentName; + private String actionName; private UpdateAction action; public UpdateActionModel(String parentName, UpdateAction action) { this.parentName = parentName; this.action = action; + this.actionName = action.getName(); } public String getParentName() { @@ -29,4 +31,12 @@ public class UpdateActionModel { public void setAction(UpdateAction action) { this.action = action; } + + public String getActionName() { + return actionName; + } + + public void setActionName(String actionName) { + this.actionName = actionName; + } } From 64578ebf2cd9c9b0baee2d9332bcc5b6fb41a1b9 Mon Sep 17 00:00:00 2001 From: XiaXiang Date: Wed, 24 May 2017 19:42:56 +0800 Subject: [PATCH 09/41] bug fix --- .../mainframe/toolbar/UpdateActionModel.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/designer_base/src/com/fr/design/mainframe/toolbar/UpdateActionModel.java b/designer_base/src/com/fr/design/mainframe/toolbar/UpdateActionModel.java index 8bfda2310e..ad3db0348d 100644 --- a/designer_base/src/com/fr/design/mainframe/toolbar/UpdateActionModel.java +++ b/designer_base/src/com/fr/design/mainframe/toolbar/UpdateActionModel.java @@ -5,6 +5,10 @@ import com.fr.design.actions.UpdateAction; /** * Created by XiaXiang on 2017/5/24. */ + +/** + * action对象 + */ public class UpdateActionModel { private String parentName; private String actionName; @@ -16,6 +20,10 @@ public class UpdateActionModel { this.actionName = action.getName(); } + /** + * 获取上一层级菜单name + * @return + */ public String getParentName() { return parentName; } @@ -24,6 +32,10 @@ public class UpdateActionModel { this.parentName = parentName; } + /** + * 获取action + * @return + */ public UpdateAction getAction() { return action; } @@ -32,6 +44,10 @@ public class UpdateActionModel { this.action = action; } + /** + * 获取actionName + * @return + */ public String getActionName() { return actionName; } From b23769e1112b97efcd75deb069ba7120e8be7501 Mon Sep 17 00:00:00 2001 From: XiaXiang Date: Thu, 25 May 2017 15:17:27 +0800 Subject: [PATCH 10/41] =?UTF-8?q?bug=20fix=20AOP=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E6=8F=90=E9=86=92=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../designer/TemplateProcessTracker.aj | 8 +++---- .../manager/RecommendSearchManager.java | 2 +- .../aspectj/designerbase/AlphaFineReminder.aj | 23 +++++++++++++++++++ .../designerbase/TemplateProcessTracker.aj | 11 +++++---- .../designerchart/TemplateProcessTracker.aj | 6 ++--- .../designerform/TemplateProcessTracker.aj | 6 ++--- 6 files changed, 41 insertions(+), 15 deletions(-) create mode 100644 designer_base/src/com/fr/aspectj/designerbase/AlphaFineReminder.aj diff --git a/designer/src/com/fr/aspectj/designer/TemplateProcessTracker.aj b/designer/src/com/fr/aspectj/designer/TemplateProcessTracker.aj index 032cd23424..d0f3108295 100644 --- a/designer/src/com/fr/aspectj/designer/TemplateProcessTracker.aj +++ b/designer/src/com/fr/aspectj/designer/TemplateProcessTracker.aj @@ -35,7 +35,7 @@ public aspect TemplateProcessTracker { // String log = String.format("%s:\n%s\n%s\n%s\n\n", new Date(), sl, e, e.getSource()); String log = ""; - TemplateInfoCollector.appendProcess(log); + //TemplateInfoCollector.appendProcess(log); } //同上 before(ActionEvent e) : onActionPerformed(e) { @@ -47,7 +47,7 @@ public aspect TemplateProcessTracker { //String log = String.format("%s:\n%s\n%s\n%s\n\n", new Date(), sl, e, e.getSource()); String log = ""; - TemplateInfoCollector.appendProcess(log); + //TemplateInfoCollector.appendProcess(log); } //同上 @@ -56,7 +56,7 @@ public aspect TemplateProcessTracker { //String log = String.format("%s:\n%s\nset value: %s at (%d, %d)\n\n", new Date(), sl, v, r, c); String log = ""; - TemplateInfoCollector.appendProcess(log); + //TemplateInfoCollector.appendProcess(log); } //同上 @@ -66,7 +66,7 @@ public aspect TemplateProcessTracker { // String v = "test"; //String log = String.format("%s:\n%s\nset value: %s at %s\n\n", new Date(), sl, v, g.getEditingCellElement()); String log = ""; - TemplateInfoCollector.appendProcess(log); + //TemplateInfoCollector.appendProcess(log); } diff --git a/designer/src/com/fr/design/mainframe/alphafine/search/manager/RecommendSearchManager.java b/designer/src/com/fr/design/mainframe/alphafine/search/manager/RecommendSearchManager.java index b2707e5020..d1213822ba 100644 --- a/designer/src/com/fr/design/mainframe/alphafine/search/manager/RecommendSearchManager.java +++ b/designer/src/com/fr/design/mainframe/alphafine/search/manager/RecommendSearchManager.java @@ -30,9 +30,9 @@ public class RecommendSearchManager implements AlphaFineSearchProcessor { } @Override public synchronized SearchResult getLessSearchResult(String searchText) { + this.modelList = new SearchResult(); if (DesignerEnvManager.getEnvManager().getAlphafineConfigManager().isContainRecommend()) { String result; - this.modelList = new SearchResult(); HttpClient httpClient = new HttpClient(SEARCHAPI + CodeUtils.cjkEncode(searchText)); httpClient.asGet(); httpClient.setTimeout(5000); diff --git a/designer_base/src/com/fr/aspectj/designerbase/AlphaFineReminder.aj b/designer_base/src/com/fr/aspectj/designerbase/AlphaFineReminder.aj new file mode 100644 index 0000000000..a42e339aca --- /dev/null +++ b/designer_base/src/com/fr/aspectj/designerbase/AlphaFineReminder.aj @@ -0,0 +1,23 @@ +package com.fr.aspectj.designerbase; + +import java.awt.event.ActionEvent; + +/** + * Created by XiaXiang on 2017/5/25. + */ +public aspect AlphaFineReminder { + pointcut onActionPerformed(ActionEvent e) : + execution(* actionPerformed(ActionEvent)) && args(e); + + before(ActionEvent e) : onActionPerformed(e) { + String point = thisJoinPoint.toString(); + if (e != null && e.getSource().toString().contains("javax.swing.Timer")) { + return; + } + if (e != null && e.getSource().getClass().getName().equals("com.fr.design.gui.imenu.UIMenuItem") && point.contains("com.fr.design.actions")) { + System.out.print("在点击菜单\n" + thisJoinPoint); + } + + + } +} diff --git a/designer_base/src/com/fr/aspectj/designerbase/TemplateProcessTracker.aj b/designer_base/src/com/fr/aspectj/designerbase/TemplateProcessTracker.aj index 61a0be5008..b3f05a2c67 100644 --- a/designer_base/src/com/fr/aspectj/designerbase/TemplateProcessTracker.aj +++ b/designer_base/src/com/fr/aspectj/designerbase/TemplateProcessTracker.aj @@ -32,19 +32,22 @@ public aspect TemplateProcessTracker { //String log = String.format("%s:\n%s\n%s\n%s\n\n", new Date(), sl, e, e.getSource()); String log = ""; - TemplateInfoCollector.appendProcess(log); + //TemplateInfoCollector.appendProcess(log); } //同上 before(ActionEvent e) : onActionPerformed(e) { SourceLocation sl = thisJoinPoint.getSourceLocation(); // !within(LogHandlerBar) 没用, 手动过滤 - if (e.getSource().toString().contains("javax.swing.Timer")) { + if (e != null && e.getSource().toString().contains("javax.swing.Timer")) { return; } + if (e != null && e.getSource().getClass().getName().equals("com.fr.design.gui.imenu.UIMenuItem")) { + System.out.print("在点击菜单\n" + thisJoinPointStaticPart.getSourceLocation() + thisJoinPoint); + } //String log = String.format("%s:\n%s\n%s\n%s\n\n", new Date(), sl, e, e.getSource()); String log = ""; - TemplateInfoCollector.appendProcess(log); + //TemplateInfoCollector.appendProcess(log); } //同上 @@ -53,7 +56,7 @@ public aspect TemplateProcessTracker { //String log = String.format("%s:\n%s\nset value: %s at (%d, %d)\n\n", new Date(), sl, v, r, c); String log = ""; - TemplateInfoCollector.appendProcess(log); + // TemplateInfoCollector.appendProcess(log); } diff --git a/designer_chart/src/com/fr/aspectj/designerchart/TemplateProcessTracker.aj b/designer_chart/src/com/fr/aspectj/designerchart/TemplateProcessTracker.aj index 51e86fd151..60038d4a39 100644 --- a/designer_chart/src/com/fr/aspectj/designerchart/TemplateProcessTracker.aj +++ b/designer_chart/src/com/fr/aspectj/designerchart/TemplateProcessTracker.aj @@ -32,7 +32,7 @@ public aspect TemplateProcessTracker { //String log = String.format("%s:\n%s\n%s\n%s\n\n", new Date(), sl, e, e.getSource()); String log = ""; - TemplateInfoCollector.appendProcess(log); + //TemplateInfoCollector.appendProcess(log); } //同上 before(ActionEvent e) : onActionPerformed(e) { @@ -44,7 +44,7 @@ public aspect TemplateProcessTracker { //String log = String.format("%s:\n%s\n%s\n%s\n\n", new Date(), sl, e, e.getSource()); String log = ""; - TemplateInfoCollector.appendProcess(log); + //TemplateInfoCollector.appendProcess(log); } //同上 @@ -52,7 +52,7 @@ public aspect TemplateProcessTracker { SourceLocation sl = thisJoinPoint.getSourceLocation(); //String log = String.format("%s:\n%s\n插入新图表:%s\n\n", new Date(), sl, c.getChartName()); String log = ""; - TemplateInfoCollector.appendProcess(log); + //TemplateInfoCollector.appendProcess(log); } diff --git a/designer_form/src/com/fr/aspectj/designerform/TemplateProcessTracker.aj b/designer_form/src/com/fr/aspectj/designerform/TemplateProcessTracker.aj index 0aabeb3620..1870793713 100644 --- a/designer_form/src/com/fr/aspectj/designerform/TemplateProcessTracker.aj +++ b/designer_form/src/com/fr/aspectj/designerform/TemplateProcessTracker.aj @@ -30,7 +30,7 @@ public aspect TemplateProcessTracker { //String log = String.format("%s:\n%s\n%s\n%s\n\n", new Date(), sl, e, e.getSource()); String log = ""; - TemplateInfoCollector.appendProcess(log); + //TemplateInfoCollector.appendProcess(log); } //同上 before(ActionEvent e) : onActionPerformed(e) { @@ -42,7 +42,7 @@ public aspect TemplateProcessTracker { //String log = String.format("%s:\n%s\n%s\n%s\n\n", new Date(), sl, e, e.getSource()); String log = ""; - TemplateInfoCollector.appendProcess(log); + //TemplateInfoCollector.appendProcess(log); } //同上 @@ -51,7 +51,7 @@ public aspect TemplateProcessTracker { //String log = String.format("%s:\n%s\nset value: %s at (%d, %d)\n\n", new Date(), sl, v, r, c); String log = ""; - TemplateInfoCollector.appendProcess(log); + //TemplateInfoCollector.appendProcess(log); } From a3eb6a06e07eab1d3ab805087f01a4ef90ee7b2e Mon Sep 17 00:00:00 2001 From: XiaXiang Date: Thu, 25 May 2017 15:49:18 +0800 Subject: [PATCH 11/41] rt --- designer_base/src/com/fr/design/extra/LoginWebBridge.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/designer_base/src/com/fr/design/extra/LoginWebBridge.java b/designer_base/src/com/fr/design/extra/LoginWebBridge.java index 6592e1601f..7db9fc5ac4 100644 --- a/designer_base/src/com/fr/design/extra/LoginWebBridge.java +++ b/designer_base/src/com/fr/design/extra/LoginWebBridge.java @@ -146,7 +146,7 @@ public class LoginWebBridge { if (res.equals(FAILED_MESSAGE_STATUS)) { } else { JSONObject jo = new JSONObject(res); - if (jo.getString("status").equals(SUCCESS_MESSAGE_STATUS)) { + if (jo.optString("status").equals(SUCCESS_MESSAGE_STATUS)) { setMessageCount(Integer.parseInt(jo.getString("message"))); } } From f9120667b1f8262b0e461b19deeb131001b64962 Mon Sep 17 00:00:00 2001 From: XiaXiang Date: Thu, 25 May 2017 15:53:17 +0800 Subject: [PATCH 12/41] bug fix --- .../src/com/fr/aspectj/designerbase/AlphaFineReminder.aj | 2 +- .../com/fr/aspectj/designerbase/TemplateProcessTracker.aj | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/designer_base/src/com/fr/aspectj/designerbase/AlphaFineReminder.aj b/designer_base/src/com/fr/aspectj/designerbase/AlphaFineReminder.aj index a42e339aca..ba1422f9e7 100644 --- a/designer_base/src/com/fr/aspectj/designerbase/AlphaFineReminder.aj +++ b/designer_base/src/com/fr/aspectj/designerbase/AlphaFineReminder.aj @@ -15,7 +15,7 @@ public aspect AlphaFineReminder { return; } if (e != null && e.getSource().getClass().getName().equals("com.fr.design.gui.imenu.UIMenuItem") && point.contains("com.fr.design.actions")) { - System.out.print("在点击菜单\n" + thisJoinPoint); + //System.out.print(thisJoinPoint + "\n"); } diff --git a/designer_base/src/com/fr/aspectj/designerbase/TemplateProcessTracker.aj b/designer_base/src/com/fr/aspectj/designerbase/TemplateProcessTracker.aj index b3f05a2c67..bc8b58615b 100644 --- a/designer_base/src/com/fr/aspectj/designerbase/TemplateProcessTracker.aj +++ b/designer_base/src/com/fr/aspectj/designerbase/TemplateProcessTracker.aj @@ -38,12 +38,9 @@ public aspect TemplateProcessTracker { before(ActionEvent e) : onActionPerformed(e) { SourceLocation sl = thisJoinPoint.getSourceLocation(); // !within(LogHandlerBar) 没用, 手动过滤 - if (e != null && e.getSource().toString().contains("javax.swing.Timer")) { + if (e.getSource().toString().contains("javax.swing.Timer")) { return; } - if (e != null && e.getSource().getClass().getName().equals("com.fr.design.gui.imenu.UIMenuItem")) { - System.out.print("在点击菜单\n" + thisJoinPointStaticPart.getSourceLocation() + thisJoinPoint); - } //String log = String.format("%s:\n%s\n%s\n%s\n\n", new Date(), sl, e, e.getSource()); String log = ""; From 6ebd8cb29328622c85ac53b2962b1bfb667c4745 Mon Sep 17 00:00:00 2001 From: hzzz Date: Tue, 23 May 2017 15:47:12 +0800 Subject: [PATCH 13/41] =?UTF-8?q?REPORT-2773=20mac=E4=B8=AD=E5=A4=8D?= =?UTF-8?q?=E5=88=B6=E5=BF=AB=E6=8D=B7=E9=94=AE=E7=9A=84=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../file/newReport/NewPolyReportAction.java | 4 +++- .../file/newReport/NewWorkBookAction.java | 4 +++- .../fr/design/mainframe/ElementCasePane.java | 12 ++++++---- .../design/mainframe/FormatBrushAction.java | 2 +- .../fr/design/actions/edit/CopyAction.java | 4 +++- .../com/fr/design/actions/edit/CutAction.java | 4 +++- .../fr/design/actions/edit/PasteAction.java | 4 +++- .../gui/autocomplete/AutoCompletion.java | 5 ++-- .../design/gui/frpane/UIAdvancedTextPane.java | 8 ++++--- .../gui/icombobox/ExtendedComboBox.java | 4 +++- .../fr/design/gui/icombobox/UIComboBoxUI.java | 4 +++- .../gui/itabpane/UITabsHeaderIconPane.java | 4 +++- .../ui/rtextarea/RTADefaultInputMap.java | 24 +++++++------------ .../loghandler/DesignerLogHandler.java | 8 ++++--- .../src/com/fr/design/menu/KeySetUtils.java | 20 +++++++++------- .../designer/beans/actions/CopyAction.java | 4 +++- .../designer/beans/actions/CutAction.java | 4 +++- .../designer/beans/actions/PasteAction.java | 4 +++- .../mainframe/actions/NewFormAction.java | 4 +++- .../widget/editors/DataTableConfigPane.java | 4 +++- 20 files changed, 80 insertions(+), 51 deletions(-) diff --git a/designer/src/com/fr/design/actions/file/newReport/NewPolyReportAction.java b/designer/src/com/fr/design/actions/file/newReport/NewPolyReportAction.java index ea7785f7ae..924d0c01d5 100644 --- a/designer/src/com/fr/design/actions/file/newReport/NewPolyReportAction.java +++ b/designer/src/com/fr/design/actions/file/newReport/NewPolyReportAction.java @@ -11,13 +11,15 @@ import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.JPolyWorkBook; import com.fr.general.Inter; +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; + public class NewPolyReportAction extends UpdateAction { public NewPolyReportAction() { this.setName(Inter.getLocText("M-New_Multi_Report")); this.setMnemonic('F'); this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/m_file/formExport.png")); - this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, KeyEvent.CTRL_MASK)); + this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, DEFAULT_MODIFIER)); } /** diff --git a/designer/src/com/fr/design/actions/file/newReport/NewWorkBookAction.java b/designer/src/com/fr/design/actions/file/newReport/NewWorkBookAction.java index 268adafbf1..cda7a0aa14 100644 --- a/designer/src/com/fr/design/actions/file/newReport/NewWorkBookAction.java +++ b/designer/src/com/fr/design/actions/file/newReport/NewWorkBookAction.java @@ -12,6 +12,8 @@ import java.awt.event.ActionEvent; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; + public class NewWorkBookAction extends UpdateAction { public NewWorkBookAction() { @@ -47,7 +49,7 @@ public class NewWorkBookAction extends UpdateAction { @Override public KeyStroke getKeyStroke() { - return KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_MASK); + return KeyStroke.getKeyStroke(KeyEvent.VK_N, DEFAULT_MODIFIER); } }; diff --git a/designer/src/com/fr/design/mainframe/ElementCasePane.java b/designer/src/com/fr/design/mainframe/ElementCasePane.java index dcc68ab81a..52bbc63931 100644 --- a/designer/src/com/fr/design/mainframe/ElementCasePane.java +++ b/designer/src/com/fr/design/mainframe/ElementCasePane.java @@ -127,6 +127,8 @@ import com.fr.stable.ColumnRow; import com.fr.stable.Constants; import com.fr.stable.unit.FU; +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; + /** * This class used to edit Report. */ @@ -280,7 +282,7 @@ public abstract class ElementCasePane extends Tar } } }); - formatBrush.registerKeyboardAction(keyListener, KeyStroke.getKeyStroke(KeyEvent.VK_B, InputEvent.CTRL_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW); + formatBrush.registerKeyboardAction(keyListener, KeyStroke.getKeyStroke(KeyEvent.VK_B, DEFAULT_MODIFIER), JComponent.WHEN_IN_FOCUSED_WINDOW); formatBrush.registerKeyboardAction(escKey, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); } @@ -855,7 +857,7 @@ public abstract class ElementCasePane extends Tar // clearReportPage old values. inputMapAncestor.clear(); actionMap.clear(); - inputMapAncestor.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_MASK), "cut"); + inputMapAncestor.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, DEFAULT_MODIFIER), "cut"); actionMap.put("cut", new AbstractAction() { public void actionPerformed(ActionEvent evt) { if (cut()) { @@ -863,13 +865,13 @@ public abstract class ElementCasePane extends Tar } } }); - inputMapAncestor.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_MASK), "copy"); + inputMapAncestor.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER), "copy"); actionMap.put("copy", new AbstractAction() { public void actionPerformed(ActionEvent evt) { copy(); } }); - inputMapAncestor.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_MASK), "paste"); + inputMapAncestor.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, DEFAULT_MODIFIER), "paste"); actionMap.put("paste", new AbstractAction() { public void actionPerformed(ActionEvent evt) { if (paste()) { @@ -887,7 +889,7 @@ public abstract class ElementCasePane extends Tar } } }); - inputMapAncestor.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, InputEvent.CTRL_MASK), "delete_all"); + inputMapAncestor.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, DEFAULT_MODIFIER), "delete_all"); actionMap.put("delete_all", new AbstractAction() { public void actionPerformed(ActionEvent evt) { if (clearAll()) { diff --git a/designer/src/com/fr/design/mainframe/FormatBrushAction.java b/designer/src/com/fr/design/mainframe/FormatBrushAction.java index 296fb6d20b..cf4c98448b 100644 --- a/designer/src/com/fr/design/mainframe/FormatBrushAction.java +++ b/designer/src/com/fr/design/mainframe/FormatBrushAction.java @@ -1 +1 @@ -package com.fr.design.mainframe; import com.fr.base.BaseUtils; import com.fr.base.Style; import com.fr.design.actions.ElementCaseAction; import com.fr.general.Inter; import com.fr.grid.selection.CellSelection; import com.fr.grid.selection.Selection; import com.fr.report.cell.DefaultTemplateCellElement; import com.fr.report.cell.TemplateCellElement; import com.fr.report.elementcase.TemplateElementCase; import javax.swing.*; import java.awt.*; import java.awt.event.*; /** * Author : daisy * Date: 13-8-7 * Time: 上午11:05 */ public class FormatBrushAction extends ElementCaseAction { private ElementCasePane ePane; private CellSelection oldSelection; public FormatBrushAction(ElementCasePane t) { super(t); this.setName(Inter.getLocText("M_Edit-FormatBrush")); this.setMnemonic('B'); this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/m_edit/formatBrush.png")); this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B, KeyEvent.CTRL_MASK)); } public boolean executeActionReturnUndoRecordNeeded() { ePane = (ElementCasePane) getEditingComponent(); if (ePane != null) { Selection selection = ePane.getSelection(); if (!(selection instanceof CellSelection)) { return false; } oldSelection = ((CellSelection) selection).clone(); ePane.setFormatReferencedCell(oldSelection); int cellRectangleCount = oldSelection.getCellRectangleCount(); if (cellRectangleCount > 1) { //格式刷只支持单次选择的区域,如果用ctrl复选选中了多片区域,点击格式刷按钮时弹出提示 //判断是不是连续区域 //荣国是连续区域,那么这些长方形的长加起来应该等于 if (!isContinueArea()) { JOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Inter.getLocText("Can_not_use_FormatBursh")); ePane.setFormatState(DesignerContext.FORMAT_STATE_NULL); ePane.getFormatBrush().setSelected(false); return false; } } //只对单个区域进行格式刷操作 ((ElementCasePane) DesignerContext.getReferencedElementCasePane()).getGrid().setNotShowingTableSelectPane(false); ePane.repaint(); return true; } return false; } /** * 判断是不是连续区域 * * @return */ private boolean isContinueArea() { int xStart = oldSelection.getCellRectangle(1).x; int xend = 0; int yStrat = oldSelection.getCellRectangle(1).y; int yend = 0; int totalNum = 0; for (int i = 0; i < oldSelection.getCellRectangleCount(); i++) { Rectangle temp = oldSelection.getCellRectangle(i); if (temp.getX() < xStart) { xStart = temp.x; } if (temp.getX() + temp.getWidth() > xend) { xend = (int) (temp.getX() + temp.getWidth()); } if (temp.getY() < yStrat) { yStrat = temp.y; } if (temp.getY() + temp.getHeight() > yend) { yend = (int) (temp.getY() + temp.getHeight()); } totalNum += (int) (temp.getWidth() * temp.getHeight()); } if ((xend - xStart) * (yend - yStrat) == totalNum) { oldSelection = new CellSelection(xStart, yStrat, (xend - xStart), (yend - yStrat)); ePane.setSelection(oldSelection); ePane.setFormatReferencedCell(oldSelection); return true; } return false; } public void updateFormatBrush(Style[][] referencedStyle, CellSelection cs, ElementCasePane reportPane) { //得到被参照的单元格的行列数 if (referencedStyle == null) { return; } int rowSpan = referencedStyle[0].length; int columnSpan = referencedStyle.length; //开始进行格式刷样式复制 TemplateElementCase elementCase = reportPane.getEditingElementCase(); int rowNum = cs.getRowSpan(); int columnNum = cs.getColumnSpan(); //如果只点选了一个,则自动补足 if (cs.getColumnSpan() * cs.getRowSpan() == 1) { rowNum = rowSpan; columnNum = columnSpan; } for (int j = 0; j < rowNum; j++) { for (int i = 0; i < columnNum; i++) { int column = i + cs.getColumn(); int row = j + cs.getRow(); TemplateCellElement cellElement = elementCase.getTemplateCellElement(column, row); if (cellElement == null) { cellElement = new DefaultTemplateCellElement(column, row); elementCase.addCellElement(cellElement); } cellElement.setStyle(referencedStyle[i % columnSpan][j % rowSpan]); } } } private Style[][] getOldStyles(CellSelection oldSelection) { Style[][] referencedStyle = new Style[oldSelection.getColumnSpan()][oldSelection.getRowSpan()]; int cellRectangleCount = oldSelection.getCellRectangleCount(); TemplateElementCase elementCase = ePane.getEditingElementCase(); for (int rect = 0; rect < cellRectangleCount; rect++) { Rectangle cellRectangle = oldSelection.getCellRectangle(rect); for (int j = 0; j < cellRectangle.height; j++) { for (int i = 0; i < cellRectangle.width; i++) { int column = i + cellRectangle.x; int row = j + cellRectangle.y; TemplateCellElement cellElement = elementCase.getTemplateCellElement(column, row); if (cellElement == null) { cellElement = new DefaultTemplateCellElement(column, row); elementCase.addCellElement(cellElement); } Style style = cellElement.getStyle(); if (style == null) { style = style.DEFAULT_STYLE; } referencedStyle[i][j] = style; } } } return referencedStyle; } } \ No newline at end of file +package com.fr.design.mainframe; import com.fr.base.BaseUtils; import com.fr.base.Style; import com.fr.design.actions.ElementCaseAction; import com.fr.general.Inter; import com.fr.grid.selection.CellSelection; import com.fr.grid.selection.Selection; import com.fr.report.cell.DefaultTemplateCellElement; import com.fr.report.cell.TemplateCellElement; import com.fr.report.elementcase.TemplateElementCase; import javax.swing.*; import java.awt.*; import java.awt.event.*; import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; /** * Author : daisy * Date: 13-8-7 * Time: 上午11:05 */ public class FormatBrushAction extends ElementCaseAction { private ElementCasePane ePane; private CellSelection oldSelection; public FormatBrushAction(ElementCasePane t) { super(t); this.setName(Inter.getLocText("M_Edit-FormatBrush")); this.setMnemonic('B'); this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/m_edit/formatBrush.png")); this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B, DEFAULT_MODIFIER)); } public boolean executeActionReturnUndoRecordNeeded() { ePane = (ElementCasePane) getEditingComponent(); if (ePane != null) { Selection selection = ePane.getSelection(); if (!(selection instanceof CellSelection)) { return false; } oldSelection = ((CellSelection) selection).clone(); ePane.setFormatReferencedCell(oldSelection); int cellRectangleCount = oldSelection.getCellRectangleCount(); if (cellRectangleCount > 1) { //格式刷只支持单次选择的区域,如果用ctrl复选选中了多片区域,点击格式刷按钮时弹出提示 //判断是不是连续区域 //荣国是连续区域,那么这些长方形的长加起来应该等于 if (!isContinueArea()) { JOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Inter.getLocText("Can_not_use_FormatBursh")); ePane.setFormatState(DesignerContext.FORMAT_STATE_NULL); ePane.getFormatBrush().setSelected(false); return false; } } //只对单个区域进行格式刷操作 ((ElementCasePane) DesignerContext.getReferencedElementCasePane()).getGrid().setNotShowingTableSelectPane(false); ePane.repaint(); return true; } return false; } /** * 判断是不是连续区域 * * @return */ private boolean isContinueArea() { int xStart = oldSelection.getCellRectangle(1).x; int xend = 0; int yStrat = oldSelection.getCellRectangle(1).y; int yend = 0; int totalNum = 0; for (int i = 0; i < oldSelection.getCellRectangleCount(); i++) { Rectangle temp = oldSelection.getCellRectangle(i); if (temp.getX() < xStart) { xStart = temp.x; } if (temp.getX() + temp.getWidth() > xend) { xend = (int) (temp.getX() + temp.getWidth()); } if (temp.getY() < yStrat) { yStrat = temp.y; } if (temp.getY() + temp.getHeight() > yend) { yend = (int) (temp.getY() + temp.getHeight()); } totalNum += (int) (temp.getWidth() * temp.getHeight()); } if ((xend - xStart) * (yend - yStrat) == totalNum) { oldSelection = new CellSelection(xStart, yStrat, (xend - xStart), (yend - yStrat)); ePane.setSelection(oldSelection); ePane.setFormatReferencedCell(oldSelection); return true; } return false; } public void updateFormatBrush(Style[][] referencedStyle, CellSelection cs, ElementCasePane reportPane) { //得到被参照的单元格的行列数 if (referencedStyle == null) { return; } int rowSpan = referencedStyle[0].length; int columnSpan = referencedStyle.length; //开始进行格式刷样式复制 TemplateElementCase elementCase = reportPane.getEditingElementCase(); int rowNum = cs.getRowSpan(); int columnNum = cs.getColumnSpan(); //如果只点选了一个,则自动补足 if (cs.getColumnSpan() * cs.getRowSpan() == 1) { rowNum = rowSpan; columnNum = columnSpan; } for (int j = 0; j < rowNum; j++) { for (int i = 0; i < columnNum; i++) { int column = i + cs.getColumn(); int row = j + cs.getRow(); TemplateCellElement cellElement = elementCase.getTemplateCellElement(column, row); if (cellElement == null) { cellElement = new DefaultTemplateCellElement(column, row); elementCase.addCellElement(cellElement); } cellElement.setStyle(referencedStyle[i % columnSpan][j % rowSpan]); } } } private Style[][] getOldStyles(CellSelection oldSelection) { Style[][] referencedStyle = new Style[oldSelection.getColumnSpan()][oldSelection.getRowSpan()]; int cellRectangleCount = oldSelection.getCellRectangleCount(); TemplateElementCase elementCase = ePane.getEditingElementCase(); for (int rect = 0; rect < cellRectangleCount; rect++) { Rectangle cellRectangle = oldSelection.getCellRectangle(rect); for (int j = 0; j < cellRectangle.height; j++) { for (int i = 0; i < cellRectangle.width; i++) { int column = i + cellRectangle.x; int row = j + cellRectangle.y; TemplateCellElement cellElement = elementCase.getTemplateCellElement(column, row); if (cellElement == null) { cellElement = new DefaultTemplateCellElement(column, row); elementCase.addCellElement(cellElement); } Style style = cellElement.getStyle(); if (style == null) { style = style.DEFAULT_STYLE; } referencedStyle[i][j] = style; } } } return referencedStyle; } } \ No newline at end of file diff --git a/designer_base/src/com/fr/design/actions/edit/CopyAction.java b/designer_base/src/com/fr/design/actions/edit/CopyAction.java index d0579a5797..b3a932ba5b 100644 --- a/designer_base/src/com/fr/design/actions/edit/CopyAction.java +++ b/designer_base/src/com/fr/design/actions/edit/CopyAction.java @@ -11,6 +11,8 @@ import com.fr.general.Inter; import javax.swing.*; import java.awt.event.KeyEvent; +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; + /** * Copy. */ @@ -21,7 +23,7 @@ public class CopyAction extends TemplateComponentAction { this.setName(Inter.getLocText("M_Edit-Copy")); this.setMnemonic('C'); this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/m_edit/copy.png")); - this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_MASK)); + this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER)); } @Override diff --git a/designer_base/src/com/fr/design/actions/edit/CutAction.java b/designer_base/src/com/fr/design/actions/edit/CutAction.java index 735ec5bf3d..b0e7847a60 100644 --- a/designer_base/src/com/fr/design/actions/edit/CutAction.java +++ b/designer_base/src/com/fr/design/actions/edit/CutAction.java @@ -12,6 +12,8 @@ import com.fr.design.actions.TemplateComponentAction; import com.fr.design.designer.TargetComponent; import com.fr.general.Inter; +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; + /** * Cut. */ @@ -25,7 +27,7 @@ public class CutAction extends TemplateComponentAction { this.setName(Inter.getLocText("M_Edit-Cut")); this.setMnemonic('T'); this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/m_edit/cut.png")); - this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.CTRL_MASK)); + this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, DEFAULT_MODIFIER)); } @Override diff --git a/designer_base/src/com/fr/design/actions/edit/PasteAction.java b/designer_base/src/com/fr/design/actions/edit/PasteAction.java index f6b71e421f..4ca42c0f22 100644 --- a/designer_base/src/com/fr/design/actions/edit/PasteAction.java +++ b/designer_base/src/com/fr/design/actions/edit/PasteAction.java @@ -12,6 +12,8 @@ import com.fr.design.actions.TemplateComponentAction; import com.fr.design.designer.TargetComponent; import com.fr.general.Inter; +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; + /** * Paste. */ @@ -25,7 +27,7 @@ public class PasteAction extends TemplateComponentAction { this.setName(Inter.getLocText("M_Edit-Paste")); this.setMnemonic('P'); this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/m_edit/paste.png")); - this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_MASK)); + this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, DEFAULT_MODIFIER)); } @Override diff --git a/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletion.java b/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletion.java index 83047ad71b..122beb1e6b 100644 --- a/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletion.java +++ b/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletion.java @@ -20,6 +20,8 @@ import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.*; +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; + /** * Adds auto-completion to a text component. Provides a popup window with a @@ -308,8 +310,7 @@ public class AutoCompletion { */ public static KeyStroke getDefaultTriggerKey() { // Default to CTRL, even on Mac, since Ctrl+Space activates Spotlight - int mask = InputEvent.CTRL_MASK; - return KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, mask); + return KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, DEFAULT_MODIFIER); } diff --git a/designer_base/src/com/fr/design/gui/frpane/UIAdvancedTextPane.java b/designer_base/src/com/fr/design/gui/frpane/UIAdvancedTextPane.java index 0194551da4..8ce8ec1a07 100644 --- a/designer_base/src/com/fr/design/gui/frpane/UIAdvancedTextPane.java +++ b/designer_base/src/com/fr/design/gui/frpane/UIAdvancedTextPane.java @@ -20,6 +20,8 @@ import com.fr.design.actions.UpdateAction; import com.fr.design.menu.KeySetUtils; import com.fr.general.Inter; +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; + /** * p:这是一个增强的JTextPane,支持很多Action */ @@ -143,7 +145,7 @@ public class UIAdvancedTextPane extends UITextPane { setName(Inter.getLocText("M_Edit-Cut")); setMnemonic('T'); setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/m_edit/cut.png")); - setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.CTRL_MASK)); + setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, DEFAULT_MODIFIER)); } public void actionPerformed(ActionEvent evt) { @@ -162,7 +164,7 @@ public class UIAdvancedTextPane extends UITextPane { this.setName(Inter.getLocText("M_Edit-Copy")); this.setMnemonic('C'); this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/m_edit/copy.png")); - this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_MASK)); + this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER)); } public void actionPerformed(ActionEvent evt) { @@ -181,7 +183,7 @@ public class UIAdvancedTextPane extends UITextPane { this.setName(Inter.getLocText("M_Edit-Paste")); this.setMnemonic('P'); this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/m_edit/paste.png")); - this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_MASK)); + this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, DEFAULT_MODIFIER)); } public void actionPerformed(ActionEvent evt) { diff --git a/designer_base/src/com/fr/design/gui/icombobox/ExtendedComboBox.java b/designer_base/src/com/fr/design/gui/icombobox/ExtendedComboBox.java index 86a5b5cf26..47ddbdac3b 100644 --- a/designer_base/src/com/fr/design/gui/icombobox/ExtendedComboBox.java +++ b/designer_base/src/com/fr/design/gui/icombobox/ExtendedComboBox.java @@ -17,6 +17,8 @@ import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicComboPopup; import javax.swing.plaf.basic.ComboPopup; +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; + public class ExtendedComboBox extends UIComboBox { private static final int VALUE120 = 120; @@ -79,7 +81,7 @@ public class ExtendedComboBox extends UIComboBox { // Key from the list. // ie., don't allow CTRL key deselection. e = new MouseEvent((Component) e.getSource(), e.getID(), e.getWhen(), e.getModifiers() - ^ InputEvent.CTRL_MASK, e.getX(), e.getY(), e.getClickCount(), e.isPopupTrigger()); + ^ DEFAULT_MODIFIER, e.getX(), e.getY(), e.getClickCount(), e.isPopupTrigger()); } super.processMouseEvent(e); } diff --git a/designer_base/src/com/fr/design/gui/icombobox/UIComboBoxUI.java b/designer_base/src/com/fr/design/gui/icombobox/UIComboBoxUI.java index 28ae0aebf7..ae1089fa92 100644 --- a/designer_base/src/com/fr/design/gui/icombobox/UIComboBoxUI.java +++ b/designer_base/src/com/fr/design/gui/icombobox/UIComboBoxUI.java @@ -24,6 +24,8 @@ import com.fr.design.gui.icontainer.UIScrollPane; import com.fr.stable.Constants; import com.fr.stable.StringUtils; +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; + /** * @author zhou F * @since 2012-5-9下午4:33:07 @@ -208,7 +210,7 @@ public class UIComboBoxUI extends BasicComboBoxUI implements MouseListener { @Override public void processMouseEvent(MouseEvent e) { if (e.isControlDown()) { - e = new MouseEvent((Component) e.getSource(), e.getID(), e.getWhen(), e.getModifiers() ^ InputEvent.CTRL_MASK, e.getX(), e.getY(), e.getClickCount(), + e = new MouseEvent((Component) e.getSource(), e.getID(), e.getWhen(), e.getModifiers() ^ DEFAULT_MODIFIER, e.getX(), e.getY(), e.getClickCount(), e.isPopupTrigger()); } super.processMouseEvent(e); diff --git a/designer_base/src/com/fr/design/gui/itabpane/UITabsHeaderIconPane.java b/designer_base/src/com/fr/design/gui/itabpane/UITabsHeaderIconPane.java index 1ba60ed579..1ec189cc13 100644 --- a/designer_base/src/com/fr/design/gui/itabpane/UITabsHeaderIconPane.java +++ b/designer_base/src/com/fr/design/gui/itabpane/UITabsHeaderIconPane.java @@ -32,6 +32,8 @@ import com.fr.design.gui.core.UITabComponent; import com.fr.design.gui.ibutton.UITabButton; import com.fr.stable.StringUtils; +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; + /** * 本来想弄个延迟加载的,发现在单元格属性表那边没有意义,就算了.这个面板是纯粹的,没有与模板的任何交互操作(比如说populate() update()) * @@ -125,7 +127,7 @@ public class UITabsHeaderIconPane extends JPanel implements UITabComponent { inputMapAncestor.clear(); actionMap.clear(); - inputMapAncestor.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, KeyEvent.CTRL_MASK), "switch"); + inputMapAncestor.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, DEFAULT_MODIFIER), "switch"); actionMap.put("switch", new AbstractAction() { /** diff --git a/designer_base/src/com/fr/design/gui/syntax/ui/rtextarea/RTADefaultInputMap.java b/designer_base/src/com/fr/design/gui/syntax/ui/rtextarea/RTADefaultInputMap.java index 5e1a7cfe74..35a1995ed8 100644 --- a/designer_base/src/com/fr/design/gui/syntax/ui/rtextarea/RTADefaultInputMap.java +++ b/designer_base/src/com/fr/design/gui/syntax/ui/rtextarea/RTADefaultInputMap.java @@ -41,6 +41,14 @@ import javax.swing.text.DefaultEditorKit; public class RTADefaultInputMap extends InputMap { + /** + * Returns the default modifier key for a system. For example, on Windows + * this would be the CTRL key (InputEvent.CTRL_MASK). + * + * @return The default modifier key. + */ + public static final int DEFAULT_MODIFIER = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); + /** * Constructs the default input map for an RTextArea. */ @@ -48,7 +56,7 @@ public class RTADefaultInputMap extends InputMap { super(); - int defaultModifier = getDefaultModifier(); + int defaultModifier = DEFAULT_MODIFIER; //int ctrl = InputEvent.CTRL_MASK; int alt = InputEvent.ALT_MASK; int shift = InputEvent.SHIFT_MASK; @@ -134,18 +142,4 @@ public class RTADefaultInputMap extends InputMap { */ } - - - /** - * Returns the default modifier key for a system. For example, on Windows - * this would be the CTRL key (InputEvent.CTRL_MASK). - * - * @return The default modifier key. - */ - protected static final int getDefaultModifier() { - return Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); - } - - - } \ No newline at end of file diff --git a/designer_base/src/com/fr/design/mainframe/loghandler/DesignerLogHandler.java b/designer_base/src/com/fr/design/mainframe/loghandler/DesignerLogHandler.java index 501f957df2..59afdba510 100644 --- a/designer_base/src/com/fr/design/mainframe/loghandler/DesignerLogHandler.java +++ b/designer_base/src/com/fr/design/mainframe/loghandler/DesignerLogHandler.java @@ -24,6 +24,8 @@ import java.util.Date; import java.util.logging.Handler; import java.util.logging.LogRecord; +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; + public class DesignerLogHandler { protected static final int INFO_INT = FRLogLevel.INFO.intValue(); protected static final int ERRO_INT = FRLogLevel.ERROR.intValue(); @@ -158,9 +160,9 @@ public class DesignerLogHandler { clear.setIcon(BaseUtils.readIcon("/com/fr/design/images/log/clear.png")); popup.add(clear); - selectAll.setAccelerator(KeyStroke.getKeyStroke('A', InputEvent.CTRL_MASK)); - copy.setAccelerator(KeyStroke.getKeyStroke('C', InputEvent.CTRL_MASK)); - clear.setAccelerator(KeyStroke.getKeyStroke('L', InputEvent.CTRL_MASK)); + selectAll.setAccelerator(KeyStroke.getKeyStroke('A', DEFAULT_MODIFIER)); + copy.setAccelerator(KeyStroke.getKeyStroke('C', DEFAULT_MODIFIER)); + clear.setAccelerator(KeyStroke.getKeyStroke('L', DEFAULT_MODIFIER)); jTextArea.addMouseListener(new MouseAdapter() { // check for right click diff --git a/designer_base/src/com/fr/design/menu/KeySetUtils.java b/designer_base/src/com/fr/design/menu/KeySetUtils.java index 1b62fcdc4a..401da7fb99 100644 --- a/designer_base/src/com/fr/design/menu/KeySetUtils.java +++ b/designer_base/src/com/fr/design/menu/KeySetUtils.java @@ -12,6 +12,8 @@ import javax.swing.*; import java.awt.event.KeyEvent; import java.util.Locale; +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; + /** * Created by IntelliJ IDEA. * Author : daisy @@ -36,7 +38,7 @@ public class KeySetUtils { @Override public KeyStroke getKeyStroke() { - return KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_MASK); + return KeyStroke.getKeyStroke(KeyEvent.VK_O, DEFAULT_MODIFIER); } }; @@ -71,7 +73,7 @@ public class KeySetUtils { @Override public KeyStroke getKeyStroke() { - return KeyStroke.getKeyStroke(KeyEvent.VK_W, KeyEvent.CTRL_MASK); + return KeyStroke.getKeyStroke(KeyEvent.VK_W, DEFAULT_MODIFIER); } }; @@ -88,7 +90,7 @@ public class KeySetUtils { @Override public KeyStroke getKeyStroke() { - return KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_MASK); + return KeyStroke.getKeyStroke(KeyEvent.VK_S, DEFAULT_MODIFIER); } }; @@ -122,7 +124,7 @@ public class KeySetUtils { @Override public KeyStroke getKeyStroke() { - return KeyStroke.getKeyStroke(KeyEvent.VK_Z, KeyEvent.CTRL_MASK); + return KeyStroke.getKeyStroke(KeyEvent.VK_Z, DEFAULT_MODIFIER); } }; @@ -139,7 +141,7 @@ public class KeySetUtils { @Override public KeyStroke getKeyStroke() { - return KeyStroke.getKeyStroke(KeyEvent.VK_Y, KeyEvent.CTRL_MASK); + return KeyStroke.getKeyStroke(KeyEvent.VK_Y, DEFAULT_MODIFIER); } }; @@ -156,7 +158,7 @@ public class KeySetUtils { @Override public KeyStroke getKeyStroke() { - return KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyEvent.CTRL_MASK); + return KeyStroke.getKeyStroke(KeyEvent.VK_E, DEFAULT_MODIFIER); } }; @@ -353,7 +355,7 @@ public class KeySetUtils { @Override public KeyStroke getKeyStroke() { - return KeyStroke.getKeyStroke(KeyEvent.VK_M, KeyEvent.CTRL_MASK); + return KeyStroke.getKeyStroke(KeyEvent.VK_M, DEFAULT_MODIFIER); } }; @@ -370,7 +372,7 @@ public class KeySetUtils { @Override public KeyStroke getKeyStroke() { - return KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyEvent.CTRL_MASK); + return KeyStroke.getKeyStroke(KeyEvent.VK_E, DEFAULT_MODIFIER); } }; @@ -387,7 +389,7 @@ public class KeySetUtils { @Override public KeyStroke getKeyStroke() { - return KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyEvent.CTRL_MASK); + return KeyStroke.getKeyStroke(KeyEvent.VK_E, DEFAULT_MODIFIER); } }; diff --git a/designer_form/src/com/fr/design/designer/beans/actions/CopyAction.java b/designer_form/src/com/fr/design/designer/beans/actions/CopyAction.java index 23686f651a..d3906040da 100644 --- a/designer_form/src/com/fr/design/designer/beans/actions/CopyAction.java +++ b/designer_form/src/com/fr/design/designer/beans/actions/CopyAction.java @@ -8,6 +8,8 @@ import javax.swing.*; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; + public class CopyAction extends FormEditAction { public CopyAction(FormDesigner t) { @@ -15,7 +17,7 @@ public class CopyAction extends FormEditAction { this.setName(Inter.getLocText("M_Edit-Copy")); this.setMnemonic('C'); this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/m_edit/copy.png")); - this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_MASK)); + this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER)); } @Override diff --git a/designer_form/src/com/fr/design/designer/beans/actions/CutAction.java b/designer_form/src/com/fr/design/designer/beans/actions/CutAction.java index 9acb261487..1f81c12807 100644 --- a/designer_form/src/com/fr/design/designer/beans/actions/CutAction.java +++ b/designer_form/src/com/fr/design/designer/beans/actions/CutAction.java @@ -9,6 +9,8 @@ import com.fr.base.BaseUtils; import com.fr.general.Inter; import com.fr.design.mainframe.FormDesigner; +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; + public class CutAction extends FormEditAction { public CutAction(FormDesigner t) { @@ -16,7 +18,7 @@ public class CutAction extends FormEditAction { this.setName(Inter.getLocText("M_Edit-Cut")); this.setMnemonic('T'); this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/m_edit/cut.png")); - this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_MASK)); + this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, DEFAULT_MODIFIER)); } @Override diff --git a/designer_form/src/com/fr/design/designer/beans/actions/PasteAction.java b/designer_form/src/com/fr/design/designer/beans/actions/PasteAction.java index 85ce1d6ed5..351a809f62 100644 --- a/designer_form/src/com/fr/design/designer/beans/actions/PasteAction.java +++ b/designer_form/src/com/fr/design/designer/beans/actions/PasteAction.java @@ -9,6 +9,8 @@ import com.fr.base.BaseUtils; import com.fr.general.Inter; import com.fr.design.mainframe.FormDesigner; +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; + public class PasteAction extends FormEditAction { public PasteAction(FormDesigner t) { @@ -16,7 +18,7 @@ public class PasteAction extends FormEditAction { this.setName(Inter.getLocText("M_Edit-Paste")); this.setMnemonic('P'); this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/m_edit/paste.png")); - this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_MASK)); + this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, DEFAULT_MODIFIER)); } @Override diff --git a/designer_form/src/com/fr/design/mainframe/actions/NewFormAction.java b/designer_form/src/com/fr/design/mainframe/actions/NewFormAction.java index 107b9da587..78b17d4b3d 100644 --- a/designer_form/src/com/fr/design/mainframe/actions/NewFormAction.java +++ b/designer_form/src/com/fr/design/mainframe/actions/NewFormAction.java @@ -14,6 +14,8 @@ import java.awt.event.ActionEvent; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; + public class NewFormAction extends UpdateAction { public NewFormAction() { @@ -48,7 +50,7 @@ public class NewFormAction extends UpdateAction { @Override public KeyStroke getKeyStroke() { - return KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_MASK); + return KeyStroke.getKeyStroke(KeyEvent.VK_F, DEFAULT_MODIFIER); } }; } \ No newline at end of file diff --git a/designer_form/src/com/fr/design/mainframe/widget/editors/DataTableConfigPane.java b/designer_form/src/com/fr/design/mainframe/widget/editors/DataTableConfigPane.java index 36c54f4ecc..417d761ccf 100644 --- a/designer_form/src/com/fr/design/mainframe/widget/editors/DataTableConfigPane.java +++ b/designer_form/src/com/fr/design/mainframe/widget/editors/DataTableConfigPane.java @@ -21,6 +21,8 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; + public class DataTableConfigPane extends JComponent implements PropertyChangeListener { private DataEditingTable table; @@ -183,7 +185,7 @@ public class DataTableConfigPane extends JComponent implements PropertyChangeLis this.setName(Inter.getLocText("M_Edit-Cut")); this.setMnemonic('T'); this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/m_edit/cut.png")); - this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.CTRL_MASK)); + this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, DEFAULT_MODIFIER)); } @Override From 7c533795e72e2b4744c977fc1546473095562517 Mon Sep 17 00:00:00 2001 From: hzzz Date: Wed, 24 May 2017 10:50:53 +0800 Subject: [PATCH 14/41] =?UTF-8?q?=E4=BF=AElogPane=E7=9A=84=E5=BF=AB?= =?UTF-8?q?=E6=8D=B7=E9=94=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RSyntaxTextAreaDefaultInputMap.java | 2 +- .../loghandler/DesignerLogHandler.java | 22 +++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/designer_base/src/com/fr/design/gui/syntax/ui/rsyntaxtextarea/RSyntaxTextAreaDefaultInputMap.java b/designer_base/src/com/fr/design/gui/syntax/ui/rsyntaxtextarea/RSyntaxTextAreaDefaultInputMap.java index f9171f74a3..715ab47fe3 100644 --- a/designer_base/src/com/fr/design/gui/syntax/ui/rsyntaxtextarea/RSyntaxTextAreaDefaultInputMap.java +++ b/designer_base/src/com/fr/design/gui/syntax/ui/rsyntaxtextarea/RSyntaxTextAreaDefaultInputMap.java @@ -34,7 +34,7 @@ public class RSyntaxTextAreaDefaultInputMap extends RTADefaultInputMap { */ public RSyntaxTextAreaDefaultInputMap() { - int defaultMod = getDefaultModifier(); + int defaultMod = DEFAULT_MODIFIER; //int ctrl = InputEvent.CTRL_MASK; int shift = InputEvent.SHIFT_MASK; //int alt = InputEvent.ALT_MASK; diff --git a/designer_base/src/com/fr/design/mainframe/loghandler/DesignerLogHandler.java b/designer_base/src/com/fr/design/mainframe/loghandler/DesignerLogHandler.java index 59afdba510..8da862fb61 100644 --- a/designer_base/src/com/fr/design/mainframe/loghandler/DesignerLogHandler.java +++ b/designer_base/src/com/fr/design/mainframe/loghandler/DesignerLogHandler.java @@ -134,8 +134,7 @@ public class DesignerLogHandler { private UIMenuItem clear; private LogHandlerArea() { - jTextArea = new JTextPane(); - + jTextArea = initLogJTextArea(); this.setLayout(FRGUIPaneFactory.createBorderLayout()); UIScrollPane js = new UIScrollPane(jTextArea); this.add(js, BorderLayout.CENTER); @@ -190,6 +189,23 @@ public class DesignerLogHandler { }); } + private JTextPane initLogJTextArea() { + JTextPane resultPane = new JTextPane(); + InputMap inputMap = resultPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER), "copy"); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_L, DEFAULT_MODIFIER), "clear"); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, DEFAULT_MODIFIER), "select-all"); + ActionMap actionMap = resultPane.getActionMap(); + actionMap.put("clear", new AbstractAction() { + public void actionPerformed(ActionEvent evt) { + resultPane.setText(""); + caption.clearMessage(); + DesignerLogImpl.getInstance().clear(); + } + }); + return resultPane; + } + public void printStackTrace(LogRecordTimeProvider logRecordTime) { LogRecord logRecord = logRecordTime.getLogRecord(); Date date = logRecordTime.getDate(); @@ -299,6 +315,4 @@ public class DesignerLogHandler { }; } - - } \ No newline at end of file From 54c008a3b985d3184129ce87fe4ae711de713188 Mon Sep 17 00:00:00 2001 From: hzzz Date: Wed, 24 May 2017 20:04:04 +0800 Subject: [PATCH 15/41] fix --- .../src/com/fr/design/gui/ilist/UIList.java | 13 +++++++++++++ .../com/fr/design/gui/itextarea/UITextArea.java | 13 +++++++++++++ .../fr/design/gui/itextfield/UITextField.java | 17 ++++++++++++++--- .../gui/itree/checkboxtree/CheckBoxTree.java | 9 +++++++-- .../loghandler/DesignerLogHandler.java | 9 +++------ 5 files changed, 50 insertions(+), 11 deletions(-) diff --git a/designer_base/src/com/fr/design/gui/ilist/UIList.java b/designer_base/src/com/fr/design/gui/ilist/UIList.java index b01f40f0b8..2a31fe6c3d 100644 --- a/designer_base/src/com/fr/design/gui/ilist/UIList.java +++ b/designer_base/src/com/fr/design/gui/ilist/UIList.java @@ -6,10 +6,14 @@ import com.fr.design.mainframe.JTemplate; import com.fr.stable.StringUtils; import javax.swing.*; +import javax.swing.text.DefaultEditorKit; import java.awt.*; +import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.util.Vector; +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; + /** * Created with IntelliJ IDEA. * User: pony @@ -22,6 +26,15 @@ public class UIList extends JList{ public UIList() { super(); + InputMap inputMap = this.getInputMap(); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, DEFAULT_MODIFIER), + DefaultEditorKit.selectAllAction); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER), + DefaultEditorKit.copyAction); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, DEFAULT_MODIFIER), + DefaultEditorKit.pasteAction); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, DEFAULT_MODIFIER), + DefaultEditorKit.cutAction); } public UIList(ListModel dataModel) { diff --git a/designer_base/src/com/fr/design/gui/itextarea/UITextArea.java b/designer_base/src/com/fr/design/gui/itextarea/UITextArea.java index cf89971b3a..8194b10cef 100644 --- a/designer_base/src/com/fr/design/gui/itextarea/UITextArea.java +++ b/designer_base/src/com/fr/design/gui/itextarea/UITextArea.java @@ -7,13 +7,26 @@ import com.fr.design.utils.gui.GUICoreUtils; import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; +import javax.swing.text.DefaultEditorKit; import java.awt.*; +import java.awt.event.KeyEvent; + +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; public class UITextArea extends JTextArea implements UIObserver { private UIObserverListener uiObserverListener; public UITextArea(int i, int j) { super(i, j); + InputMap inputMap = this.getInputMap(); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, DEFAULT_MODIFIER), + DefaultEditorKit.selectAllAction); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER), + DefaultEditorKit.copyAction); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, DEFAULT_MODIFIER), + DefaultEditorKit.pasteAction); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, DEFAULT_MODIFIER), + DefaultEditorKit.cutAction); initComponents(); } diff --git a/designer_base/src/com/fr/design/gui/itextfield/UITextField.java b/designer_base/src/com/fr/design/gui/itextfield/UITextField.java index 7a451593bd..ff4556acbc 100644 --- a/designer_base/src/com/fr/design/gui/itextfield/UITextField.java +++ b/designer_base/src/com/fr/design/gui/itextfield/UITextField.java @@ -1,12 +1,12 @@ package com.fr.design.gui.itextfield; import java.awt.*; +import java.awt.event.KeyEvent; -import javax.swing.JFrame; -import javax.swing.JPanel; -import javax.swing.JTextField; +import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; +import javax.swing.text.DefaultEditorKit; import javax.swing.text.Document; import com.fr.design.event.GlobalNameListener; @@ -16,6 +16,8 @@ import com.fr.design.event.UIObserverListener; import com.fr.stable.Constants; import com.fr.design.utils.gui.GUICoreUtils; +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; + /** * @author Jerry */ @@ -30,6 +32,15 @@ public class UITextField extends JTextField implements UIObserver, GlobalNameObs public UITextField() { super(); + InputMap inputMap = this.getInputMap(); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, DEFAULT_MODIFIER), + DefaultEditorKit.selectAllAction); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER), + DefaultEditorKit.copyAction); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, DEFAULT_MODIFIER), + DefaultEditorKit.pasteAction); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, DEFAULT_MODIFIER), + DefaultEditorKit.cutAction); initListener(); } diff --git a/designer_base/src/com/fr/design/gui/itree/checkboxtree/CheckBoxTree.java b/designer_base/src/com/fr/design/gui/itree/checkboxtree/CheckBoxTree.java index 0511504cf7..c56efdfd64 100644 --- a/designer_base/src/com/fr/design/gui/itree/checkboxtree/CheckBoxTree.java +++ b/designer_base/src/com/fr/design/gui/itree/checkboxtree/CheckBoxTree.java @@ -16,10 +16,10 @@ import java.beans.PropertyChangeListener; import java.util.Hashtable; import java.util.Vector; -import javax.swing.JTree; -import javax.swing.SwingUtilities; +import javax.swing.*; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; +import javax.swing.text.DefaultEditorKit; import javax.swing.text.Position; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.TreeCellRenderer; @@ -29,6 +29,8 @@ import javax.swing.tree.TreePath; import com.fr.design.gui.icheckbox.UICheckBox; +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; + /** * CheckBoxTree is a special JTree which uses UICheckBox as the tree renderer. * In addition to regular JTree's features, it also allows you select any number @@ -87,6 +89,9 @@ public class CheckBoxTree extends JTree { public CheckBoxTree(TreeModel newModel) { super(newModel); + InputMap inputMap = this.getInputMap(); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, DEFAULT_MODIFIER), + "selectAll"); init(); } diff --git a/designer_base/src/com/fr/design/mainframe/loghandler/DesignerLogHandler.java b/designer_base/src/com/fr/design/mainframe/loghandler/DesignerLogHandler.java index 8da862fb61..0bf286e51b 100644 --- a/designer_base/src/com/fr/design/mainframe/loghandler/DesignerLogHandler.java +++ b/designer_base/src/com/fr/design/mainframe/loghandler/DesignerLogHandler.java @@ -13,10 +13,7 @@ import com.fr.general.LogRecordTime; import com.fr.stable.xml.LogRecordTimeProvider; import javax.swing.*; -import javax.swing.text.BadLocationException; -import javax.swing.text.Document; -import javax.swing.text.SimpleAttributeSet; -import javax.swing.text.StyleConstants; +import javax.swing.text.*; import java.awt.*; import java.awt.event.*; import java.text.SimpleDateFormat; @@ -192,9 +189,9 @@ public class DesignerLogHandler { private JTextPane initLogJTextArea() { JTextPane resultPane = new JTextPane(); InputMap inputMap = resultPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); - inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER), "copy"); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER), DefaultEditorKit.copyAction); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, DEFAULT_MODIFIER), DefaultEditorKit.selectAllAction); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_L, DEFAULT_MODIFIER), "clear"); - inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, DEFAULT_MODIFIER), "select-all"); ActionMap actionMap = resultPane.getActionMap(); actionMap.put("clear", new AbstractAction() { public void actionPerformed(ActionEvent evt) { From 89564565cdd5098aa3fc242859a3baed3a9c357d Mon Sep 17 00:00:00 2001 From: hzzz Date: Wed, 24 May 2017 20:09:10 +0800 Subject: [PATCH 16/41] =?UTF-8?q?REPORT-2773=20mac=E4=B8=AD=E5=A4=8D?= =?UTF-8?q?=E5=88=B6=E5=BF=AB=E6=8D=B7=E9=94=AE=E7=9A=84=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/com/fr/design/gui/ilist/UIList.java | 24 ++------ .../fr/design/gui/itextarea/UITextArea.java | 8 +-- .../fr/design/gui/itextfield/UITextField.java | 8 +-- .../gui/itree/checkboxtree/CheckBoxTree.java | 60 +++++++------------ 4 files changed, 37 insertions(+), 63 deletions(-) diff --git a/designer_base/src/com/fr/design/gui/ilist/UIList.java b/designer_base/src/com/fr/design/gui/ilist/UIList.java index 2a31fe6c3d..8916cf18c8 100644 --- a/designer_base/src/com/fr/design/gui/ilist/UIList.java +++ b/designer_base/src/com/fr/design/gui/ilist/UIList.java @@ -6,14 +6,10 @@ import com.fr.design.mainframe.JTemplate; import com.fr.stable.StringUtils; import javax.swing.*; -import javax.swing.text.DefaultEditorKit; import java.awt.*; -import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.util.Vector; -import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; - /** * Created with IntelliJ IDEA. * User: pony @@ -21,20 +17,11 @@ import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_M * Time: 上午11:07 * To change this template use File | Settings | File Templates. */ -public class UIList extends JList{ +public class UIList extends JList { private Icon icon; public UIList() { super(); - InputMap inputMap = this.getInputMap(); - inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, DEFAULT_MODIFIER), - DefaultEditorKit.selectAllAction); - inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER), - DefaultEditorKit.copyAction); - inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, DEFAULT_MODIFIER), - DefaultEditorKit.pasteAction); - inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, DEFAULT_MODIFIER), - DefaultEditorKit.cutAction); } public UIList(ListModel dataModel) { @@ -59,12 +46,12 @@ public class UIList extends JList{ if (rendererComp.getPreferredSize().width > getVisibleRect().width) { String tips = (rendererComp instanceof JComponent) ? ((JComponent) rendererComp).getToolTipText() : null; if (tips == null) { - if(value instanceof JTemplate){ + if (value instanceof JTemplate) { tips = ((JTemplate) value).getEditingFILE().getName(); icon = ((JTemplate) value).getEditingFILE().getIcon(); - } else if (value instanceof ListModelElement || value instanceof TableProcedure){ - tips = ((JLabel)rendererComp).getText(); - icon = ((JLabel)rendererComp).getIcon(); + } else if (value instanceof ListModelElement || value instanceof TableProcedure) { + tips = ((JLabel) rendererComp).getText(); + icon = ((JLabel) rendererComp).getIcon(); } } return tips; @@ -84,6 +71,7 @@ public class UIList extends JList{ } return null; } + public JToolTip createToolTip() { UIToolTip tip = new UIToolTip(icon); tip.setComponent(this); diff --git a/designer_base/src/com/fr/design/gui/itextarea/UITextArea.java b/designer_base/src/com/fr/design/gui/itextarea/UITextArea.java index 8194b10cef..03a70a6ef4 100644 --- a/designer_base/src/com/fr/design/gui/itextarea/UITextArea.java +++ b/designer_base/src/com/fr/design/gui/itextarea/UITextArea.java @@ -19,13 +19,13 @@ public class UITextArea extends JTextArea implements UIObserver { public UITextArea(int i, int j) { super(i, j); InputMap inputMap = this.getInputMap(); - inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, DEFAULT_MODIFIER), + inputMap.getParent().put(KeyStroke.getKeyStroke(KeyEvent.VK_A, DEFAULT_MODIFIER), DefaultEditorKit.selectAllAction); - inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER), + inputMap.getParent().put(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER), DefaultEditorKit.copyAction); - inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, DEFAULT_MODIFIER), + inputMap.getParent().put(KeyStroke.getKeyStroke(KeyEvent.VK_V, DEFAULT_MODIFIER), DefaultEditorKit.pasteAction); - inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, DEFAULT_MODIFIER), + inputMap.getParent().put(KeyStroke.getKeyStroke(KeyEvent.VK_X, DEFAULT_MODIFIER), DefaultEditorKit.cutAction); initComponents(); } diff --git a/designer_base/src/com/fr/design/gui/itextfield/UITextField.java b/designer_base/src/com/fr/design/gui/itextfield/UITextField.java index ff4556acbc..0af105058b 100644 --- a/designer_base/src/com/fr/design/gui/itextfield/UITextField.java +++ b/designer_base/src/com/fr/design/gui/itextfield/UITextField.java @@ -33,13 +33,13 @@ public class UITextField extends JTextField implements UIObserver, GlobalNameObs public UITextField() { super(); InputMap inputMap = this.getInputMap(); - inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, DEFAULT_MODIFIER), + inputMap.getParent().put(KeyStroke.getKeyStroke(KeyEvent.VK_A, DEFAULT_MODIFIER), DefaultEditorKit.selectAllAction); - inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER), + inputMap.getParent().put(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER), DefaultEditorKit.copyAction); - inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, DEFAULT_MODIFIER), + inputMap.getParent().put(KeyStroke.getKeyStroke(KeyEvent.VK_V, DEFAULT_MODIFIER), DefaultEditorKit.pasteAction); - inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, DEFAULT_MODIFIER), + inputMap.getParent().put(KeyStroke.getKeyStroke(KeyEvent.VK_X, DEFAULT_MODIFIER), DefaultEditorKit.cutAction); initListener(); } diff --git a/designer_base/src/com/fr/design/gui/itree/checkboxtree/CheckBoxTree.java b/designer_base/src/com/fr/design/gui/itree/checkboxtree/CheckBoxTree.java index c56efdfd64..a22264477f 100644 --- a/designer_base/src/com/fr/design/gui/itree/checkboxtree/CheckBoxTree.java +++ b/designer_base/src/com/fr/design/gui/itree/checkboxtree/CheckBoxTree.java @@ -5,8 +5,14 @@ */ package com.fr.design.gui.itree.checkboxtree; -import java.awt.Component; -import java.awt.Rectangle; +import com.fr.design.gui.icheckbox.UICheckBox; + +import javax.swing.*; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.text.Position; +import javax.swing.tree.*; +import java.awt.*; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; @@ -16,19 +22,6 @@ import java.beans.PropertyChangeListener; import java.util.Hashtable; import java.util.Vector; -import javax.swing.*; -import javax.swing.event.TreeSelectionEvent; -import javax.swing.event.TreeSelectionListener; -import javax.swing.text.DefaultEditorKit; -import javax.swing.text.Position; -import javax.swing.tree.DefaultTreeCellRenderer; -import javax.swing.tree.TreeCellRenderer; -import javax.swing.tree.TreeModel; -import javax.swing.tree.TreeNode; -import javax.swing.tree.TreePath; - -import com.fr.design.gui.icheckbox.UICheckBox; - import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; /** @@ -39,11 +32,11 @@ import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_M * select one or several tree nodes and press SPACE key to toggle the * check box selection for all selected tree nodes. *

- * In order to retrieve which tree paths are selected, you need to call + * In order to retrieve which tree paths are selected, you need to call * {@link #getCheckBoxTreeSelectionModel()}. - * It will return the selection model that keeps track of which tree + * It will return the selection model that keeps track of which tree * paths have been checked. For example - * {@link CheckBoxTreeSelectionModel#getSelectionPaths()} + * {@link CheckBoxTreeSelectionModel#getSelectionPaths()} * will give the list of paths which have * been checked. */ @@ -90,8 +83,7 @@ public class CheckBoxTree extends JTree { public CheckBoxTree(TreeModel newModel) { super(newModel); InputMap inputMap = this.getInputMap(); - inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, DEFAULT_MODIFIER), - "selectAll"); + inputMap.getParent().put(KeyStroke.getKeyStroke(KeyEvent.VK_A, DEFAULT_MODIFIER), "selectAll"); init(); } @@ -116,7 +108,7 @@ public class CheckBoxTree extends JTree { addPropertyChangeListener(JTree.SELECTION_MODEL_PROPERTY, _modelChangeListener); updateRowMapper(); } - + /** * Inserts the mouse listener at the particular index in the listeners' chain. * @@ -127,7 +119,7 @@ public class CheckBoxTree extends JTree { private void insertMouseListener(Component component, MouseListener l, int index) { MouseListener[] listeners = component.getMouseListeners(); for (int i = 0, length = listeners.length; i < length; i++) { - component.removeMouseListener(listeners[i]); + component.removeMouseListener(listeners[i]); } // for (MouseListener listener : listeners) { // component.removeMouseListener(listener); @@ -173,7 +165,7 @@ public class CheckBoxTree extends JTree { * Gets the cell renderer with check box. * * @return CheckBoxTree's own cell renderer which has the check box. The actual cell renderer - * you set by setCellRenderer() can be accessed by using {@link #getActualCellRenderer()}. + * you set by setCellRenderer() can be accessed by using {@link #getActualCellRenderer()}. */ public TreeCellRenderer getCellRenderer() { TreeCellRenderer cellRenderer = super.getCellRenderer(); @@ -182,8 +174,7 @@ public class CheckBoxTree extends JTree { } if (_treeCellRenderer == null) { _treeCellRenderer = createCellRenderer(cellRenderer); - } - else { + } else { _treeCellRenderer.setActualTreeRenderer(cellRenderer); } return _treeCellRenderer; @@ -199,8 +190,7 @@ public class CheckBoxTree extends JTree { public TreeCellRenderer getActualCellRenderer() { if (_treeCellRenderer != null) { return _treeCellRenderer.getActualTreeRenderer(); - } - else { + } else { return super.getCellRenderer(); } } @@ -255,8 +245,7 @@ public class CheckBoxTree extends JTree { if (clicksInCheckBox(e, path)) { return path; - } - else { + } else { return null; } } @@ -264,13 +253,11 @@ public class CheckBoxTree extends JTree { protected boolean clicksInCheckBox(MouseEvent e, TreePath path) { if (!_tree.isCheckBoxVisible(path)) { return false; - } - else { + } else { Rectangle bounds = _tree.getPathBounds(path); if (_tree.getComponentOrientation().isLeftToRight()) { return e.getX() < bounds.x + _hotspot; - } - else { + } else { return e.getX() > bounds.x + bounds.width - _hotspot; } } @@ -354,8 +341,7 @@ public class CheckBoxTree extends JTree { selectionModel.removeSelectionPath(path); else selectionModel.addSelectionPath(path); - } - finally { + } finally { if (!selectionModel.isSingleEventMode()) { selectionModel.setBatchMode(false); } @@ -370,8 +356,8 @@ public class CheckBoxTree extends JTree { return; } for (int i = 0, length = treePaths.length; i < length; i++) { - TreePath tmpTreePath = treePaths[i]; - toggleSelection(tmpTreePath); + TreePath tmpTreePath = treePaths[i]; + toggleSelection(tmpTreePath); } // for (TreePath treePath : treePaths) { // toggleSelection(treePath); From aaa4c1fb0d5edc54c4680a03e1959425b6bd3919 Mon Sep 17 00:00:00 2001 From: hzzz Date: Wed, 24 May 2017 21:00:29 +0800 Subject: [PATCH 17/41] =?UTF-8?q?REPORT-2773=20mac=E4=B8=AD=E5=A4=8D?= =?UTF-8?q?=E5=88=B6=E5=BF=AB=E6=8D=B7=E9=94=AE=E7=9A=84=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- designer/src/com/fr/design/mainframe/FormatBrushAction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/designer/src/com/fr/design/mainframe/FormatBrushAction.java b/designer/src/com/fr/design/mainframe/FormatBrushAction.java index cf4c98448b..a2daa7902e 100644 --- a/designer/src/com/fr/design/mainframe/FormatBrushAction.java +++ b/designer/src/com/fr/design/mainframe/FormatBrushAction.java @@ -1 +1 @@ -package com.fr.design.mainframe; import com.fr.base.BaseUtils; import com.fr.base.Style; import com.fr.design.actions.ElementCaseAction; import com.fr.general.Inter; import com.fr.grid.selection.CellSelection; import com.fr.grid.selection.Selection; import com.fr.report.cell.DefaultTemplateCellElement; import com.fr.report.cell.TemplateCellElement; import com.fr.report.elementcase.TemplateElementCase; import javax.swing.*; import java.awt.*; import java.awt.event.*; import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; /** * Author : daisy * Date: 13-8-7 * Time: 上午11:05 */ public class FormatBrushAction extends ElementCaseAction { private ElementCasePane ePane; private CellSelection oldSelection; public FormatBrushAction(ElementCasePane t) { super(t); this.setName(Inter.getLocText("M_Edit-FormatBrush")); this.setMnemonic('B'); this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/m_edit/formatBrush.png")); this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B, DEFAULT_MODIFIER)); } public boolean executeActionReturnUndoRecordNeeded() { ePane = (ElementCasePane) getEditingComponent(); if (ePane != null) { Selection selection = ePane.getSelection(); if (!(selection instanceof CellSelection)) { return false; } oldSelection = ((CellSelection) selection).clone(); ePane.setFormatReferencedCell(oldSelection); int cellRectangleCount = oldSelection.getCellRectangleCount(); if (cellRectangleCount > 1) { //格式刷只支持单次选择的区域,如果用ctrl复选选中了多片区域,点击格式刷按钮时弹出提示 //判断是不是连续区域 //荣国是连续区域,那么这些长方形的长加起来应该等于 if (!isContinueArea()) { JOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Inter.getLocText("Can_not_use_FormatBursh")); ePane.setFormatState(DesignerContext.FORMAT_STATE_NULL); ePane.getFormatBrush().setSelected(false); return false; } } //只对单个区域进行格式刷操作 ((ElementCasePane) DesignerContext.getReferencedElementCasePane()).getGrid().setNotShowingTableSelectPane(false); ePane.repaint(); return true; } return false; } /** * 判断是不是连续区域 * * @return */ private boolean isContinueArea() { int xStart = oldSelection.getCellRectangle(1).x; int xend = 0; int yStrat = oldSelection.getCellRectangle(1).y; int yend = 0; int totalNum = 0; for (int i = 0; i < oldSelection.getCellRectangleCount(); i++) { Rectangle temp = oldSelection.getCellRectangle(i); if (temp.getX() < xStart) { xStart = temp.x; } if (temp.getX() + temp.getWidth() > xend) { xend = (int) (temp.getX() + temp.getWidth()); } if (temp.getY() < yStrat) { yStrat = temp.y; } if (temp.getY() + temp.getHeight() > yend) { yend = (int) (temp.getY() + temp.getHeight()); } totalNum += (int) (temp.getWidth() * temp.getHeight()); } if ((xend - xStart) * (yend - yStrat) == totalNum) { oldSelection = new CellSelection(xStart, yStrat, (xend - xStart), (yend - yStrat)); ePane.setSelection(oldSelection); ePane.setFormatReferencedCell(oldSelection); return true; } return false; } public void updateFormatBrush(Style[][] referencedStyle, CellSelection cs, ElementCasePane reportPane) { //得到被参照的单元格的行列数 if (referencedStyle == null) { return; } int rowSpan = referencedStyle[0].length; int columnSpan = referencedStyle.length; //开始进行格式刷样式复制 TemplateElementCase elementCase = reportPane.getEditingElementCase(); int rowNum = cs.getRowSpan(); int columnNum = cs.getColumnSpan(); //如果只点选了一个,则自动补足 if (cs.getColumnSpan() * cs.getRowSpan() == 1) { rowNum = rowSpan; columnNum = columnSpan; } for (int j = 0; j < rowNum; j++) { for (int i = 0; i < columnNum; i++) { int column = i + cs.getColumn(); int row = j + cs.getRow(); TemplateCellElement cellElement = elementCase.getTemplateCellElement(column, row); if (cellElement == null) { cellElement = new DefaultTemplateCellElement(column, row); elementCase.addCellElement(cellElement); } cellElement.setStyle(referencedStyle[i % columnSpan][j % rowSpan]); } } } private Style[][] getOldStyles(CellSelection oldSelection) { Style[][] referencedStyle = new Style[oldSelection.getColumnSpan()][oldSelection.getRowSpan()]; int cellRectangleCount = oldSelection.getCellRectangleCount(); TemplateElementCase elementCase = ePane.getEditingElementCase(); for (int rect = 0; rect < cellRectangleCount; rect++) { Rectangle cellRectangle = oldSelection.getCellRectangle(rect); for (int j = 0; j < cellRectangle.height; j++) { for (int i = 0; i < cellRectangle.width; i++) { int column = i + cellRectangle.x; int row = j + cellRectangle.y; TemplateCellElement cellElement = elementCase.getTemplateCellElement(column, row); if (cellElement == null) { cellElement = new DefaultTemplateCellElement(column, row); elementCase.addCellElement(cellElement); } Style style = cellElement.getStyle(); if (style == null) { style = style.DEFAULT_STYLE; } referencedStyle[i][j] = style; } } } return referencedStyle; } } \ No newline at end of file +package com.fr.design.mainframe; import com.fr.base.BaseUtils; import com.fr.base.Style; import com.fr.design.actions.ElementCaseAction; import com.fr.general.Inter; import com.fr.grid.selection.CellSelection; import com.fr.grid.selection.Selection; import com.fr.report.cell.DefaultTemplateCellElement; import com.fr.report.cell.TemplateCellElement; import com.fr.report.elementcase.TemplateElementCase; import javax.swing.*; import java.awt.*; import java.awt.event.KeyEvent; import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; /** * Author : daisy * Date: 13-8-7 * Time: 上午11:05 */ public class FormatBrushAction extends ElementCaseAction { private ElementCasePane ePane; private CellSelection oldSelection; public FormatBrushAction(ElementCasePane t) { super(t); this.setName(Inter.getLocText("M_Edit-FormatBrush")); this.setMnemonic('B'); this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/m_edit/formatBrush.png")); this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B, DEFAULT_MODIFIER)); } public boolean executeActionReturnUndoRecordNeeded() { ePane = (ElementCasePane) getEditingComponent(); if (ePane != null) { Selection selection = ePane.getSelection(); if (!(selection instanceof CellSelection)) { return false; } oldSelection = ((CellSelection) selection).clone(); ePane.setFormatReferencedCell(oldSelection); int cellRectangleCount = oldSelection.getCellRectangleCount(); if (cellRectangleCount > 1) { //格式刷只支持单次选择的区域,如果用ctrl复选选中了多片区域,点击格式刷按钮时弹出提示 //判断是不是连续区域 //荣国是连续区域,那么这些长方形的长加起来应该等于 if (!isContinueArea()) { JOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Inter.getLocText("Can_not_use_FormatBursh")); ePane.setFormatState(DesignerContext.FORMAT_STATE_NULL); ePane.getFormatBrush().setSelected(false); return false; } } //只对单个区域进行格式刷操作 ((ElementCasePane) DesignerContext.getReferencedElementCasePane()).getGrid().setNotShowingTableSelectPane(false); ePane.repaint(); return true; } return false; } /** * 判断是不是连续区域 * * @return */ private boolean isContinueArea() { int xStart = oldSelection.getCellRectangle(1).x; int xend = 0; int yStrat = oldSelection.getCellRectangle(1).y; int yend = 0; int totalNum = 0; for (int i = 0; i < oldSelection.getCellRectangleCount(); i++) { Rectangle temp = oldSelection.getCellRectangle(i); if (temp.getX() < xStart) { xStart = temp.x; } if (temp.getX() + temp.getWidth() > xend) { xend = (int) (temp.getX() + temp.getWidth()); } if (temp.getY() < yStrat) { yStrat = temp.y; } if (temp.getY() + temp.getHeight() > yend) { yend = (int) (temp.getY() + temp.getHeight()); } totalNum += (int) (temp.getWidth() * temp.getHeight()); } if ((xend - xStart) * (yend - yStrat) == totalNum) { oldSelection = new CellSelection(xStart, yStrat, (xend - xStart), (yend - yStrat)); ePane.setSelection(oldSelection); ePane.setFormatReferencedCell(oldSelection); return true; } return false; } public void updateFormatBrush(Style[][] referencedStyle, CellSelection cs, ElementCasePane reportPane) { //得到被参照的单元格的行列数 if (referencedStyle == null) { return; } int rowSpan = referencedStyle[0].length; int columnSpan = referencedStyle.length; //开始进行格式刷样式复制 TemplateElementCase elementCase = reportPane.getEditingElementCase(); int rowNum = cs.getRowSpan(); int columnNum = cs.getColumnSpan(); //如果只点选了一个,则自动补足 if (cs.getColumnSpan() * cs.getRowSpan() == 1) { rowNum = rowSpan; columnNum = columnSpan; } for (int j = 0; j < rowNum; j++) { for (int i = 0; i < columnNum; i++) { int column = i + cs.getColumn(); int row = j + cs.getRow(); TemplateCellElement cellElement = elementCase.getTemplateCellElement(column, row); if (cellElement == null) { cellElement = new DefaultTemplateCellElement(column, row); elementCase.addCellElement(cellElement); } cellElement.setStyle(referencedStyle[i % columnSpan][j % rowSpan]); } } } private Style[][] getOldStyles(CellSelection oldSelection) { Style[][] referencedStyle = new Style[oldSelection.getColumnSpan()][oldSelection.getRowSpan()]; int cellRectangleCount = oldSelection.getCellRectangleCount(); TemplateElementCase elementCase = ePane.getEditingElementCase(); for (int rect = 0; rect < cellRectangleCount; rect++) { Rectangle cellRectangle = oldSelection.getCellRectangle(rect); for (int j = 0; j < cellRectangle.height; j++) { for (int i = 0; i < cellRectangle.width; i++) { int column = i + cellRectangle.x; int row = j + cellRectangle.y; TemplateCellElement cellElement = elementCase.getTemplateCellElement(column, row); if (cellElement == null) { cellElement = new DefaultTemplateCellElement(column, row); elementCase.addCellElement(cellElement); } Style style = cellElement.getStyle(); if (style == null) { style = style.DEFAULT_STYLE; } referencedStyle[i][j] = style; } } } return referencedStyle; } } \ No newline at end of file From fbc7daed4f64e582f912d20f1621aaab594f76aa Mon Sep 17 00:00:00 2001 From: hzzz Date: Thu, 25 May 2017 09:41:12 +0800 Subject: [PATCH 18/41] =?UTF-8?q?REPORT-2773=20mac=E4=B8=AD=E5=A4=8D?= =?UTF-8?q?=E5=88=B6=E5=BF=AB=E6=8D=B7=E9=94=AE=E7=9A=84=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../design/mainframe/FormatBrushAction.java | 172 +++++++++++++++++- .../fr/design/gui/itextarea/UITextArea.java | 23 ++- .../fr/design/gui/itextfield/UITextField.java | 41 +++-- .../gui/itree/checkboxtree/CheckBoxTree.java | 4 - 4 files changed, 210 insertions(+), 30 deletions(-) diff --git a/designer/src/com/fr/design/mainframe/FormatBrushAction.java b/designer/src/com/fr/design/mainframe/FormatBrushAction.java index a2daa7902e..84bd160ab2 100644 --- a/designer/src/com/fr/design/mainframe/FormatBrushAction.java +++ b/designer/src/com/fr/design/mainframe/FormatBrushAction.java @@ -1 +1,171 @@ -package com.fr.design.mainframe; import com.fr.base.BaseUtils; import com.fr.base.Style; import com.fr.design.actions.ElementCaseAction; import com.fr.general.Inter; import com.fr.grid.selection.CellSelection; import com.fr.grid.selection.Selection; import com.fr.report.cell.DefaultTemplateCellElement; import com.fr.report.cell.TemplateCellElement; import com.fr.report.elementcase.TemplateElementCase; import javax.swing.*; import java.awt.*; import java.awt.event.KeyEvent; import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; /** * Author : daisy * Date: 13-8-7 * Time: 上午11:05 */ public class FormatBrushAction extends ElementCaseAction { private ElementCasePane ePane; private CellSelection oldSelection; public FormatBrushAction(ElementCasePane t) { super(t); this.setName(Inter.getLocText("M_Edit-FormatBrush")); this.setMnemonic('B'); this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/m_edit/formatBrush.png")); this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B, DEFAULT_MODIFIER)); } public boolean executeActionReturnUndoRecordNeeded() { ePane = (ElementCasePane) getEditingComponent(); if (ePane != null) { Selection selection = ePane.getSelection(); if (!(selection instanceof CellSelection)) { return false; } oldSelection = ((CellSelection) selection).clone(); ePane.setFormatReferencedCell(oldSelection); int cellRectangleCount = oldSelection.getCellRectangleCount(); if (cellRectangleCount > 1) { //格式刷只支持单次选择的区域,如果用ctrl复选选中了多片区域,点击格式刷按钮时弹出提示 //判断是不是连续区域 //荣国是连续区域,那么这些长方形的长加起来应该等于 if (!isContinueArea()) { JOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Inter.getLocText("Can_not_use_FormatBursh")); ePane.setFormatState(DesignerContext.FORMAT_STATE_NULL); ePane.getFormatBrush().setSelected(false); return false; } } //只对单个区域进行格式刷操作 ((ElementCasePane) DesignerContext.getReferencedElementCasePane()).getGrid().setNotShowingTableSelectPane(false); ePane.repaint(); return true; } return false; } /** * 判断是不是连续区域 * * @return */ private boolean isContinueArea() { int xStart = oldSelection.getCellRectangle(1).x; int xend = 0; int yStrat = oldSelection.getCellRectangle(1).y; int yend = 0; int totalNum = 0; for (int i = 0; i < oldSelection.getCellRectangleCount(); i++) { Rectangle temp = oldSelection.getCellRectangle(i); if (temp.getX() < xStart) { xStart = temp.x; } if (temp.getX() + temp.getWidth() > xend) { xend = (int) (temp.getX() + temp.getWidth()); } if (temp.getY() < yStrat) { yStrat = temp.y; } if (temp.getY() + temp.getHeight() > yend) { yend = (int) (temp.getY() + temp.getHeight()); } totalNum += (int) (temp.getWidth() * temp.getHeight()); } if ((xend - xStart) * (yend - yStrat) == totalNum) { oldSelection = new CellSelection(xStart, yStrat, (xend - xStart), (yend - yStrat)); ePane.setSelection(oldSelection); ePane.setFormatReferencedCell(oldSelection); return true; } return false; } public void updateFormatBrush(Style[][] referencedStyle, CellSelection cs, ElementCasePane reportPane) { //得到被参照的单元格的行列数 if (referencedStyle == null) { return; } int rowSpan = referencedStyle[0].length; int columnSpan = referencedStyle.length; //开始进行格式刷样式复制 TemplateElementCase elementCase = reportPane.getEditingElementCase(); int rowNum = cs.getRowSpan(); int columnNum = cs.getColumnSpan(); //如果只点选了一个,则自动补足 if (cs.getColumnSpan() * cs.getRowSpan() == 1) { rowNum = rowSpan; columnNum = columnSpan; } for (int j = 0; j < rowNum; j++) { for (int i = 0; i < columnNum; i++) { int column = i + cs.getColumn(); int row = j + cs.getRow(); TemplateCellElement cellElement = elementCase.getTemplateCellElement(column, row); if (cellElement == null) { cellElement = new DefaultTemplateCellElement(column, row); elementCase.addCellElement(cellElement); } cellElement.setStyle(referencedStyle[i % columnSpan][j % rowSpan]); } } } private Style[][] getOldStyles(CellSelection oldSelection) { Style[][] referencedStyle = new Style[oldSelection.getColumnSpan()][oldSelection.getRowSpan()]; int cellRectangleCount = oldSelection.getCellRectangleCount(); TemplateElementCase elementCase = ePane.getEditingElementCase(); for (int rect = 0; rect < cellRectangleCount; rect++) { Rectangle cellRectangle = oldSelection.getCellRectangle(rect); for (int j = 0; j < cellRectangle.height; j++) { for (int i = 0; i < cellRectangle.width; i++) { int column = i + cellRectangle.x; int row = j + cellRectangle.y; TemplateCellElement cellElement = elementCase.getTemplateCellElement(column, row); if (cellElement == null) { cellElement = new DefaultTemplateCellElement(column, row); elementCase.addCellElement(cellElement); } Style style = cellElement.getStyle(); if (style == null) { style = style.DEFAULT_STYLE; } referencedStyle[i][j] = style; } } } return referencedStyle; } } \ No newline at end of file +package com.fr.design.mainframe; + +import com.fr.base.BaseUtils; +import com.fr.base.Style; +import com.fr.design.actions.ElementCaseAction; +import com.fr.general.Inter; +import com.fr.grid.selection.CellSelection; +import com.fr.grid.selection.Selection; +import com.fr.report.cell.DefaultTemplateCellElement; +import com.fr.report.cell.TemplateCellElement; +import com.fr.report.elementcase.TemplateElementCase; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; + +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; + +/** + * Author : daisy + * Date: 13-8-7 + * Time: 上午11:05 + */ +public class FormatBrushAction extends ElementCaseAction { + + private ElementCasePane ePane; + private CellSelection oldSelection; + + + public FormatBrushAction(ElementCasePane t) { + super(t); + this.setName(Inter.getLocText("M_Edit-FormatBrush")); + this.setMnemonic('B'); + this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/m_edit/formatBrush.png")); + this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B, DEFAULT_MODIFIER)); + } + + public boolean executeActionReturnUndoRecordNeeded() { + ePane = (ElementCasePane) getEditingComponent(); + if (ePane != null) { + Selection selection = ePane.getSelection(); + if (!(selection instanceof CellSelection)) { + return false; + } + oldSelection = ((CellSelection) selection).clone(); + ePane.setFormatReferencedCell(oldSelection); + int cellRectangleCount = oldSelection.getCellRectangleCount(); + if (cellRectangleCount > 1) { + //格式刷只支持单次选择的区域,如果用ctrl复选选中了多片区域,点击格式刷按钮时弹出提示 + //判断是不是连续区域 + //荣国是连续区域,那么这些长方形的长加起来应该等于 + if (!isContinueArea()) { + JOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Inter.getLocText("Can_not_use_FormatBursh")); + ePane.setFormatState(DesignerContext.FORMAT_STATE_NULL); + ePane.getFormatBrush().setSelected(false); + return false; + } + } + //只对单个区域进行格式刷操作 + ((ElementCasePane) DesignerContext.getReferencedElementCasePane()).getGrid().setNotShowingTableSelectPane(false); + ePane.repaint(); + return true; + } + return false; + } + + + /** + * 判断是不是连续区域 + * + * @return + */ + private boolean isContinueArea() { + int xStart = oldSelection.getCellRectangle(1).x; + int xend = 0; + int yStrat = oldSelection.getCellRectangle(1).y; + int yend = 0; + int totalNum = 0; + for (int i = 0; i < oldSelection.getCellRectangleCount(); i++) { + Rectangle temp = oldSelection.getCellRectangle(i); + if (temp.getX() < xStart) { + xStart = temp.x; + } + if (temp.getX() + temp.getWidth() > xend) { + xend = (int) (temp.getX() + temp.getWidth()); + } + if (temp.getY() < yStrat) { + yStrat = temp.y; + } + if (temp.getY() + temp.getHeight() > yend) { + yend = (int) (temp.getY() + temp.getHeight()); + } + totalNum += (int) (temp.getWidth() * temp.getHeight()); + } + + if ((xend - xStart) * (yend - yStrat) == totalNum) { + oldSelection = new CellSelection(xStart, yStrat, (xend - xStart), (yend - yStrat)); + ePane.setSelection(oldSelection); + ePane.setFormatReferencedCell(oldSelection); + return true; + } + return false; + } + + + public void updateFormatBrush(Style[][] referencedStyle, CellSelection cs, ElementCasePane reportPane) { + //得到被参照的单元格的行列数 + if (referencedStyle == null) { + return; + } + int rowSpan = referencedStyle[0].length; + int columnSpan = referencedStyle.length; + + //开始进行格式刷样式复制 + TemplateElementCase elementCase = reportPane.getEditingElementCase(); + int rowNum = cs.getRowSpan(); + int columnNum = cs.getColumnSpan(); + + + //如果只点选了一个,则自动补足 + if (cs.getColumnSpan() * cs.getRowSpan() == 1) { + rowNum = rowSpan; + columnNum = columnSpan; + } + + for (int j = 0; j < rowNum; j++) { + for (int i = 0; i < columnNum; i++) { + int column = i + cs.getColumn(); + int row = j + cs.getRow(); + TemplateCellElement cellElement = elementCase.getTemplateCellElement(column, row); + if (cellElement == null) { + cellElement = new DefaultTemplateCellElement(column, row); + elementCase.addCellElement(cellElement); + } + cellElement.setStyle(referencedStyle[i % columnSpan][j % rowSpan]); + } + } + + + } + + + private Style[][] getOldStyles(CellSelection oldSelection) { + Style[][] referencedStyle = new Style[oldSelection.getColumnSpan()][oldSelection.getRowSpan()]; + int cellRectangleCount = oldSelection.getCellRectangleCount(); + TemplateElementCase elementCase = ePane.getEditingElementCase(); + for (int rect = 0; rect < cellRectangleCount; rect++) { + Rectangle cellRectangle = oldSelection.getCellRectangle(rect); + for (int j = 0; j < cellRectangle.height; j++) { + for (int i = 0; i < cellRectangle.width; i++) { + int column = i + cellRectangle.x; + int row = j + cellRectangle.y; + TemplateCellElement cellElement = elementCase.getTemplateCellElement(column, row); + if (cellElement == null) { + cellElement = new DefaultTemplateCellElement(column, row); + elementCase.addCellElement(cellElement); + } + Style style = cellElement.getStyle(); + if (style == null) { + style = style.DEFAULT_STYLE; + } + + referencedStyle[i][j] = style; + } + } + } + + return referencedStyle; + } + +} \ No newline at end of file diff --git a/designer_base/src/com/fr/design/gui/itextarea/UITextArea.java b/designer_base/src/com/fr/design/gui/itextarea/UITextArea.java index 03a70a6ef4..6e04eacb86 100644 --- a/designer_base/src/com/fr/design/gui/itextarea/UITextArea.java +++ b/designer_base/src/com/fr/design/gui/itextarea/UITextArea.java @@ -19,14 +19,21 @@ public class UITextArea extends JTextArea implements UIObserver { public UITextArea(int i, int j) { super(i, j); InputMap inputMap = this.getInputMap(); - inputMap.getParent().put(KeyStroke.getKeyStroke(KeyEvent.VK_A, DEFAULT_MODIFIER), - DefaultEditorKit.selectAllAction); - inputMap.getParent().put(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER), - DefaultEditorKit.copyAction); - inputMap.getParent().put(KeyStroke.getKeyStroke(KeyEvent.VK_V, DEFAULT_MODIFIER), - DefaultEditorKit.pasteAction); - inputMap.getParent().put(KeyStroke.getKeyStroke(KeyEvent.VK_X, DEFAULT_MODIFIER), - DefaultEditorKit.cutAction); + while (inputMap.getParent() != null) { + inputMap = inputMap.getParent(); + } + if (inputMap.get(KeyStroke.getKeyStroke(KeyEvent.VK_A, DEFAULT_MODIFIER)) == null) { + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, DEFAULT_MODIFIER), DefaultEditorKit.selectAllAction); + } + if (inputMap.get(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER)) == null) { + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER), DefaultEditorKit.copyAction); + } + if (inputMap.get(KeyStroke.getKeyStroke(KeyEvent.VK_V, DEFAULT_MODIFIER)) == null) { + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, DEFAULT_MODIFIER), DefaultEditorKit.pasteAction); + } + if (inputMap.get(KeyStroke.getKeyStroke(KeyEvent.VK_X, DEFAULT_MODIFIER)) == null) { + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, DEFAULT_MODIFIER), DefaultEditorKit.cutAction); + } initComponents(); } diff --git a/designer_base/src/com/fr/design/gui/itextfield/UITextField.java b/designer_base/src/com/fr/design/gui/itextfield/UITextField.java index 0af105058b..4f15b1f81b 100644 --- a/designer_base/src/com/fr/design/gui/itextfield/UITextField.java +++ b/designer_base/src/com/fr/design/gui/itextfield/UITextField.java @@ -1,20 +1,19 @@ package com.fr.design.gui.itextfield; -import java.awt.*; -import java.awt.event.KeyEvent; +import com.fr.design.event.GlobalNameListener; +import com.fr.design.event.GlobalNameObserver; +import com.fr.design.event.UIObserver; +import com.fr.design.event.UIObserverListener; +import com.fr.design.utils.gui.GUICoreUtils; +import com.fr.stable.Constants; import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.DefaultEditorKit; import javax.swing.text.Document; - -import com.fr.design.event.GlobalNameListener; -import com.fr.design.event.GlobalNameObserver; -import com.fr.design.event.UIObserver; -import com.fr.design.event.UIObserverListener; -import com.fr.stable.Constants; -import com.fr.design.utils.gui.GUICoreUtils; +import java.awt.*; +import java.awt.event.KeyEvent; import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; @@ -33,14 +32,21 @@ public class UITextField extends JTextField implements UIObserver, GlobalNameObs public UITextField() { super(); InputMap inputMap = this.getInputMap(); - inputMap.getParent().put(KeyStroke.getKeyStroke(KeyEvent.VK_A, DEFAULT_MODIFIER), - DefaultEditorKit.selectAllAction); - inputMap.getParent().put(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER), - DefaultEditorKit.copyAction); - inputMap.getParent().put(KeyStroke.getKeyStroke(KeyEvent.VK_V, DEFAULT_MODIFIER), - DefaultEditorKit.pasteAction); - inputMap.getParent().put(KeyStroke.getKeyStroke(KeyEvent.VK_X, DEFAULT_MODIFIER), - DefaultEditorKit.cutAction); + while (inputMap.getParent() != null) { + inputMap = inputMap.getParent(); + } + if (inputMap.get(KeyStroke.getKeyStroke(KeyEvent.VK_A, DEFAULT_MODIFIER)) == null) { + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, DEFAULT_MODIFIER), DefaultEditorKit.selectAllAction); + } + if (inputMap.get(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER)) == null) { + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER), DefaultEditorKit.copyAction); + } + if (inputMap.get(KeyStroke.getKeyStroke(KeyEvent.VK_V, DEFAULT_MODIFIER)) == null) { + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, DEFAULT_MODIFIER), DefaultEditorKit.pasteAction); + } + if (inputMap.get(KeyStroke.getKeyStroke(KeyEvent.VK_X, DEFAULT_MODIFIER)) == null) { + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, DEFAULT_MODIFIER), DefaultEditorKit.cutAction); + } initListener(); } @@ -197,6 +203,7 @@ public class UITextField extends JTextField implements UIObserver, GlobalNameObs /** * 主函数 + * * @param args 参数 */ public static void main(String... args) { diff --git a/designer_base/src/com/fr/design/gui/itree/checkboxtree/CheckBoxTree.java b/designer_base/src/com/fr/design/gui/itree/checkboxtree/CheckBoxTree.java index a22264477f..941fd962a1 100644 --- a/designer_base/src/com/fr/design/gui/itree/checkboxtree/CheckBoxTree.java +++ b/designer_base/src/com/fr/design/gui/itree/checkboxtree/CheckBoxTree.java @@ -22,8 +22,6 @@ import java.beans.PropertyChangeListener; import java.util.Hashtable; import java.util.Vector; -import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; - /** * CheckBoxTree is a special JTree which uses UICheckBox as the tree renderer. * In addition to regular JTree's features, it also allows you select any number @@ -82,8 +80,6 @@ public class CheckBoxTree extends JTree { public CheckBoxTree(TreeModel newModel) { super(newModel); - InputMap inputMap = this.getInputMap(); - inputMap.getParent().put(KeyStroke.getKeyStroke(KeyEvent.VK_A, DEFAULT_MODIFIER), "selectAll"); init(); } From 487002536ec56a94949f45d8b28c41920a049e63 Mon Sep 17 00:00:00 2001 From: hzzz Date: Thu, 25 May 2017 09:42:21 +0800 Subject: [PATCH 19/41] =?UTF-8?q?REPORT-2773=20mac=E4=B8=AD=E5=A4=8D?= =?UTF-8?q?=E5=88=B6=E5=BF=AB=E6=8D=B7=E9=94=AE=E7=9A=84=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../design/mainframe/FormatBrushAction.java | 340 +++++++++--------- 1 file changed, 170 insertions(+), 170 deletions(-) diff --git a/designer/src/com/fr/design/mainframe/FormatBrushAction.java b/designer/src/com/fr/design/mainframe/FormatBrushAction.java index 84bd160ab2..ddc9e29dcc 100644 --- a/designer/src/com/fr/design/mainframe/FormatBrushAction.java +++ b/designer/src/com/fr/design/mainframe/FormatBrushAction.java @@ -1,171 +1,171 @@ -package com.fr.design.mainframe; - -import com.fr.base.BaseUtils; -import com.fr.base.Style; -import com.fr.design.actions.ElementCaseAction; -import com.fr.general.Inter; -import com.fr.grid.selection.CellSelection; -import com.fr.grid.selection.Selection; -import com.fr.report.cell.DefaultTemplateCellElement; -import com.fr.report.cell.TemplateCellElement; -import com.fr.report.elementcase.TemplateElementCase; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.KeyEvent; - -import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; - -/** - * Author : daisy - * Date: 13-8-7 - * Time: 上午11:05 - */ -public class FormatBrushAction extends ElementCaseAction { - - private ElementCasePane ePane; - private CellSelection oldSelection; - - - public FormatBrushAction(ElementCasePane t) { - super(t); - this.setName(Inter.getLocText("M_Edit-FormatBrush")); - this.setMnemonic('B'); - this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/m_edit/formatBrush.png")); - this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B, DEFAULT_MODIFIER)); - } - - public boolean executeActionReturnUndoRecordNeeded() { - ePane = (ElementCasePane) getEditingComponent(); - if (ePane != null) { - Selection selection = ePane.getSelection(); - if (!(selection instanceof CellSelection)) { - return false; - } - oldSelection = ((CellSelection) selection).clone(); - ePane.setFormatReferencedCell(oldSelection); - int cellRectangleCount = oldSelection.getCellRectangleCount(); - if (cellRectangleCount > 1) { - //格式刷只支持单次选择的区域,如果用ctrl复选选中了多片区域,点击格式刷按钮时弹出提示 - //判断是不是连续区域 - //荣国是连续区域,那么这些长方形的长加起来应该等于 - if (!isContinueArea()) { - JOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Inter.getLocText("Can_not_use_FormatBursh")); - ePane.setFormatState(DesignerContext.FORMAT_STATE_NULL); - ePane.getFormatBrush().setSelected(false); - return false; - } - } - //只对单个区域进行格式刷操作 - ((ElementCasePane) DesignerContext.getReferencedElementCasePane()).getGrid().setNotShowingTableSelectPane(false); - ePane.repaint(); - return true; - } - return false; - } - - - /** - * 判断是不是连续区域 - * - * @return - */ - private boolean isContinueArea() { - int xStart = oldSelection.getCellRectangle(1).x; - int xend = 0; - int yStrat = oldSelection.getCellRectangle(1).y; - int yend = 0; - int totalNum = 0; - for (int i = 0; i < oldSelection.getCellRectangleCount(); i++) { - Rectangle temp = oldSelection.getCellRectangle(i); - if (temp.getX() < xStart) { - xStart = temp.x; - } - if (temp.getX() + temp.getWidth() > xend) { - xend = (int) (temp.getX() + temp.getWidth()); - } - if (temp.getY() < yStrat) { - yStrat = temp.y; - } - if (temp.getY() + temp.getHeight() > yend) { - yend = (int) (temp.getY() + temp.getHeight()); - } - totalNum += (int) (temp.getWidth() * temp.getHeight()); - } - - if ((xend - xStart) * (yend - yStrat) == totalNum) { - oldSelection = new CellSelection(xStart, yStrat, (xend - xStart), (yend - yStrat)); - ePane.setSelection(oldSelection); - ePane.setFormatReferencedCell(oldSelection); - return true; - } - return false; - } - - - public void updateFormatBrush(Style[][] referencedStyle, CellSelection cs, ElementCasePane reportPane) { - //得到被参照的单元格的行列数 - if (referencedStyle == null) { - return; - } - int rowSpan = referencedStyle[0].length; - int columnSpan = referencedStyle.length; - - //开始进行格式刷样式复制 - TemplateElementCase elementCase = reportPane.getEditingElementCase(); - int rowNum = cs.getRowSpan(); - int columnNum = cs.getColumnSpan(); - - - //如果只点选了一个,则自动补足 - if (cs.getColumnSpan() * cs.getRowSpan() == 1) { - rowNum = rowSpan; - columnNum = columnSpan; - } - - for (int j = 0; j < rowNum; j++) { - for (int i = 0; i < columnNum; i++) { - int column = i + cs.getColumn(); - int row = j + cs.getRow(); - TemplateCellElement cellElement = elementCase.getTemplateCellElement(column, row); - if (cellElement == null) { - cellElement = new DefaultTemplateCellElement(column, row); - elementCase.addCellElement(cellElement); - } - cellElement.setStyle(referencedStyle[i % columnSpan][j % rowSpan]); - } - } - - - } - - - private Style[][] getOldStyles(CellSelection oldSelection) { - Style[][] referencedStyle = new Style[oldSelection.getColumnSpan()][oldSelection.getRowSpan()]; - int cellRectangleCount = oldSelection.getCellRectangleCount(); - TemplateElementCase elementCase = ePane.getEditingElementCase(); - for (int rect = 0; rect < cellRectangleCount; rect++) { - Rectangle cellRectangle = oldSelection.getCellRectangle(rect); - for (int j = 0; j < cellRectangle.height; j++) { - for (int i = 0; i < cellRectangle.width; i++) { - int column = i + cellRectangle.x; - int row = j + cellRectangle.y; - TemplateCellElement cellElement = elementCase.getTemplateCellElement(column, row); - if (cellElement == null) { - cellElement = new DefaultTemplateCellElement(column, row); - elementCase.addCellElement(cellElement); - } - Style style = cellElement.getStyle(); - if (style == null) { - style = style.DEFAULT_STYLE; - } - - referencedStyle[i][j] = style; - } - } - } - - return referencedStyle; - } - +package com.fr.design.mainframe; + +import com.fr.base.BaseUtils; +import com.fr.base.Style; +import com.fr.design.actions.ElementCaseAction; +import com.fr.general.Inter; +import com.fr.grid.selection.CellSelection; +import com.fr.grid.selection.Selection; +import com.fr.report.cell.DefaultTemplateCellElement; +import com.fr.report.cell.TemplateCellElement; +import com.fr.report.elementcase.TemplateElementCase; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; + +import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; + +/** + * Author : daisy + * Date: 13-8-7 + * Time: 上午11:05 + */ +public class FormatBrushAction extends ElementCaseAction { + + private ElementCasePane ePane; + private CellSelection oldSelection; + + + public FormatBrushAction(ElementCasePane t) { + super(t); + this.setName(Inter.getLocText("M_Edit-FormatBrush")); + this.setMnemonic('B'); + this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/m_edit/formatBrush.png")); + this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B, DEFAULT_MODIFIER)); + } + + public boolean executeActionReturnUndoRecordNeeded() { + ePane = (ElementCasePane) getEditingComponent(); + if (ePane != null) { + Selection selection = ePane.getSelection(); + if (!(selection instanceof CellSelection)) { + return false; + } + oldSelection = ((CellSelection) selection).clone(); + ePane.setFormatReferencedCell(oldSelection); + int cellRectangleCount = oldSelection.getCellRectangleCount(); + if (cellRectangleCount > 1) { + //格式刷只支持单次选择的区域,如果用ctrl复选选中了多片区域,点击格式刷按钮时弹出提示 + //判断是不是连续区域 + //荣国是连续区域,那么这些长方形的长加起来应该等于 + if (!isContinueArea()) { + JOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Inter.getLocText("Can_not_use_FormatBursh")); + ePane.setFormatState(DesignerContext.FORMAT_STATE_NULL); + ePane.getFormatBrush().setSelected(false); + return false; + } + } + //只对单个区域进行格式刷操作 + ((ElementCasePane) DesignerContext.getReferencedElementCasePane()).getGrid().setNotShowingTableSelectPane(false); + ePane.repaint(); + return true; + } + return false; + } + + + /** + * 判断是不是连续区域 + * + * @return + */ + private boolean isContinueArea() { + int xStart = oldSelection.getCellRectangle(1).x; + int xend = 0; + int yStrat = oldSelection.getCellRectangle(1).y; + int yend = 0; + int totalNum = 0; + for (int i = 0; i < oldSelection.getCellRectangleCount(); i++) { + Rectangle temp = oldSelection.getCellRectangle(i); + if (temp.getX() < xStart) { + xStart = temp.x; + } + if (temp.getX() + temp.getWidth() > xend) { + xend = (int) (temp.getX() + temp.getWidth()); + } + if (temp.getY() < yStrat) { + yStrat = temp.y; + } + if (temp.getY() + temp.getHeight() > yend) { + yend = (int) (temp.getY() + temp.getHeight()); + } + totalNum += (int) (temp.getWidth() * temp.getHeight()); + } + + if ((xend - xStart) * (yend - yStrat) == totalNum) { + oldSelection = new CellSelection(xStart, yStrat, (xend - xStart), (yend - yStrat)); + ePane.setSelection(oldSelection); + ePane.setFormatReferencedCell(oldSelection); + return true; + } + return false; + } + + + public void updateFormatBrush(Style[][] referencedStyle, CellSelection cs, ElementCasePane reportPane) { + //得到被参照的单元格的行列数 + if (referencedStyle == null) { + return; + } + int rowSpan = referencedStyle[0].length; + int columnSpan = referencedStyle.length; + + //开始进行格式刷样式复制 + TemplateElementCase elementCase = reportPane.getEditingElementCase(); + int rowNum = cs.getRowSpan(); + int columnNum = cs.getColumnSpan(); + + + //如果只点选了一个,则自动补足 + if (cs.getColumnSpan() * cs.getRowSpan() == 1) { + rowNum = rowSpan; + columnNum = columnSpan; + } + + for (int j = 0; j < rowNum; j++) { + for (int i = 0; i < columnNum; i++) { + int column = i + cs.getColumn(); + int row = j + cs.getRow(); + TemplateCellElement cellElement = elementCase.getTemplateCellElement(column, row); + if (cellElement == null) { + cellElement = new DefaultTemplateCellElement(column, row); + elementCase.addCellElement(cellElement); + } + cellElement.setStyle(referencedStyle[i % columnSpan][j % rowSpan]); + } + } + + + } + + + private Style[][] getOldStyles(CellSelection oldSelection) { + Style[][] referencedStyle = new Style[oldSelection.getColumnSpan()][oldSelection.getRowSpan()]; + int cellRectangleCount = oldSelection.getCellRectangleCount(); + TemplateElementCase elementCase = ePane.getEditingElementCase(); + for (int rect = 0; rect < cellRectangleCount; rect++) { + Rectangle cellRectangle = oldSelection.getCellRectangle(rect); + for (int j = 0; j < cellRectangle.height; j++) { + for (int i = 0; i < cellRectangle.width; i++) { + int column = i + cellRectangle.x; + int row = j + cellRectangle.y; + TemplateCellElement cellElement = elementCase.getTemplateCellElement(column, row); + if (cellElement == null) { + cellElement = new DefaultTemplateCellElement(column, row); + elementCase.addCellElement(cellElement); + } + Style style = cellElement.getStyle(); + if (style == null) { + style = style.DEFAULT_STYLE; + } + + referencedStyle[i][j] = style; + } + } + } + + return referencedStyle; + } + } \ No newline at end of file From e26becc6847f20291aabcb06f537ec7fb203837c Mon Sep 17 00:00:00 2001 From: hzzz Date: Thu, 25 May 2017 13:52:51 +0800 Subject: [PATCH 20/41] PMD --- .../design/mainframe/FormatBrushAction.java | 2 +- .../autocomplete/AutoCompletePopupWindow.java | 16 +- .../gui/autocomplete/AutoCompletion.java | 2590 ++++++++--------- .../ParameterizedCompletionContext.java | 4 +- .../gui/itabpane/UITabsHeaderIconPane.java | 10 +- .../gui/itree/checkboxtree/CheckBoxTree.java | 6 +- .../com/fr/design/locale/designer.properties | 2 +- .../design/locale/designer_en_US.properties | 2 +- .../design/locale/designer_ja_JP.properties | 2 +- .../design/locale/designer_ko_KR.properties | 2 +- .../design/locale/designer_zh_CN.properties | 2 +- .../design/locale/designer_zh_TW.properties | 2 +- .../widget/editors/DataTableConfigPane.java | 475 +-- 13 files changed, 1552 insertions(+), 1563 deletions(-) diff --git a/designer/src/com/fr/design/mainframe/FormatBrushAction.java b/designer/src/com/fr/design/mainframe/FormatBrushAction.java index ddc9e29dcc..f77bda9eb7 100644 --- a/designer/src/com/fr/design/mainframe/FormatBrushAction.java +++ b/designer/src/com/fr/design/mainframe/FormatBrushAction.java @@ -50,7 +50,7 @@ public class FormatBrushAction extends ElementCaseAction { //判断是不是连续区域 //荣国是连续区域,那么这些长方形的长加起来应该等于 if (!isContinueArea()) { - JOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Inter.getLocText("Can_not_use_FormatBursh")); + JOptionPane.showMessageDialog(DesignerContext.getDesignerFrame(), Inter.getLocText("FR-Designer_Can_not_use_FormatBursh")); ePane.setFormatState(DesignerContext.FORMAT_STATE_NULL); ePane.getFormatBrush().setSelected(false); return false; diff --git a/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletePopupWindow.java b/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletePopupWindow.java index c5efadc5cb..40b3d7ca26 100644 --- a/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletePopupWindow.java +++ b/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletePopupWindow.java @@ -179,7 +179,7 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, } else { doAutocomplete(); } - } else if (AutoCompletion.getDebug()) { + } else if (AutoCompletion.isDebug()) { Thread.dumpStack(); } } @@ -300,7 +300,7 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, */ private void installKeyBindings() { - if (AutoCompletion.getDebug()) { + if (AutoCompletion.isDebug()) { System.out.println("PopupWindow: Installing keybindings"); } @@ -313,7 +313,7 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, ActionMap am = comp.getActionMap(); replaceAction(im, am, KeyEvent.VK_ESCAPE, escapeKap, oldEscape); - if (AutoCompletion.getDebug() && oldEscape.action == escapeKap.action) { + if (AutoCompletion.isDebug() && oldEscape.action == escapeKap.action) { Thread.dumpStack(); } replaceAction(im, am, KeyEvent.VK_UP, upKap, oldUp); @@ -371,7 +371,7 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, */ private void positionDescWindow() { - boolean showDescWindow = descWindow != null && ac.getShowDescWindow(); + boolean showDescWindow = descWindow != null && ac.isShowDescWindow(); if (!showDescWindow) { return; } @@ -604,7 +604,7 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, Rectangle screenBounds = Util.getScreenBoundsForPoint(r.x, r.y); //Dimension screenSize = getToolkit().getScreenSize(); - boolean showDescWindow = descWindow != null && ac.getShowDescWindow(); + boolean showDescWindow = descWindow != null && ac.isShowDescWindow(); int totalH = getHeight(); if (showDescWindow) { totalH = Math.max(totalH, descWindow.getHeight()); @@ -655,7 +655,7 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, installKeyBindings(); lastLine = ac.getLineOfCaret(); selectFirstItem(); - if (descWindow == null && ac.getShowDescWindow()) { + if (descWindow == null && ac.isShowDescWindow()) { descWindow = createDescriptionWindow(); positionDescWindow(); } @@ -693,7 +693,7 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, // because of the way child JWindows' visibility is handled - in // some ways it's dependent on the parent, in other ways it's not. if (descWindow != null) { - descWindow.setVisible(visible && ac.getShowDescWindow()); + descWindow.setVisible(visible && ac.isShowDescWindow()); } } @@ -708,7 +708,7 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, */ private void uninstallKeyBindings() { - if (AutoCompletion.getDebug()) { + if (AutoCompletion.isDebug()) { System.out.println("PopupWindow: Removing keybindings"); } diff --git a/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletion.java b/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletion.java index 122beb1e6b..d5447880b1 100644 --- a/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletion.java +++ b/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletion.java @@ -8,17 +8,17 @@ */ package com.fr.design.gui.autocomplete; -import java.awt.*; -import java.awt.event.*; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.util.List; import javax.swing.*; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.*; +import java.awt.*; +import java.awt.event.*; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.List; import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; @@ -26,20 +26,20 @@ import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_M /** * Adds auto-completion to a text component. Provides a popup window with a * list of auto-complete choices on a given keystroke, such as Crtrl+Space.

- * + *

* Depending on the {@link CompletionProvider} installed, the following * auto-completion features may be enabled: - * + *

*

    - *
  • An auto-complete choices list made visible via e.g. Ctrl+Space
  • - *
  • A "description" window displayed alongside the choices list that - * provides documentation on the currently selected completion choice - * (as seen in Eclipse and NetBeans).
  • - *
  • Parameter assistance. If this is enabled, if the user enters a - * "parameterized" completion, such as a method or a function, then - * they will receive a tool tip describing the arguments they have to - * enter to the completion. Also, the arguments can be navigated via - * tab and shift+tab (a la Eclipse and NetBeans).
  • + *
  • An auto-complete choices list made visible via e.g. Ctrl+Space
  • + *
  • A "description" window displayed alongside the choices list that + * provides documentation on the currently selected completion choice + * (as seen in Eclipse and NetBeans).
  • + *
  • Parameter assistance. If this is enabled, if the user enters a + * "parameterized" completion, such as a method or a function, then + * they will receive a tool tip describing the arguments they have to + * enter to the completion. Also, the arguments can be navigated via + * tab and shift+tab (a la Eclipse and NetBeans).
  • *
* * @author Robert Futrell @@ -53,1293 +53,1277 @@ import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_M */ public class AutoCompletion { - /** - * The text component we're providing completion for. - */ - private JTextComponent textComponent; - - /** - * The parent window of {@link #textComponent}. - */ - private Window parentWindow; - - /** - * The popup window containing completion choices. - */ - private AutoCompletePopupWindow popupWindow; - - /** - * The preferred size of the completion choices window. This field exists - * because the user will likely set the preferred size of the window - * before it is actually created. - */ - private Dimension preferredChoicesWindowSize; - - /** - * The preferred size of the optional description window. This field - * only exists because the user may (and usually will) set the size of - * the description window before it exists (it must be parented to a - * Window). - */ - private Dimension preferredDescWindowSize; - - /** - * Manages any parameterized completions that are inserted. - */ - private ParameterizedCompletionContext pcc; - - /** - * Provides the completion options relevant to the current caret position. - */ - private CompletionProvider provider; - - /** - * The renderer to use for the completion choices. If this is - * null, then a default renderer is used. - */ - private ListCellRenderer renderer; - - /** - * The handler to use when an external URL is clicked in the help - * documentation. - */ - private ExternalURLHandler externalURLHandler; - - /** - * An optional redirector that converts URL's to some other location before - * being handed over to externalURLHandler. - */ - private static LinkRedirector linkRedirector; - - /** - * Whether the description window should be displayed along with the - * completion choice window. - */ - private boolean showDescWindow; - - /** - * Whether auto-complete is enabled. - */ - private boolean autoCompleteEnabled; - - /** - * Whether the auto-activation of auto-complete (after a delay, after the - * user types an appropriate character) is enabled. - */ - private boolean autoActivationEnabled; - - /** - * Whether or not, when there is only a single auto-complete option - * that matches the text at the current text position, that text should - * be auto-inserted, instead of the completion window displaying. - */ - private boolean autoCompleteSingleChoices; - - /** - * Whether parameter assistance is enabled. - */ - private boolean parameterAssistanceEnabled; - - /** - * A renderer used for {@link Completion}s in the optional parameter - * choices popup window (displayed when a {@link ParameterizedCompletion} - * is code-completed). If this isn't set, a default renderer is used. - */ - private ListCellRenderer paramChoicesRenderer; - - /** - * The keystroke that triggers the completion window. - */ - private KeyStroke trigger; - - /** - * The previous key in the text component's InputMap for the - * trigger key. - */ - private Object oldTriggerKey; - - /** - * The action previously assigned to {@link #trigger}, so we can reset it - * if the user disables auto-completion. - */ - private Action oldTriggerAction; - - /** - * The previous key in the text component's InputMap for the - * parameter completion trigger key. - */ - private Object oldParenKey; - - /** - * The action previously assigned to the parameter completion key, so we - * can reset it when we uninstall. - */ - private Action oldParenAction; - - /** - * Listens for events in the parent window that affect the visibility of - * the popup windows. - */ - private ParentWindowListener parentWindowListener; - - /** - * Listens for events from the text component that affect the visibility - * of the popup windows. - */ - private TextComponentListener textComponentListener; - - /** - * Listens for events in the text component that cause the popup windows - * to automatically activate. - */ - private AutoActivationListener autoActivationListener; - - /** - * Listens for LAF changes so the auto-complete windows automatically - * update themselves accordingly. - */ - private LookAndFeelChangeListener lafListener; - - /** - * The key used in the input map for the AutoComplete action. - */ - private static final String PARAM_TRIGGER_KEY = "AutoComplete"; - - /** - * Key used in the input map for the parameter completion action. - */ - private static final String PARAM_COMPLETE_KEY = "AutoCompletion.FunctionStart"; - - /** - * Stores how to render auto-completion-specific highlights in text - * components. - */ - private static final AutoCompletionStyleContext styleContext = - new AutoCompletionStyleContext(); - - /** - * Whether debug messages should be printed to stdout as AutoCompletion - * runs. - */ - private static final boolean DEBUG = initDebug(); - - - /** - * Constructor. - * - * @param provider The completion provider. This cannot be - * null. - */ - public AutoCompletion(CompletionProvider provider) { - - setChoicesWindowSize(350, 200); - setDescriptionWindowSize(350, 250); - - setCompletionProvider(provider); - setTriggerKey(getDefaultTriggerKey()); - setAutoCompleteEnabled(true); - setAutoCompleteSingleChoices(true); - setAutoActivationEnabled(false); - setShowDescWindow(false); - parentWindowListener = new ParentWindowListener(); - textComponentListener = new TextComponentListener(); - autoActivationListener = new AutoActivationListener(); - lafListener = new LookAndFeelChangeListener(); - - } - - - /** - * Displays the popup window. Hosting applications can call this method - * to programmatically begin an auto-completion operation. - */ - public void doCompletion() { - refreshPopupWindow(); - } - - - /** - * Returns the delay between when the user types a character and when the - * code completion popup should automatically appear (if applicable). - * - * @return The delay, in milliseconds. - * @see #setAutoActivationDelay(int) - */ - public int getAutoActivationDelay() { - return autoActivationListener.timer.getDelay(); - } - - - /** - * Returns whether, if a single auto-complete choice is available, it - * should be automatically inserted, without displaying the popup menu. - * - * @return Whether to auto-complete single choices. - * @see #setAutoCompleteSingleChoices(boolean) - */ - public boolean getAutoCompleteSingleChoices() { - return autoCompleteSingleChoices; - } - - - /** - * Returns the completion provider. - * - * @return The completion provider. - */ - public CompletionProvider getCompletionProvider() { - return provider; - } - - - /** - * Returns whether debug is enabled for AutoCompletion. - * - * @return Whether debug is enabled. - */ - static boolean getDebug() { - return DEBUG; - } - - - /** - * Returns the default auto-complete "trigger key" for this OS. For - * Windows, for example, it is Ctrl+Space. - * - * @return The default auto-complete trigger key. - */ - public static KeyStroke getDefaultTriggerKey() { - // Default to CTRL, even on Mac, since Ctrl+Space activates Spotlight - return KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, DEFAULT_MODIFIER); - } - - - /** - * Returns the handler to use when an external URL is clicked in the - * description window. - * - * @return The handler. - * @see #setExternalURLHandler(ExternalURLHandler) - * @see #getLinkRedirector() - */ - public ExternalURLHandler getExternalURLHandler() { - return externalURLHandler; - } - - - int getLineOfCaret() { - Document doc = textComponent.getDocument(); - Element root = doc.getDefaultRootElement(); - return root.getElementIndex(textComponent.getCaretPosition()); - } - - - /** - * Returns the link redirector, if any. - * - * @return The link redirector, or null if none. - * @see #setLinkRedirector(LinkRedirector) - */ - public static LinkRedirector getLinkRedirector() { - return linkRedirector; - } - - - /** - * Returns the default list cell renderer used when a completion provider - * does not supply its own. - * - * @return The default list cell renderer. - * @see #setListCellRenderer(ListCellRenderer) - */ - public ListCellRenderer getListCellRenderer() { - return renderer; - } - - - /** - * Returns the renderer to use for {@link Completion}s in the optional - * parameter choices popup window (displayed when a - * {@link ParameterizedCompletion} is code-completed). If this returns - * null, a default renderer is used. - * - * @return The renderer to use. - * @see #setParamChoicesRenderer(ListCellRenderer) - * @see #isParameterAssistanceEnabled() - */ - public ListCellRenderer getParamChoicesRenderer() { - return paramChoicesRenderer; - } - - - /** - * Returns the text to replace with in the document. This is a - * "last-chance" hook for subclasses to make special modifications to the - * completion text inserted. The default implementation simply returns - * c.getReplacementText(). You usually will not need to modify - * this method. - * - * @param c The completion being inserted. - * @param doc The document being modified. - * @param start The start of the text being replaced. - * @param len The length of the text being replaced. - * @return The text to replace with. - */ - protected String getReplacementText(Completion c, Document doc, int start, - int len) { - return c.getReplacementText(); - } - - - /** - * Returns whether the "description window" should be shown alongside - * the completion window. - * - * @return Whether the description window should be shown. - * @see #setShowDescWindow(boolean) - */ - public boolean getShowDescWindow() { - return showDescWindow; - } - - - /** - * Returns the style context describing how auto-completion related - * highlights in the editor are rendered. - * - * @return The style context. - */ - public static AutoCompletionStyleContext getStyleContext() { - return styleContext; - } - - - /** - * Returns the text component for which auto-completion is enabled. - * - * @return The text component, or null if this - * {@link AutoCompletion} is not installed on any text component. - * @see #install(JTextComponent) - */ - public JTextComponent getTextComponent() { - return textComponent; - } - - - /** - * Returns the orientation of the text component we're installed to. - * - * @return The orientation of the text component, or null if - * we are not installed on one. - */ - ComponentOrientation getTextComponentOrientation() { - return textComponent==null ? null : - textComponent.getComponentOrientation(); - } - - - /** - * Returns the "trigger key" used for auto-complete. - * - * @return The trigger key. - * @see #setTriggerKey(KeyStroke) - */ - public KeyStroke getTriggerKey() { - return trigger; - } - - - /** - * Hides any child windows being displayed by the auto-completion system. - * - * @return Whether any windows were visible. - */ - public boolean hideChildWindows() { - //return hidePopupWindow() || hideToolTipWindow(); - boolean res = hidePopupWindow(); - res |= hideParameterCompletionPopups(); - return res; - } - - - /** - * Hides and disposes of any parameter completion-related popups. - * - * @return Whether any such windows were visible (and thus hidden). - */ - private boolean hideParameterCompletionPopups() { - if (pcc!=null) { - pcc.deactivate(); - pcc = null; - return true; - } - return false; - } - - - /** - * Hides the popup window, if it is visible. - * - * @return Whether the popup window was visible. - */ - private boolean hidePopupWindow() { - if (popupWindow!=null) { - if (popupWindow.isVisible()) { - popupWindow.setVisible(false); - return true; - } - } - return false; - } - - - /** - * Determines whether debug should be enabled for the AutoCompletion - * library. This method checks a system property, but takes care of - * {@link SecurityException}s in case we're in an applet or WebStart. - * - * @return Whether debug should be enabled. - */ - private static final boolean initDebug() { - boolean debug = false; - try { - debug = Boolean.getBoolean("AutoCompletion.debug"); - } catch (SecurityException se) { // We're in an applet or WebStart. - debug = false; - } - return debug; - } - - - /** - * Inserts a completion. Any time a code completion event occurs, the - * actual text insertion happens through this method. - * - * @param c A completion to insert. This cannot be null. - */ - protected final void insertCompletion(Completion c) { - insertCompletion(c, false); - } - - - /** - * Inserts a completion. Any time a code completion event occurs, the - * actual text insertion happens through this method. - * - * @param c A completion to insert. This cannot be null. - * @param typedParamListStartChar Whether the parameterized completion - * start character was typed (typically '('). - */ - protected void insertCompletion(Completion c, - boolean typedParamListStartChar) { - - JTextComponent textComp = getTextComponent(); - String alreadyEntered = c.getAlreadyEntered(textComp); - hidePopupWindow(); - Caret caret = textComp.getCaret(); - - int dot = caret.getDot(); - int len = alreadyEntered.length(); - int start = dot-len; - String replacement = getReplacementText(c, textComp.getDocument(), - start, len); - - caret.setDot(start); - caret.moveDot(dot); - textComp.replaceSelection(replacement); - - if (isParameterAssistanceEnabled() && - (c instanceof ParameterizedCompletion)) { - ParameterizedCompletion pc = (ParameterizedCompletion)c; - startParameterizedCompletionAssistance(pc, typedParamListStartChar); - } - - } - - - /** - * Installs this auto-completion on a text component. If this - * {@link AutoCompletion} is already installed on another text component, - * it is uninstalled first. - * - * @param c The text component. - * @see #uninstall() - */ - public void install(JTextComponent c) { - - if (textComponent!=null) { - uninstall(); - } - - this.textComponent = c; - installTriggerKey(getTriggerKey()); - - // Install the function completion key, if there is one. - // NOTE: We cannot do this if the start char is ' ' (e.g. just a space - // between the function name and parameters) because it overrides - // RSTA's special space action. It seems KeyStorke.getKeyStroke(' ') - // hoses ctrl+space, shift+space, etc., even though I think it - // shouldn't... - char start = provider.getParameterListStart(); - if (start!=0 && start!=' ') { - InputMap im = c.getInputMap(); - ActionMap am = c.getActionMap(); - KeyStroke ks = KeyStroke.getKeyStroke(start); - oldParenKey = im.get(ks); - im.put(ks, PARAM_COMPLETE_KEY); - oldParenAction = am.get(PARAM_COMPLETE_KEY); - am.put(PARAM_COMPLETE_KEY, - new ParameterizedCompletionStartAction(start)); - } - - textComponentListener.addTo(this.textComponent); - // In case textComponent is already in a window... - textComponentListener.hierarchyChanged(null); - - if (isAutoActivationEnabled()) { - autoActivationListener.addTo(this.textComponent); - } - - UIManager.addPropertyChangeListener(lafListener); - updateUI(); // In case there have been changes since we uninstalled - - } - - - /** - * Installs a "trigger key" action onto the current text component. - * - * @param ks The keystroke that should trigger the action. - * @see #uninstallTriggerKey() - */ - private void installTriggerKey(KeyStroke ks) { - InputMap im = textComponent.getInputMap(); - oldTriggerKey = im.get(ks); - im.put(ks, PARAM_TRIGGER_KEY); - ActionMap am = textComponent.getActionMap(); - oldTriggerAction = am.get(PARAM_TRIGGER_KEY); - am.put(PARAM_TRIGGER_KEY, new AutoCompleteAction()); - } - - - /** - * Returns whether auto-activation is enabled (that is, whether the - * completion popup will automatically appear after a delay when the user - * types an appropriate character). Note that this parameter will be - * ignored if auto-completion is disabled. - * - * @return Whether auto-activation is enabled. - * @see #setAutoActivationEnabled(boolean) - * @see #getAutoActivationDelay() - * @see #isAutoCompleteEnabled() - */ - public boolean isAutoActivationEnabled() { - return autoActivationEnabled; - } - - - /** - * Returns whether auto-completion is enabled. - * - * @return Whether auto-completion is enabled. - * @see #setAutoCompleteEnabled(boolean) - */ - public boolean isAutoCompleteEnabled() { - return autoCompleteEnabled; - } - - - /** - * Returns whether parameter assistance is enabled. - * - * @return Whether parameter assistance is enabled. - * @see #setParameterAssistanceEnabled(boolean) - */ - public boolean isParameterAssistanceEnabled() { - return parameterAssistanceEnabled; - } - - - /** - * Returns whether the completion popup window is visible. - * - * @return Whether the completion popup window is visible. - */ - public boolean isPopupVisible() { - return popupWindow!=null && popupWindow.isVisible(); - } - - - /** - * Refreshes the popup window. First, this method gets the possible - * completions for the current caret position. If there are none, and the - * popup is visible, it is hidden. If there are some completions and the - * popup is hidden, it is made visible and made to display the completions. - * If there are some completions and the popup is visible, its list is - * updated to the current set of completions. - * - * @return The current line number of the caret. - */ - protected int refreshPopupWindow() { - - // A return value of null => don't suggest completions - String text = provider.getAlreadyEnteredText(textComponent); - if (text==null && !isPopupVisible()) { - return getLineOfCaret(); - } - - // If the popup is currently visible, and they type a space (or any - // character that resets the completion list to "all completions"), - // the popup window should be hidden instead of being reset to show - // everything. - int textLen = text==null ? 0 : text.length(); - if (textLen==0) { - if (isPopupVisible()) { - hidePopupWindow(); - return getLineOfCaret(); - } - } - - final List completions = provider. - getCompletions(textComponent); - int count = completions.size(); - - if (count>1 || (count==1 && (isPopupVisible() || textLen==0)) || - (count==1 && !getAutoCompleteSingleChoices())) { - - if (popupWindow==null) { - popupWindow = new AutoCompletePopupWindow(parentWindow, this); - // Completion is usually done for code, which is always done - // LTR, so make completion stuff RTL only if text component is - // also RTL. - popupWindow.applyComponentOrientation( - getTextComponentOrientation()); - if (renderer!=null) { - popupWindow.setListCellRenderer(renderer); - } - if (preferredChoicesWindowSize!=null) { - popupWindow.setSize(preferredChoicesWindowSize); - } - if (preferredDescWindowSize!=null) { - popupWindow.setDescriptionWindowSize( - preferredDescWindowSize); - } - } - - popupWindow.setCompletions(completions); - - if (!popupWindow.isVisible()) { - Rectangle r = null; - try { - r = textComponent.modelToView(textComponent. - getCaretPosition()); - } catch (BadLocationException ble) { - - return -1; - } - Point p = new Point(r.x, r.y); - SwingUtilities.convertPointToScreen(p, textComponent); - r.x = p.x; - r.y = p.y; - popupWindow.setLocationRelativeTo(r); - popupWindow.setVisible(true); - } - - } - - else if (count==1) { // !isPopupVisible && autoCompleteSingleChoices - SwingUtilities.invokeLater(new Runnable() { - public void run() { - insertCompletion(completions.get(0)); - } - }); - } - - else { - hidePopupWindow(); - } - - return getLineOfCaret(); - - } - - - /** - * Sets the delay between when the user types a character and when the - * code completion popup should automatically appear (if applicable). - * - * @param ms The delay, in milliseconds. This should be greater than zero. - * @see #getAutoActivationDelay() - */ - public void setAutoActivationDelay(int ms) { - ms = Math.max(0, ms); - autoActivationListener.timer.stop(); - autoActivationListener.timer.setInitialDelay(ms); - } - - - /** - * Toggles whether auto-activation is enabled. Note that auto-activation - * also depends on auto-completion itself being enabled. - * - * @param enabled Whether auto-activation is enabled. - * @see #isAutoActivationEnabled() - * @see #setAutoActivationDelay(int) - */ - public void setAutoActivationEnabled(boolean enabled) { - if (enabled!=autoActivationEnabled) { - autoActivationEnabled = enabled; - if (textComponent!=null) { - if (autoActivationEnabled) { - autoActivationListener.addTo(textComponent); - } - else { - autoActivationListener.removeFrom(textComponent); - } - } - } - } - - - /** - * Sets whether auto-completion is enabled. - * - * @param enabled Whether auto-completion is enabled. - * @see #isAutoCompleteEnabled() - */ - public void setAutoCompleteEnabled(boolean enabled) { - if (enabled!=autoCompleteEnabled) { - autoCompleteEnabled = enabled; - hidePopupWindow(); - } - } - - - /** - * Sets whether, if a single auto-complete choice is available, it should - * be automatically inserted, without displaying the popup menu. - * - * @param autoComplete Whether to auto-complete single choices. - * @see #getAutoCompleteSingleChoices() - */ - public void setAutoCompleteSingleChoices(boolean autoComplete) { - autoCompleteSingleChoices = autoComplete; - } - - - /** - * Sets the completion provider being used. - * - * @param provider The new completion provider. This cannot be - * null. - * @throws IllegalArgumentException If provider is - * null. - */ - public void setCompletionProvider(CompletionProvider provider) { - if (provider==null) { - throw new IllegalArgumentException("provider cannot be null"); - } - this.provider = provider; - hidePopupWindow(); // In case new choices should be displayed. - } - - - /** - * Sets the size of the completion choices window. - * - * @param w The new width. - * @param h The new height. - * @see #setDescriptionWindowSize(int, int) - */ - public void setChoicesWindowSize(int w, int h) { - preferredChoicesWindowSize = new Dimension(w, h); - if (popupWindow!=null) { - popupWindow.setSize(preferredChoicesWindowSize); - } - } - - - /** - * Sets the size of the description window. - * - * @param w The new width. - * @param h The new height. - * @see #setChoicesWindowSize(int, int) - */ - public void setDescriptionWindowSize(int w, int h) { - preferredDescWindowSize = new Dimension(w, h); - if (popupWindow!=null) { - popupWindow.setDescriptionWindowSize(preferredDescWindowSize); - } - } - - - /** - * Sets the handler to use when an external URL is clicked in the - * description window. This handler can perform some action, such as - * open the URL in a web browser. The default implementation will open - * the URL in a browser, but only if running in Java 6. If you want - * browser support for Java 5 and below, or otherwise want to respond to - * hyperlink clicks, you will have to install your own handler to do so. - * - * @param handler The new handler. - * @see #getExternalURLHandler() - */ - public void setExternalURLHandler(ExternalURLHandler handler) { - this.externalURLHandler = handler; - } - - - /** - * Sets the redirector for external URL's found in code completion - * documentation. When a non-local link in completion popups is clicked, - * this redirector is given the chance to modify the URL fetched and - * displayed. - * - * @param linkRedirector The link redirector, or null for - * none. - * @see #getLinkRedirector() - */ - public static void setLinkRedirector(LinkRedirector linkRedirector) { - AutoCompletion.linkRedirector = linkRedirector; - } - - - /** - * Sets the default list cell renderer to use when a completion provider - * does not supply its own. - * - * @param renderer The renderer to use. If this is null, - * a default renderer is used. - * @see #getListCellRenderer() - */ - public void setListCellRenderer(ListCellRenderer renderer) { - this.renderer = renderer; - if (popupWindow!=null) { - popupWindow.setListCellRenderer(renderer); - hidePopupWindow(); - } - } - - - /** - * Sets the renderer to use for {@link Completion}s in the optional - * parameter choices popup window (displayed when a - * {@link ParameterizedCompletion} is code-completed). If this isn't set, - * a default renderer is used. - * - * @param r The renderer to use. - * @see #getParamChoicesRenderer() - * @see #setParameterAssistanceEnabled(boolean) - */ - public void setParamChoicesRenderer(ListCellRenderer r) { - paramChoicesRenderer = r; - } - - - /** - * Sets whether parameter assistance is enabled. If parameter assistance - * is enabled, and a "parameterized" completion (such as a function or - * method) is inserted, the user will get "assistance" in inserting the - * parameters in the form of a popup window with documentation and easy - * tabbing through the arguments (as seen in Eclipse and NetBeans). - * - * @param enabled Whether parameter assistance should be enabled. - * @see #isParameterAssistanceEnabled() - */ - public void setParameterAssistanceEnabled(boolean enabled) { - parameterAssistanceEnabled = enabled; - } - - - /** - * Sets whether the "description window" should be shown beside the - * completion window. - * - * @param show Whether to show the description window. - * @see #getShowDescWindow() - */ - public void setShowDescWindow(boolean show) { - hidePopupWindow(); // Needed to force it to take effect - showDescWindow = show; - } - - - /** - * Sets the keystroke that should be used to trigger the auto-complete - * popup window. - * - * @param ks The keystroke. - * @throws IllegalArgumentException If ks is null. - * @see #getTriggerKey() - */ - public void setTriggerKey(KeyStroke ks) { - if (ks==null) { - throw new IllegalArgumentException("trigger key cannot be null"); - } - if (!ks.equals(trigger)) { - if (textComponent!=null) { - // Put old trigger action back. - uninstallTriggerKey(); - // Grab current action for new trigger and replace it. - installTriggerKey(ks); - } - trigger = ks; - } - } - - - /** - * Displays a "tool tip" detailing the inputs to the function just entered. - * - * @param pc The completion. - * @param typedParamListStartChar Whether the parameterized completion list - * starting character was typed. - */ - private void startParameterizedCompletionAssistance( - ParameterizedCompletion pc, boolean typedParamListStartChar) { - - // Get rid of the previous tool tip window, if there is one. - hideParameterCompletionPopups(); - - // Don't bother with a tool tip if there are no parameters, but if - // they typed e.g. the opening '(', make them overtype the ')'. - if (pc.getParamCount()==0 && !(pc instanceof TemplateCompletion)) { - CompletionProvider p = pc.getProvider(); - char end = p.getParameterListEnd(); // Might be '\0' - String text = end=='\0' ? "" : Character.toString(end); - if (typedParamListStartChar) { - String template = "${}" + text + "${cursor}"; - textComponent.replaceSelection(Character.toString(p.getParameterListStart())); - TemplateCompletion tc = new TemplateCompletion(p, null, null, template); - pc = tc; - } - else { - text = p.getParameterListStart() + text; - textComponent.replaceSelection(text); - return; - } - } - - pcc = new ParameterizedCompletionContext(parentWindow, this, pc); - pcc.activate(); - - } - - - /** - * Uninstalls this auto-completion from its text component. If it is not - * installed on any text component, nothing happens. - * - * @see #install(JTextComponent) - */ - public void uninstall() { - - if (textComponent!=null) { - - hidePopupWindow(); // Unregisters listeners, actions, etc. - - uninstallTriggerKey(); - - // Uninstall the function completion key. - char start = provider.getParameterListStart(); - if (start!=0) { - KeyStroke ks = KeyStroke.getKeyStroke(start); - InputMap im = textComponent.getInputMap(); - im.put(ks, oldParenKey); - ActionMap am = textComponent.getActionMap(); - am.put(PARAM_COMPLETE_KEY, oldParenAction); - } - - textComponentListener.removeFrom(textComponent); - if (parentWindow!=null) { - parentWindowListener.removeFrom(parentWindow); - } - - if (isAutoActivationEnabled()) { - autoActivationListener.removeFrom(textComponent); - } - - UIManager.removePropertyChangeListener(lafListener); - - textComponent = null; - popupWindow = null; - - } - - } - - - /** - * Replaces the "trigger key" action with the one that was there - * before auto-completion was installed. - * - * @see #installTriggerKey(KeyStroke) - */ - private void uninstallTriggerKey() { - InputMap im = textComponent.getInputMap(); - im.put(trigger, oldTriggerKey); - ActionMap am = textComponent.getActionMap(); - am.put(PARAM_TRIGGER_KEY, oldTriggerAction); - } - - - /** - * Updates the LookAndFeel of the popup window. Applications can call - * this method as appropriate if they support changing the LookAndFeel - * at runtime. - */ - private void updateUI() { - if (popupWindow!=null) { - popupWindow.updateUI(); - } - if (pcc!=null) { - pcc.updateUI(); - } - // Will practically always be a JComponent (a JLabel) - if (paramChoicesRenderer instanceof JComponent) { - ((JComponent)paramChoicesRenderer).updateUI(); - } - } - - - /** - * Listens for events in the text component to auto-activate the code - * completion popup. - */ - private class AutoActivationListener extends FocusAdapter - implements DocumentListener, CaretListener, ActionListener { - - private Timer timer; - private boolean justInserted; - - public AutoActivationListener() { - timer = new Timer(200, this); - timer.setRepeats(false); - } - - public void actionPerformed(ActionEvent e) { - doCompletion(); - } - - public void addTo(JTextComponent tc) { - tc.addFocusListener(this); - tc.getDocument().addDocumentListener(this); - tc.addCaretListener(this); - } - - public void caretUpdate(CaretEvent e) { - if (justInserted) { - justInserted = false; - } - else { - timer.stop(); - } - } - - public void changedUpdate(DocumentEvent e) { - // Ignore - } - - @Override - public void focusLost(FocusEvent e) { - timer.stop(); - //hideChildWindows(); Other listener will do this - } - - public void insertUpdate(DocumentEvent e) { - justInserted = false; - if (isAutoCompleteEnabled() && isAutoActivationEnabled() && - e.getLength()==1) { - if (provider.isAutoActivateOkay(textComponent)) { - timer.restart(); - justInserted = true; - } - else { - timer.stop(); - } - } - else { - timer.stop(); - } - } - - public void removeFrom(JTextComponent tc) { - tc.removeFocusListener(this); - tc.getDocument().removeDocumentListener(this); - tc.removeCaretListener(this); - timer.stop(); - justInserted = false; - } - - public void removeUpdate(DocumentEvent e) { - timer.stop(); - } - - } - - - /** - * The Action that displays the popup window if - * auto-completion is enabled. - */ - private class AutoCompleteAction extends AbstractAction { - - public void actionPerformed(ActionEvent e) { - if (isAutoCompleteEnabled()) { - refreshPopupWindow(); - } - else if (oldTriggerAction!=null) { - oldTriggerAction.actionPerformed(e); - } - } - - } - - - /** - * Listens for LookAndFeel changes and updates the various popup windows - * involved in auto-completion accordingly. - */ - private class LookAndFeelChangeListener implements PropertyChangeListener { - - public void propertyChange(PropertyChangeEvent e) { - String name = e.getPropertyName(); - if ("lookAndFeel".equals(name)) { - updateUI(); - } - } - - } - - - /** - * Action that starts a parameterized completion, e.g. after '(' is - * typed. - */ - private class ParameterizedCompletionStartAction extends AbstractAction { - - private String start; - - public ParameterizedCompletionStartAction(char ch) { - this.start = Character.toString(ch); - } - - public void actionPerformed(ActionEvent e) { - - // Prevents keystrokes from messing up - boolean wasVisible = hidePopupWindow(); - - // Only proceed if they were selecting a completion - if (!wasVisible || !isParameterAssistanceEnabled()) { - textComponent.replaceSelection(start); - return; - } - - Completion c = popupWindow.getSelection(); - if (c instanceof ParameterizedCompletion) { // Should always be true - // Fixes capitalization of the entered text. - insertCompletion(c, true); - } - - } - - } - - - /** - * Listens for events in the parent window of the text component with - * auto-completion enabled. - */ - private class ParentWindowListener extends ComponentAdapter - implements WindowFocusListener { - - public void addTo(Window w) { - w.addComponentListener(this); - w.addWindowFocusListener(this); - } - - @Override - public void componentHidden(ComponentEvent e) { - hideChildWindows(); - } - - @Override - public void componentMoved(ComponentEvent e) { - hideChildWindows(); - } - - @Override - public void componentResized(ComponentEvent e) { - hideChildWindows(); - } - - public void removeFrom(Window w) { - w.removeComponentListener(this); - w.removeWindowFocusListener(this); - } - - public void windowGainedFocus(WindowEvent e) { - } - - public void windowLostFocus(WindowEvent e) { - hideChildWindows(); - } - - } - - - /** - * Listens for events from the text component we're installed on. - */ - private class TextComponentListener extends FocusAdapter - implements HierarchyListener { - - void addTo(JTextComponent tc) { - tc.addFocusListener(this); - tc.addHierarchyListener(this); - } - - /** - * Hide the auto-completion windows when the text component loses - * focus. - */ - @Override - public void focusLost(FocusEvent e) { - hideChildWindows(); - } - - /** - * Called when the component hierarchy for our text component changes. - * When the text component is added to a new {@link Window}, this - * method registers listeners on that Window. - * - * @param e The event. - */ - public void hierarchyChanged(HierarchyEvent e) { - - // NOTE: e many be null as we call this method at other times. - //System.out.println("Hierarchy changed! " + e); - - Window oldParentWindow = parentWindow; - parentWindow = SwingUtilities.getWindowAncestor(textComponent); - if (parentWindow!=oldParentWindow) { - if (oldParentWindow!=null) { - parentWindowListener.removeFrom(oldParentWindow); - } - if (parentWindow!=null) { - parentWindowListener.addTo(parentWindow); - } - } - - } - - public void removeFrom(JTextComponent tc) { - tc.removeFocusListener(this); - tc.removeHierarchyListener(this); - } - - } + /** + * The text component we're providing completion for. + */ + private JTextComponent textComponent; + + /** + * The parent window of {@link #textComponent}. + */ + private Window parentWindow; + + /** + * The popup window containing completion choices. + */ + private AutoCompletePopupWindow popupWindow; + + /** + * The preferred size of the completion choices window. This field exists + * because the user will likely set the preferred size of the window + * before it is actually created. + */ + private Dimension preferredChoicesWindowSize; + + /** + * The preferred size of the optional description window. This field + * only exists because the user may (and usually will) set the size of + * the description window before it exists (it must be parented to a + * Window). + */ + private Dimension preferredDescWindowSize; + + /** + * Manages any parameterized completions that are inserted. + */ + private ParameterizedCompletionContext pcc; + + /** + * Provides the completion options relevant to the current caret position. + */ + private CompletionProvider provider; + + /** + * The renderer to use for the completion choices. If this is + * null, then a default renderer is used. + */ + private ListCellRenderer renderer; + + /** + * The handler to use when an external URL is clicked in the help + * documentation. + */ + private ExternalURLHandler externalURLHandler; + + /** + * An optional redirector that converts URL's to some other location before + * being handed over to externalURLHandler. + */ + private static LinkRedirector linkRedirector; + + /** + * Whether the description window should be displayed along with the + * completion choice window. + */ + private boolean showDescWindow; + + /** + * Whether auto-complete is enabled. + */ + private boolean autoCompleteEnabled; + + /** + * Whether the auto-activation of auto-complete (after a delay, after the + * user types an appropriate character) is enabled. + */ + private boolean autoActivationEnabled; + + /** + * Whether or not, when there is only a single auto-complete option + * that matches the text at the current text position, that text should + * be auto-inserted, instead of the completion window displaying. + */ + private boolean autoCompleteSingleChoices; + + /** + * Whether parameter assistance is enabled. + */ + private boolean parameterAssistanceEnabled; + + /** + * A renderer used for {@link Completion}s in the optional parameter + * choices popup window (displayed when a {@link ParameterizedCompletion} + * is code-completed). If this isn't set, a default renderer is used. + */ + private ListCellRenderer paramChoicesRenderer; + + /** + * The keystroke that triggers the completion window. + */ + private KeyStroke trigger; + + /** + * The previous key in the text component's InputMap for the + * trigger key. + */ + private Object oldTriggerKey; + + /** + * The action previously assigned to {@link #trigger}, so we can reset it + * if the user disables auto-completion. + */ + private Action oldTriggerAction; + + /** + * The previous key in the text component's InputMap for the + * parameter completion trigger key. + */ + private Object oldParenKey; + + /** + * The action previously assigned to the parameter completion key, so we + * can reset it when we uninstall. + */ + private Action oldParenAction; + + /** + * Listens for events in the parent window that affect the visibility of + * the popup windows. + */ + private ParentWindowListener parentWindowListener; + + /** + * Listens for events from the text component that affect the visibility + * of the popup windows. + */ + private TextComponentListener textComponentListener; + + /** + * Listens for events in the text component that cause the popup windows + * to automatically activate. + */ + private AutoActivationListener autoActivationListener; + + /** + * Listens for LAF changes so the auto-complete windows automatically + * update themselves accordingly. + */ + private LookAndFeelChangeListener lafListener; + + /** + * The key used in the input map for the AutoComplete action. + */ + private static final String PARAM_TRIGGER_KEY = "AutoComplete"; + + /** + * Key used in the input map for the parameter completion action. + */ + private static final String PARAM_COMPLETE_KEY = "AutoCompletion.FunctionStart"; + + /** + * Stores how to render auto-completion-specific highlights in text + * components. + */ + private static final AutoCompletionStyleContext STYLE_CONTEXT = + new AutoCompletionStyleContext(); + + /** + * Whether debug messages should be printed to stdout as AutoCompletion + * runs. + */ + private static final boolean DEBUG = initDebug(); + + + /** + * Constructor. + * + * @param provider The completion provider. This cannot be + * null. + */ + public AutoCompletion(CompletionProvider provider) { + + setChoicesWindowSize(350, 200); + setDescriptionWindowSize(350, 250); + + setCompletionProvider(provider); + setTriggerKey(getDefaultTriggerKey()); + setAutoCompleteEnabled(true); + setAutoCompleteSingleChoices(true); + setAutoActivationEnabled(false); + setShowDescWindow(false); + parentWindowListener = new ParentWindowListener(); + textComponentListener = new TextComponentListener(); + autoActivationListener = new AutoActivationListener(); + lafListener = new LookAndFeelChangeListener(); + + } + + + /** + * Displays the popup window. Hosting applications can call this method + * to programmatically begin an auto-completion operation. + */ + public void doCompletion() { + refreshPopupWindow(); + } + + + /** + * Returns the delay between when the user types a character and when the + * code completion popup should automatically appear (if applicable). + * + * @return The delay, in milliseconds. + * @see #setAutoActivationDelay(int) + */ + public int getAutoActivationDelay() { + return autoActivationListener.timer.getDelay(); + } + + + /** + * Returns whether, if a single auto-complete choice is available, it + * should be automatically inserted, without displaying the popup menu. + * + * @return Whether to auto-complete single choices. + * @see #setAutoCompleteSingleChoices(boolean) + */ + public boolean getAutoCompleteSingleChoices() { + return autoCompleteSingleChoices; + } + + + /** + * Returns the completion provider. + * + * @return The completion provider. + */ + public CompletionProvider getCompletionProvider() { + return provider; + } + + + /** + * Returns whether debug is enabled for AutoCompletion. + * + * @return Whether debug is enabled. + */ + static boolean isDebug() { + return DEBUG; + } + + + /** + * Returns the default auto-complete "trigger key" for this OS. For + * Windows, for example, it is Ctrl+Space. + * + * @return The default auto-complete trigger key. + */ + public static KeyStroke getDefaultTriggerKey() { + // Default to CTRL, even on Mac, since Ctrl+Space activates Spotlight + return KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, DEFAULT_MODIFIER); + } + + + /** + * Returns the handler to use when an external URL is clicked in the + * description window. + * + * @return The handler. + * @see #setExternalURLHandler(ExternalURLHandler) + * @see #getLinkRedirector() + */ + public ExternalURLHandler getExternalURLHandler() { + return externalURLHandler; + } + + + int getLineOfCaret() { + Document doc = textComponent.getDocument(); + Element root = doc.getDefaultRootElement(); + return root.getElementIndex(textComponent.getCaretPosition()); + } + + + /** + * Returns the link redirector, if any. + * + * @return The link redirector, or null if none. + * @see #setLinkRedirector(LinkRedirector) + */ + public static LinkRedirector getLinkRedirector() { + return linkRedirector; + } + + + /** + * Returns the default list cell renderer used when a completion provider + * does not supply its own. + * + * @return The default list cell renderer. + * @see #setListCellRenderer(ListCellRenderer) + */ + public ListCellRenderer getListCellRenderer() { + return renderer; + } + + + /** + * Returns the renderer to use for {@link Completion}s in the optional + * parameter choices popup window (displayed when a + * {@link ParameterizedCompletion} is code-completed). If this returns + * null, a default renderer is used. + * + * @return The renderer to use. + * @see #setParamChoicesRenderer(ListCellRenderer) + * @see #isParameterAssistanceEnabled() + */ + public ListCellRenderer getParamChoicesRenderer() { + return paramChoicesRenderer; + } + + + /** + * Returns the text to replace with in the document. This is a + * "last-chance" hook for subclasses to make special modifications to the + * completion text inserted. The default implementation simply returns + * c.getReplacementText(). You usually will not need to modify + * this method. + * + * @param c The completion being inserted. + * @param doc The document being modified. + * @param start The start of the text being replaced. + * @param len The length of the text being replaced. + * @return The text to replace with. + */ + protected String getReplacementText(Completion c, Document doc, int start, + int len) { + return c.getReplacementText(); + } + + + /** + * Returns whether the "description window" should be shown alongside + * the completion window. + * + * @return Whether the description window should be shown. + * @see #setShowDescWindow(boolean) + */ + public boolean isShowDescWindow() { + return showDescWindow; + } + + + /** + * Returns the style context describing how auto-completion related + * highlights in the editor are rendered. + * + * @return The style context. + */ + public static AutoCompletionStyleContext getStyleContext() { + return STYLE_CONTEXT; + } + + + /** + * Returns the text component for which auto-completion is enabled. + * + * @return The text component, or null if this + * {@link AutoCompletion} is not installed on any text component. + * @see #install(JTextComponent) + */ + public JTextComponent getTextComponent() { + return textComponent; + } + + + /** + * Returns the orientation of the text component we're installed to. + * + * @return The orientation of the text component, or null if + * we are not installed on one. + */ + ComponentOrientation getTextComponentOrientation() { + return textComponent == null ? null : + textComponent.getComponentOrientation(); + } + + + /** + * Returns the "trigger key" used for auto-complete. + * + * @return The trigger key. + * @see #setTriggerKey(KeyStroke) + */ + public KeyStroke getTriggerKey() { + return trigger; + } + + + /** + * Hides any child windows being displayed by the auto-completion system. + * + * @return Whether any windows were visible. + */ + public boolean hideChildWindows() { + //return hidePopupWindow() || hideToolTipWindow(); + boolean res = hidePopupWindow(); + res |= hideParameterCompletionPopups(); + return res; + } + + + /** + * Hides and disposes of any parameter completion-related popups. + * + * @return Whether any such windows were visible (and thus hidden). + */ + private boolean hideParameterCompletionPopups() { + if (pcc != null) { + pcc.deactivate(); + pcc = null; + return true; + } + return false; + } + + + /** + * Hides the popup window, if it is visible. + * + * @return Whether the popup window was visible. + */ + private boolean hidePopupWindow() { + if (popupWindow != null) { + if (popupWindow.isVisible()) { + popupWindow.setVisible(false); + return true; + } + } + return false; + } + + + /** + * Determines whether debug should be enabled for the AutoCompletion + * library. This method checks a system property, but takes care of + * {@link SecurityException}s in case we're in an applet or WebStart. + * + * @return Whether debug should be enabled. + */ + private static final boolean initDebug() { + boolean debug = false; + try { + debug = Boolean.getBoolean("AutoCompletion.debug"); + } catch (SecurityException se) { // We're in an applet or WebStart. + debug = false; + } + return debug; + } + + + /** + * Inserts a completion. Any time a code completion event occurs, the + * actual text insertion happens through this method. + * + * @param c A completion to insert. This cannot be null. + */ + protected final void insertCompletion(Completion c) { + insertCompletion(c, false); + } + + + /** + * Inserts a completion. Any time a code completion event occurs, the + * actual text insertion happens through this method. + * + * @param c A completion to insert. This cannot be null. + * @param typedParamListStartChar Whether the parameterized completion + * start character was typed (typically '('). + */ + protected void insertCompletion(Completion c, + boolean typedParamListStartChar) { + + JTextComponent textComp = getTextComponent(); + String alreadyEntered = c.getAlreadyEntered(textComp); + hidePopupWindow(); + Caret caret = textComp.getCaret(); + + int dot = caret.getDot(); + int len = alreadyEntered.length(); + int start = dot - len; + String replacement = getReplacementText(c, textComp.getDocument(), + start, len); + + caret.setDot(start); + caret.moveDot(dot); + textComp.replaceSelection(replacement); + + if (isParameterAssistanceEnabled() && + (c instanceof ParameterizedCompletion)) { + ParameterizedCompletion pc = (ParameterizedCompletion) c; + startParameterizedCompletionAssistance(pc, typedParamListStartChar); + } + + } + + + /** + * Installs this auto-completion on a text component. If this + * {@link AutoCompletion} is already installed on another text component, + * it is uninstalled first. + * + * @param c The text component. + * @see #uninstall() + */ + public void install(JTextComponent c) { + + if (textComponent != null) { + uninstall(); + } + + this.textComponent = c; + installTriggerKey(getTriggerKey()); + + // Install the function completion key, if there is one. + // NOTE: We cannot do this if the start char is ' ' (e.g. just a space + // between the function name and parameters) because it overrides + // RSTA's special space action. It seems KeyStorke.getKeyStroke(' ') + // hoses ctrl+space, shift+space, etc., even though I think it + // shouldn't... + char start = provider.getParameterListStart(); + if (start != 0 && start != ' ') { + InputMap im = c.getInputMap(); + ActionMap am = c.getActionMap(); + KeyStroke ks = KeyStroke.getKeyStroke(start); + oldParenKey = im.get(ks); + im.put(ks, PARAM_COMPLETE_KEY); + oldParenAction = am.get(PARAM_COMPLETE_KEY); + am.put(PARAM_COMPLETE_KEY, + new ParameterizedCompletionStartAction(start)); + } + + textComponentListener.addTo(this.textComponent); + // In case textComponent is already in a window... + textComponentListener.hierarchyChanged(null); + + if (isAutoActivationEnabled()) { + autoActivationListener.addTo(this.textComponent); + } + + UIManager.addPropertyChangeListener(lafListener); + updateUI(); // In case there have been changes since we uninstalled + + } + + + /** + * Installs a "trigger key" action onto the current text component. + * + * @param ks The keystroke that should trigger the action. + * @see #uninstallTriggerKey() + */ + private void installTriggerKey(KeyStroke ks) { + InputMap im = textComponent.getInputMap(); + oldTriggerKey = im.get(ks); + im.put(ks, PARAM_TRIGGER_KEY); + ActionMap am = textComponent.getActionMap(); + oldTriggerAction = am.get(PARAM_TRIGGER_KEY); + am.put(PARAM_TRIGGER_KEY, new AutoCompleteAction()); + } + + + /** + * Returns whether auto-activation is enabled (that is, whether the + * completion popup will automatically appear after a delay when the user + * types an appropriate character). Note that this parameter will be + * ignored if auto-completion is disabled. + * + * @return Whether auto-activation is enabled. + * @see #setAutoActivationEnabled(boolean) + * @see #getAutoActivationDelay() + * @see #isAutoCompleteEnabled() + */ + public boolean isAutoActivationEnabled() { + return autoActivationEnabled; + } + + + /** + * Returns whether auto-completion is enabled. + * + * @return Whether auto-completion is enabled. + * @see #setAutoCompleteEnabled(boolean) + */ + public boolean isAutoCompleteEnabled() { + return autoCompleteEnabled; + } + + + /** + * Returns whether parameter assistance is enabled. + * + * @return Whether parameter assistance is enabled. + * @see #setParameterAssistanceEnabled(boolean) + */ + public boolean isParameterAssistanceEnabled() { + return parameterAssistanceEnabled; + } + + + /** + * Returns whether the completion popup window is visible. + * + * @return Whether the completion popup window is visible. + */ + public boolean isPopupVisible() { + return popupWindow != null && popupWindow.isVisible(); + } + + + /** + * Refreshes the popup window. First, this method gets the possible + * completions for the current caret position. If there are none, and the + * popup is visible, it is hidden. If there are some completions and the + * popup is hidden, it is made visible and made to display the completions. + * If there are some completions and the popup is visible, its list is + * updated to the current set of completions. + * + * @return The current line number of the caret. + */ + protected int refreshPopupWindow() { + // A return value of null => don't suggest completions + String text = provider.getAlreadyEnteredText(textComponent); + if (text == null && !isPopupVisible()) { + return getLineOfCaret(); + } + // If the popup is currently visible, and they type a space (or any + // character that resets the completion list to "all completions"), + // the popup window should be hidden instead of being reset to show + // everything. + int textLen = text == null ? 0 : text.length(); + if (textLen == 0 && isPopupVisible()) { + hidePopupWindow(); + return getLineOfCaret(); + } + final List completions = provider.getCompletions(textComponent); + int count = completions.size(); + if (needSetPopupWindow(count, textLen)) { + if (popupWindow == null) { + popupWindow = createAutoCompletePopupWindow(); + } + popupWindow.setCompletions(completions); + if (!popupWindow.isVisible()) { + Rectangle r = null; + try { + r = textComponent.modelToView(textComponent.getCaretPosition()); + } catch (BadLocationException ble) { + return -1; + } + Point p = new Point(r.x, r.y); + SwingUtilities.convertPointToScreen(p, textComponent); + r.x = p.x; + r.y = p.y; + popupWindow.setLocationRelativeTo(r); + popupWindow.setVisible(true); + } + } else if (count == 1) { // !isPopupVisible && autoCompleteSingleChoices + SwingUtilities.invokeLater(new Runnable() { + public void run() { + insertCompletion(completions.get(0)); + } + }); + } else { + hidePopupWindow(); + } + return getLineOfCaret(); + } + + private boolean needSetPopupWindow(int count, int textLen) { + return (count == 1 && (isPopupVisible() || textLen == 0)) + || (count == 1 && !getAutoCompleteSingleChoices()) + || count > 1; + } + + private AutoCompletePopupWindow createAutoCompletePopupWindow() { + AutoCompletePopupWindow popupWindow = new AutoCompletePopupWindow(parentWindow, this); + // Completion is usually done for code, which is always done + // LTR, so make completion stuff RTL only if text component is + // also RTL. + popupWindow.applyComponentOrientation( + getTextComponentOrientation()); + if (renderer != null) { + popupWindow.setListCellRenderer(renderer); + } + if (preferredChoicesWindowSize != null) { + popupWindow.setSize(preferredChoicesWindowSize); + } + if (preferredDescWindowSize != null) { + popupWindow.setDescriptionWindowSize( + preferredDescWindowSize); + } + return popupWindow; + } + + /** + * Sets the delay between when the user types a character and when the + * code completion popup should automatically appear (if applicable). + * + * @param ms The delay, in milliseconds. This should be greater than zero. + * @see #getAutoActivationDelay() + */ + public void setAutoActivationDelay(int ms) { + ms = Math.max(0, ms); + autoActivationListener.timer.stop(); + autoActivationListener.timer.setInitialDelay(ms); + } + + + /** + * Toggles whether auto-activation is enabled. Note that auto-activation + * also depends on auto-completion itself being enabled. + * + * @param enabled Whether auto-activation is enabled. + * @see #isAutoActivationEnabled() + * @see #setAutoActivationDelay(int) + */ + public void setAutoActivationEnabled(boolean enabled) { + if (enabled != autoActivationEnabled) { + autoActivationEnabled = enabled; + if (textComponent != null) { + if (autoActivationEnabled) { + autoActivationListener.addTo(textComponent); + } else { + autoActivationListener.removeFrom(textComponent); + } + } + } + } + + + /** + * Sets whether auto-completion is enabled. + * + * @param enabled Whether auto-completion is enabled. + * @see #isAutoCompleteEnabled() + */ + public void setAutoCompleteEnabled(boolean enabled) { + if (enabled != autoCompleteEnabled) { + autoCompleteEnabled = enabled; + hidePopupWindow(); + } + } + + + /** + * Sets whether, if a single auto-complete choice is available, it should + * be automatically inserted, without displaying the popup menu. + * + * @param autoComplete Whether to auto-complete single choices. + * @see #getAutoCompleteSingleChoices() + */ + public void setAutoCompleteSingleChoices(boolean autoComplete) { + autoCompleteSingleChoices = autoComplete; + } + + + /** + * Sets the completion provider being used. + * + * @param provider The new completion provider. This cannot be + * null. + * @throws IllegalArgumentException If provider is + * null. + */ + public void setCompletionProvider(CompletionProvider provider) { + if (provider == null) { + throw new IllegalArgumentException("provider cannot be null"); + } + this.provider = provider; + hidePopupWindow(); // In case new choices should be displayed. + } + + + /** + * Sets the size of the completion choices window. + * + * @param w The new width. + * @param h The new height. + * @see #setDescriptionWindowSize(int, int) + */ + public void setChoicesWindowSize(int w, int h) { + preferredChoicesWindowSize = new Dimension(w, h); + if (popupWindow != null) { + popupWindow.setSize(preferredChoicesWindowSize); + } + } + + + /** + * Sets the size of the description window. + * + * @param w The new width. + * @param h The new height. + * @see #setChoicesWindowSize(int, int) + */ + public void setDescriptionWindowSize(int w, int h) { + preferredDescWindowSize = new Dimension(w, h); + if (popupWindow != null) { + popupWindow.setDescriptionWindowSize(preferredDescWindowSize); + } + } + + + /** + * Sets the handler to use when an external URL is clicked in the + * description window. This handler can perform some action, such as + * open the URL in a web browser. The default implementation will open + * the URL in a browser, but only if running in Java 6. If you want + * browser support for Java 5 and below, or otherwise want to respond to + * hyperlink clicks, you will have to install your own handler to do so. + * + * @param handler The new handler. + * @see #getExternalURLHandler() + */ + public void setExternalURLHandler(ExternalURLHandler handler) { + this.externalURLHandler = handler; + } + + + /** + * Sets the redirector for external URL's found in code completion + * documentation. When a non-local link in completion popups is clicked, + * this redirector is given the chance to modify the URL fetched and + * displayed. + * + * @param linkRedirector The link redirector, or null for + * none. + * @see #getLinkRedirector() + */ + public static void setLinkRedirector(LinkRedirector linkRedirector) { + AutoCompletion.linkRedirector = linkRedirector; + } + + + /** + * Sets the default list cell renderer to use when a completion provider + * does not supply its own. + * + * @param renderer The renderer to use. If this is null, + * a default renderer is used. + * @see #getListCellRenderer() + */ + public void setListCellRenderer(ListCellRenderer renderer) { + this.renderer = renderer; + if (popupWindow != null) { + popupWindow.setListCellRenderer(renderer); + hidePopupWindow(); + } + } + + + /** + * Sets the renderer to use for {@link Completion}s in the optional + * parameter choices popup window (displayed when a + * {@link ParameterizedCompletion} is code-completed). If this isn't set, + * a default renderer is used. + * + * @param r The renderer to use. + * @see #getParamChoicesRenderer() + * @see #setParameterAssistanceEnabled(boolean) + */ + public void setParamChoicesRenderer(ListCellRenderer r) { + paramChoicesRenderer = r; + } + + + /** + * Sets whether parameter assistance is enabled. If parameter assistance + * is enabled, and a "parameterized" completion (such as a function or + * method) is inserted, the user will get "assistance" in inserting the + * parameters in the form of a popup window with documentation and easy + * tabbing through the arguments (as seen in Eclipse and NetBeans). + * + * @param enabled Whether parameter assistance should be enabled. + * @see #isParameterAssistanceEnabled() + */ + public void setParameterAssistanceEnabled(boolean enabled) { + parameterAssistanceEnabled = enabled; + } + + + /** + * Sets whether the "description window" should be shown beside the + * completion window. + * + * @param show Whether to show the description window. + * @see #isShowDescWindow() + */ + public void setShowDescWindow(boolean show) { + hidePopupWindow(); // Needed to force it to take effect + showDescWindow = show; + } + + + /** + * Sets the keystroke that should be used to trigger the auto-complete + * popup window. + * + * @param ks The keystroke. + * @throws IllegalArgumentException If ks is null. + * @see #getTriggerKey() + */ + public void setTriggerKey(KeyStroke ks) { + if (ks == null) { + throw new IllegalArgumentException("trigger key cannot be null"); + } + if (!ks.equals(trigger)) { + if (textComponent != null) { + // Put old trigger action back. + uninstallTriggerKey(); + // Grab current action for new trigger and replace it. + installTriggerKey(ks); + } + trigger = ks; + } + } + + + /** + * Displays a "tool tip" detailing the inputs to the function just entered. + * + * @param pc The completion. + * @param typedParamListStartChar Whether the parameterized completion list + * starting character was typed. + */ + private void startParameterizedCompletionAssistance( + ParameterizedCompletion pc, boolean typedParamListStartChar) { + + // Get rid of the previous tool tip window, if there is one. + hideParameterCompletionPopups(); + + // Don't bother with a tool tip if there are no parameters, but if + // they typed e.g. the opening '(', make them overtype the ')'. + if (pc.getParamCount() == 0 && !(pc instanceof TemplateCompletion)) { + CompletionProvider p = pc.getProvider(); + char end = p.getParameterListEnd(); // Might be '\0' + String text = end == '\0' ? "" : Character.toString(end); + if (typedParamListStartChar) { + String template = "${}" + text + "${cursor}"; + textComponent.replaceSelection(Character.toString(p.getParameterListStart())); + TemplateCompletion tc = new TemplateCompletion(p, null, null, template); + pc = tc; + } else { + text = p.getParameterListStart() + text; + textComponent.replaceSelection(text); + return; + } + } + + pcc = new ParameterizedCompletionContext(parentWindow, this, pc); + pcc.activate(); + + } + + + /** + * Uninstalls this auto-completion from its text component. If it is not + * installed on any text component, nothing happens. + * + * @see #install(JTextComponent) + */ + public void uninstall() { + + if (textComponent != null) { + + hidePopupWindow(); // Unregisters listeners, actions, etc. + + uninstallTriggerKey(); + + // Uninstall the function completion key. + char start = provider.getParameterListStart(); + if (start != 0) { + KeyStroke ks = KeyStroke.getKeyStroke(start); + InputMap im = textComponent.getInputMap(); + im.put(ks, oldParenKey); + ActionMap am = textComponent.getActionMap(); + am.put(PARAM_COMPLETE_KEY, oldParenAction); + } + + textComponentListener.removeFrom(textComponent); + if (parentWindow != null) { + parentWindowListener.removeFrom(parentWindow); + } + + if (isAutoActivationEnabled()) { + autoActivationListener.removeFrom(textComponent); + } + + UIManager.removePropertyChangeListener(lafListener); + + textComponent = null; + popupWindow = null; + + } + + } + + + /** + * Replaces the "trigger key" action with the one that was there + * before auto-completion was installed. + * + * @see #installTriggerKey(KeyStroke) + */ + private void uninstallTriggerKey() { + InputMap im = textComponent.getInputMap(); + im.put(trigger, oldTriggerKey); + ActionMap am = textComponent.getActionMap(); + am.put(PARAM_TRIGGER_KEY, oldTriggerAction); + } + + + /** + * Updates the LookAndFeel of the popup window. Applications can call + * this method as appropriate if they support changing the LookAndFeel + * at runtime. + */ + private void updateUI() { + if (popupWindow != null) { + popupWindow.updateUI(); + } + if (pcc != null) { + pcc.updateUI(); + } + // Will practically always be a JComponent (a JLabel) + if (paramChoicesRenderer instanceof JComponent) { + ((JComponent) paramChoicesRenderer).updateUI(); + } + } + + + /** + * Listens for events in the text component to auto-activate the code + * completion popup. + */ + private class AutoActivationListener extends FocusAdapter + implements DocumentListener, CaretListener, ActionListener { + + private Timer timer; + private boolean justInserted; + + public AutoActivationListener() { + timer = new Timer(200, this); + timer.setRepeats(false); + } + + public void actionPerformed(ActionEvent e) { + doCompletion(); + } + + public void addTo(JTextComponent tc) { + tc.addFocusListener(this); + tc.getDocument().addDocumentListener(this); + tc.addCaretListener(this); + } + + public void caretUpdate(CaretEvent e) { + if (justInserted) { + justInserted = false; + } else { + timer.stop(); + } + } + + public void changedUpdate(DocumentEvent e) { + // Ignore + } + + @Override + public void focusLost(FocusEvent e) { + timer.stop(); + //hideChildWindows(); Other listener will do this + } + + public void insertUpdate(DocumentEvent e) { + justInserted = false; + if (isAutoCompleteEnabled() && isAutoActivationEnabled() && + e.getLength() == 1) { + if (provider.isAutoActivateOkay(textComponent)) { + timer.restart(); + justInserted = true; + } else { + timer.stop(); + } + } else { + timer.stop(); + } + } + + public void removeFrom(JTextComponent tc) { + tc.removeFocusListener(this); + tc.getDocument().removeDocumentListener(this); + tc.removeCaretListener(this); + timer.stop(); + justInserted = false; + } + + public void removeUpdate(DocumentEvent e) { + timer.stop(); + } + + } + + + /** + * The Action that displays the popup window if + * auto-completion is enabled. + */ + private class AutoCompleteAction extends AbstractAction { + + public void actionPerformed(ActionEvent e) { + if (isAutoCompleteEnabled()) { + refreshPopupWindow(); + } else if (oldTriggerAction != null) { + oldTriggerAction.actionPerformed(e); + } + } + + } + + + /** + * Listens for LookAndFeel changes and updates the various popup windows + * involved in auto-completion accordingly. + */ + private class LookAndFeelChangeListener implements PropertyChangeListener { + + public void propertyChange(PropertyChangeEvent e) { + String name = e.getPropertyName(); + if ("lookAndFeel".equals(name)) { + updateUI(); + } + } + + } + + + /** + * Action that starts a parameterized completion, e.g. after '(' is + * typed. + */ + private class ParameterizedCompletionStartAction extends AbstractAction { + + private String start; + + public ParameterizedCompletionStartAction(char ch) { + this.start = Character.toString(ch); + } + + public void actionPerformed(ActionEvent e) { + + // Prevents keystrokes from messing up + boolean wasVisible = hidePopupWindow(); + + // Only proceed if they were selecting a completion + if (!wasVisible || !isParameterAssistanceEnabled()) { + textComponent.replaceSelection(start); + return; + } + + Completion c = popupWindow.getSelection(); + if (c instanceof ParameterizedCompletion) { // Should always be true + // Fixes capitalization of the entered text. + insertCompletion(c, true); + } + + } + + } + + + /** + * Listens for events in the parent window of the text component with + * auto-completion enabled. + */ + private class ParentWindowListener extends ComponentAdapter + implements WindowFocusListener { + + public void addTo(Window w) { + w.addComponentListener(this); + w.addWindowFocusListener(this); + } + + @Override + public void componentHidden(ComponentEvent e) { + hideChildWindows(); + } + + @Override + public void componentMoved(ComponentEvent e) { + hideChildWindows(); + } + + @Override + public void componentResized(ComponentEvent e) { + hideChildWindows(); + } + + public void removeFrom(Window w) { + w.removeComponentListener(this); + w.removeWindowFocusListener(this); + } + + public void windowGainedFocus(WindowEvent e) { + } + + public void windowLostFocus(WindowEvent e) { + hideChildWindows(); + } + + } + + + /** + * Listens for events from the text component we're installed on. + */ + private class TextComponentListener extends FocusAdapter + implements HierarchyListener { + + void addTo(JTextComponent tc) { + tc.addFocusListener(this); + tc.addHierarchyListener(this); + } + + /** + * Hide the auto-completion windows when the text component loses + * focus. + */ + @Override + public void focusLost(FocusEvent e) { + hideChildWindows(); + } + + /** + * Called when the component hierarchy for our text component changes. + * When the text component is added to a new {@link Window}, this + * method registers listeners on that Window. + * + * @param e The event. + */ + public void hierarchyChanged(HierarchyEvent e) { + + // NOTE: e many be null as we call this method at other times. + //System.out.println("Hierarchy changed! " + e); + + Window oldParentWindow = parentWindow; + parentWindow = SwingUtilities.getWindowAncestor(textComponent); + if (parentWindow != oldParentWindow) { + if (oldParentWindow != null) { + parentWindowListener.removeFrom(oldParentWindow); + } + if (parentWindow != null) { + parentWindowListener.addTo(parentWindow); + } + } + + } + + public void removeFrom(JTextComponent tc) { + tc.removeFocusListener(this); + tc.removeHierarchyListener(this); + } + + } } \ No newline at end of file diff --git a/designer_base/src/com/fr/design/gui/autocomplete/ParameterizedCompletionContext.java b/designer_base/src/com/fr/design/gui/autocomplete/ParameterizedCompletionContext.java index 62c68dc987..966035b894 100644 --- a/designer_base/src/com/fr/design/gui/autocomplete/ParameterizedCompletionContext.java +++ b/designer_base/src/com/fr/design/gui/autocomplete/ParameterizedCompletionContext.java @@ -439,7 +439,7 @@ class ParameterizedCompletionContext { */ private void installKeyBindings() { - if (AutoCompletion.getDebug()) { + if (AutoCompletion.isDebug()) { System.out.println("CompletionContext: Installing keybindings"); } @@ -733,7 +733,7 @@ class ParameterizedCompletionContext { */ private void uninstallKeyBindings() { - if (AutoCompletion.getDebug()) { + if (AutoCompletion.isDebug()) { System.out.println("CompletionContext Uninstalling keybindings"); } diff --git a/designer_base/src/com/fr/design/gui/itabpane/UITabsHeaderIconPane.java b/designer_base/src/com/fr/design/gui/itabpane/UITabsHeaderIconPane.java index 1ec189cc13..ba77523520 100644 --- a/designer_base/src/com/fr/design/gui/itabpane/UITabsHeaderIconPane.java +++ b/designer_base/src/com/fr/design/gui/itabpane/UITabsHeaderIconPane.java @@ -160,12 +160,14 @@ public class UITabsHeaderIconPane extends JPanel implements UITabComponent { public void run() { int height = centerPane.getHeight(); int width = centerPane.getWidth(); + int step = 30; + int x = 0; int y = -height; - for (int i = 0; i <= height; i += 30) { + for (int i = 0; i <= height; i += step) { // 设置面板位置 - currentPanel.setBounds(0, i, width, height); - panel.setBounds(0, y, width, height); - y += 30; + currentPanel.setBounds(x, i, width, height); + panel.setBounds(x, y, width, height); + y += step; try { Thread.sleep(3); } catch (InterruptedException e) { diff --git a/designer_base/src/com/fr/design/gui/itree/checkboxtree/CheckBoxTree.java b/designer_base/src/com/fr/design/gui/itree/checkboxtree/CheckBoxTree.java index 941fd962a1..b81ea7c38b 100644 --- a/designer_base/src/com/fr/design/gui/itree/checkboxtree/CheckBoxTree.java +++ b/designer_base/src/com/fr/design/gui/itree/checkboxtree/CheckBoxTree.java @@ -236,8 +236,9 @@ public class CheckBoxTree extends JTree { } TreePath path = _tree.getPathForLocation(e.getX(), e.getY()); - if (path == null) + if (path == null) { return null; + } if (clicksInCheckBox(e, path)) { return path; @@ -308,8 +309,9 @@ public class CheckBoxTree extends JTree { return; } - if (e.getModifiers() == 0 && e.getKeyChar() == KeyEvent.VK_SPACE) + if (e.getModifiers() == 0 && e.getKeyChar() == KeyEvent.VK_SPACE) { toggleSelections(); + } } public void keyTyped(KeyEvent e) { diff --git a/designer_base/src/com/fr/design/locale/designer.properties b/designer_base/src/com/fr/design/locale/designer.properties index 9b75c6f47d..9d6332e6a8 100644 --- a/designer_base/src/com/fr/design/locale/designer.properties +++ b/designer_base/src/com/fr/design/locale/designer.properties @@ -1137,7 +1137,7 @@ FRFont-bold=bold FR-Designer_Set_Submit_Condition= Form-Change_Widget_Name=Change Widget Name ReportColumns-Report_Columns=Report Columns -Can_not_use_FormatBursh= +FR-Designer_Can_not_use_FormatBursh= CellElement-Property_Table=CellElement Property Table Dictionary-Dynamic_SQL=Dynamic SQL FR-Designer_Form-CheckBoxGroup=CheckBoxGroup diff --git a/designer_base/src/com/fr/design/locale/designer_en_US.properties b/designer_base/src/com/fr/design/locale/designer_en_US.properties index 8636f53ceb..e8f9e376c5 100644 --- a/designer_base/src/com/fr/design/locale/designer_en_US.properties +++ b/designer_base/src/com/fr/design/locale/designer_en_US.properties @@ -1138,7 +1138,7 @@ FRFont-bold=Bold FR-Designer_Set_Submit_Condition=Submit Condition Form-Change_Widget_Name=Change Control Name ReportColumns-Report_Columns=Multi-columns/lines display -Can_not_use_FormatBursh=Can't use format painter in multiple selections +FR-Designer_Can_not_use_FormatBursh=Can't use format painter in multiple selections CellElement-Property_Table=Cell Attribute Table Dictionary-Dynamic_SQL=Dynamic SQL FR-Designer_Form-CheckBoxGroup=CheckBoxGroup diff --git a/designer_base/src/com/fr/design/locale/designer_ja_JP.properties b/designer_base/src/com/fr/design/locale/designer_ja_JP.properties index d5d9dac39f..9cb8cd654e 100644 --- a/designer_base/src/com/fr/design/locale/designer_ja_JP.properties +++ b/designer_base/src/com/fr/design/locale/designer_ja_JP.properties @@ -1133,7 +1133,7 @@ FRFont-bold=\u592A\u5B57 FR-Designer_Set_Submit_Condition=\u63D0\u51FA\u6761\u4EF6\u3092\u8A2D\u5B9A Form-Change_Widget_Name=\u30B3\u30F3\u30C8\u30ED\u30FC\u30EB\u540D\u5909\u66F4 ReportColumns-Report_Columns=\u5E33\u7968\u30B3\u30E9\u30E0 -Can_not_use_FormatBursh=\u8907\u6570\u9078\u629E\u3057\u305F\u30A8\u30EA\u30A2\u3067\u306F\u66F8\u5F0F\u30D6\u30E9\u30B7\u3092\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\! +FR-Designer_Can_not_use_FormatBursh=\u8907\u6570\u9078\u629E\u3057\u305F\u30A8\u30EA\u30A2\u3067\u306F\u66F8\u5F0F\u30D6\u30E9\u30B7\u3092\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\! CellElement-Property_Table=\u30BB\u30EB\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u00B7\u30B7\u30FC\u30C8 Dictionary-Dynamic_SQL=\u52D5\u614BSQL FR-Designer_Form-CheckBoxGroup=\u30D5\u30EC\u30FC\u30E0\u30BB\u30C3\u30C8\u3092\u8907\u6570\u9078\u629E diff --git a/designer_base/src/com/fr/design/locale/designer_ko_KR.properties b/designer_base/src/com/fr/design/locale/designer_ko_KR.properties index 39ebe76b63..93a796d79f 100644 --- a/designer_base/src/com/fr/design/locale/designer_ko_KR.properties +++ b/designer_base/src/com/fr/design/locale/designer_ko_KR.properties @@ -1134,7 +1134,7 @@ FRFont-bold=\uAD75\uAC8C FR-Designer_Set_Submit_Condition=\uC81C\uCD9C\uC870\uAC74\uC124\uC815 Form-Change_Widget_Name=\uC18C\uD504\uD2B8\uC6E8\uC5B4\uC81C\uC5B4\uC774\uB984\uBCC0\uACBD ReportColumns-Report_Columns=\uBB38\uC11C\uC140\uB098\uB204\uAE30 -Can_not_use_FormatBursh=\uC911\uBCF5\uC120\uD0DD\uB41C\uC601\uC5ED\uC5D0\uC11C\uC2DD\uC744\uC774\uC6A9\uD558\uC5EC\uC778\uC1C4\uD560\uC218\uC5C6\uC2B5\uB2C8\uB2E4.\! +FR-Designer_Can_not_use_FormatBursh=\uC911\uBCF5\uC120\uD0DD\uB41C\uC601\uC5ED\uC5D0\uC11C\uC2DD\uC744\uC774\uC6A9\uD558\uC5EC\uC778\uC1C4\uD560\uC218\uC5C6\uC2B5\uB2C8\uB2E4.\! CellElement-Property_Table=\uC140\uC18D\uC131\uD45C Dictionary-Dynamic_SQL=\uB3D9\uC801 SQL FR-Designer_Form-CheckBoxGroup=\uCCB4\uD06C\uBC15\uC2A4\uADF8\uB8F9 diff --git a/designer_base/src/com/fr/design/locale/designer_zh_CN.properties b/designer_base/src/com/fr/design/locale/designer_zh_CN.properties index 62caf9aebb..1fe8ac3c1e 100644 --- a/designer_base/src/com/fr/design/locale/designer_zh_CN.properties +++ b/designer_base/src/com/fr/design/locale/designer_zh_CN.properties @@ -1133,7 +1133,7 @@ FRFont-bold=\u52A0\u7C97 FR-Designer_Set_Submit_Condition=\u8BBE\u7F6E\u63D0\u4EA4\u6761\u4EF6 Form-Change_Widget_Name=\u66F4\u6539\u63A7\u4EF6\u540D ReportColumns-Report_Columns=\u62A5\u8868\u5206\u680F -Can_not_use_FormatBursh=\u4E0D\u80FD\u5BF9\u591A\u91CD\u9009\u5B9A\u533A\u57DF\u4F7F\u7528\u683C\u5F0F\u5237\! +FR-Designer_Can_not_use_FormatBursh=\u4E0D\u80FD\u5BF9\u591A\u91CD\u9009\u5B9A\u533A\u57DF\u4F7F\u7528\u683C\u5F0F\u5237\! CellElement-Property_Table=\u5355\u5143\u683C\u5C5E\u6027\u8868 Dictionary-Dynamic_SQL=\u52A8\u6001SQL FR-Designer_Form-CheckBoxGroup=\u590D\u9009\u6846\u7EC4 diff --git a/designer_base/src/com/fr/design/locale/designer_zh_TW.properties b/designer_base/src/com/fr/design/locale/designer_zh_TW.properties index 867b50f709..08a75d41e2 100644 --- a/designer_base/src/com/fr/design/locale/designer_zh_TW.properties +++ b/designer_base/src/com/fr/design/locale/designer_zh_TW.properties @@ -1133,7 +1133,7 @@ FRFont-bold=\u7C97\u9AD4 FR-Designer_Set_Submit_Condition=\u8A2D\u5B9A\u63D0\u4EA4\u689D\u4EF6 Form-Change_Widget_Name=\u66F4\u6539\u63A7\u5236\u9805\u540D ReportColumns-Report_Columns=\u5831\u8868\u5206\u6B04 -Can_not_use_FormatBursh=\u7121\u6CD5\u4F7F\u7528\u8907\u88FD\u683C\u5F0F +FR-Designer_Can_not_use_FormatBursh=\u7121\u6CD5\u4F7F\u7528\u8907\u88FD\u683C\u5F0F CellElement-Property_Table=\u5132\u5B58\u683C\u5C6C\u6027\u8868 Dictionary-Dynamic_SQL=\u52D5\u614BSQL FR-Designer_Form-CheckBoxGroup=\u5FA9\u9078\u6846\u7D44 diff --git a/designer_form/src/com/fr/design/mainframe/widget/editors/DataTableConfigPane.java b/designer_form/src/com/fr/design/mainframe/widget/editors/DataTableConfigPane.java index 417d761ccf..a45d9fa255 100644 --- a/designer_form/src/com/fr/design/mainframe/widget/editors/DataTableConfigPane.java +++ b/designer_form/src/com/fr/design/mainframe/widget/editors/DataTableConfigPane.java @@ -25,248 +25,249 @@ import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_M public class DataTableConfigPane extends JComponent implements PropertyChangeListener { - private DataEditingTable table; - - public DataTableConfigPane() { - table = new DataEditingTable(); - JScrollPane scrollPane = new JScrollPane(table); - this.setLayout(new DataTableLayout()); - this.add(scrollPane, BorderLayout.CENTER); - } - - public void populate(DataTableConfig config) { - table.populate(config); - } - - public DataTableConfig update() { - return table.update(); - } - - class DataTableLayout extends BorderLayout { - public void layoutContainer(Container target) { - super.layoutContainer(target); - table.doLayout(); - } - } - - class DataEditingTable extends JTable { - - private DataTableConfig config; - private BeanTableModel model; - private TableColumnModelListener modeListener; - - public DataEditingTable() { - this.setBorder(BorderFactory.createLineBorder(new Color(210, 210, 210), 1)); - this.setColumnSelectionAllowed(true); - this.setRowSelectionAllowed(true); - MouseAdapterListener l = new MouseAdapterListener(this); - this.addMouseListener(l); - this.addMouseMotionListener(l); - model = new BeanTableModel(); - modeListener = new TableColumnModelListener() { - - @Override - public void columnAdded(TableColumnModelEvent e) { - - } - - @Override - public void columnMarginChanged(ChangeEvent e) { - DataTableConfigPane.this.propertyChange(); - } - - @Override - public void columnMoved(TableColumnModelEvent e) { - DataTableConfigPane.this.propertyChange(); - } - - @Override - public void columnRemoved(TableColumnModelEvent e) { - - } - - @Override - public void columnSelectionChanged(ListSelectionEvent e) { - - } - - }; - } - - public TableCellRenderer getCellRenderer(int row, int column) { - TableCellRenderer renderer = super.getCellRenderer(row, column); - if (renderer instanceof UILabel) { - ((UILabel) renderer).setHorizontalAlignment(UILabel.CENTER); - } - return renderer; - } - - public void populate(DataTableConfig config) { - this.getTableHeader().getColumnModel().removeColumnModelListener(modeListener); - if (config == null) { - config = DataTableConfig.DEFAULT_TABLE_DATA_CONFIG; - } - this.config = config; - - model = new BeanTableModel(); - this.setModel(model); - this.setRowHeight(0, config.getRowHeight()); - for (int i = 0; i < config.getColumnCount(); i++) { - this.getColumn(this.getColumnName(i)).setPreferredWidth(config.getColumnWidth(i)); - } - this.getTableHeader().getColumnModel().addColumnModelListener(modeListener); - this.doLayout(); - this.repaint(); - } - - public DataTableConfig update() { - config.setRowHeight(this.getRowHeight(0)); - model = new BeanTableModel(); - String[] columns = new String[this.getColumnCount()]; - for (int i = 0; i < this.getColumnCount(); i++) { - config.setColumnWidth(i, this.getColumn(this.getColumnName(i)).getWidth()); - columns[i] = this.getColumnName(i); - } - - config.setColumns(columns); - return config; - } - - public class BeanTableModel extends AbstractTableModel { - - @Override - public int getColumnCount() { - return config.getColumnCount(); - } - - @Override - public int getRowCount() { - return 1; - } - - @Override - public String getColumnName(int column) { - return config.getColumnName(column); - } - - @Override - public Object getValueAt(int rowIndex, int columnIndex) { - return config.getTableDataName() + "." + config.getColumnName(columnIndex); - } - - } - - class MouseAdapterListener extends MouseAdapter { - private JTable table; - int oldY = 0; - int newY = 0; - int row = 0; - int oldHeight = 0; - boolean drag = false; - int increase = 0; - JPopupMenu popupMenu; - - public MouseAdapterListener(JTable table) { - this.table = table; - popupMenu = new JPopupMenu(); - - popupMenu.add(new CutAction()); - popupMenu.add(new CutAction()); - popupMenu.add(new CutAction()); - popupMenu.add(new CutAction()); - } - - class CutAction extends UpdateAction { - - /** - * Constructor - */ - public CutAction() { - this.setName(Inter.getLocText("M_Edit-Cut")); - this.setMnemonic('T'); - this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/m_edit/cut.png")); - this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, DEFAULT_MODIFIER)); - } - - @Override - public void actionPerformed(ActionEvent e) { - int row = table.getSelectedRow(); - int column = table.getSelectedColumn(); - table.getColumnModel().removeColumn(table.getColumn(table.getColumnName(column))); - DataTableConfigPane.this.propertyChange(); - } - } - - public void mouseMoved(MouseEvent e) { - int onRow = table.rowAtPoint(e.getPoint()); - - int height = 0; - for (int i = 0; i <= onRow; i++) { - height = height + table.getRowHeight(i); - } - - if (height - e.getY() < 3) { - drag = true; - table.setCursor(new Cursor(Cursor.N_RESIZE_CURSOR)); - } else { - drag = false; - table.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); - } - - } - - private void trigger_popup(MouseEvent e) { - - popupMenu.show(table, e.getX(), e.getY()); - } - - public void mouseDragged(MouseEvent e) { - if (drag) { - int value = oldHeight + e.getY() - oldY; - if (value < 30) - table.setRowHeight(row, 30); - else - table.setRowHeight(row, oldHeight + e.getY() - oldY); - DataTableConfigPane.this.propertyChange(); - } - } - - public void mousePressed(MouseEvent e) { - oldY = e.getY(); - row = table.rowAtPoint(e.getPoint()); - oldHeight = table.getRowHeight(row); - if (e.getButton() == MouseEvent.BUTTON3) { - trigger_popup(e); - } - } - - public void mouseReleased(MouseEvent e) { - newY = e.getY(); - table.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); - } - } - } - - private ArrayList changetList = new ArrayList(); - - public void addpropertyChangeListener(PropertyChangeListener l) { - changetList.add(l); - } - - @Override - public void propertyChange() { - for (PropertyChangeListener l : changetList) { - l.propertyChange(); - } - } + private DataEditingTable table; + + public DataTableConfigPane() { + table = new DataEditingTable(); + JScrollPane scrollPane = new JScrollPane(table); + this.setLayout(new DataTableLayout()); + this.add(scrollPane, BorderLayout.CENTER); + } + + public void populate(DataTableConfig config) { + table.populate(config); + } + + public DataTableConfig update() { + return table.update(); + } + + class DataTableLayout extends BorderLayout { + public void layoutContainer(Container target) { + super.layoutContainer(target); + table.doLayout(); + } + } + + class DataEditingTable extends JTable { + + private DataTableConfig config; + private BeanTableModel model; + private TableColumnModelListener modeListener; + + public DataEditingTable() { + this.setBorder(BorderFactory.createLineBorder(new Color(210, 210, 210), 1)); + this.setColumnSelectionAllowed(true); + this.setRowSelectionAllowed(true); + MouseAdapterListener l = new MouseAdapterListener(this); + this.addMouseListener(l); + this.addMouseMotionListener(l); + model = new BeanTableModel(); + modeListener = new TableColumnModelListener() { + + @Override + public void columnAdded(TableColumnModelEvent e) { + + } + + @Override + public void columnMarginChanged(ChangeEvent e) { + DataTableConfigPane.this.propertyChange(); + } + + @Override + public void columnMoved(TableColumnModelEvent e) { + DataTableConfigPane.this.propertyChange(); + } + + @Override + public void columnRemoved(TableColumnModelEvent e) { + + } + + @Override + public void columnSelectionChanged(ListSelectionEvent e) { + + } + + }; + } + + public TableCellRenderer getCellRenderer(int row, int column) { + TableCellRenderer renderer = super.getCellRenderer(row, column); + if (renderer instanceof UILabel) { + ((UILabel) renderer).setHorizontalAlignment(UILabel.CENTER); + } + return renderer; + } + + public void populate(DataTableConfig config) { + this.getTableHeader().getColumnModel().removeColumnModelListener(modeListener); + if (config == null) { + config = DataTableConfig.DEFAULT_TABLE_DATA_CONFIG; + } + this.config = config; + + model = new BeanTableModel(); + this.setModel(model); + this.setRowHeight(0, config.getRowHeight()); + for (int i = 0; i < config.getColumnCount(); i++) { + this.getColumn(this.getColumnName(i)).setPreferredWidth(config.getColumnWidth(i)); + } + this.getTableHeader().getColumnModel().addColumnModelListener(modeListener); + this.doLayout(); + this.repaint(); + } + + public DataTableConfig update() { + config.setRowHeight(this.getRowHeight(0)); + model = new BeanTableModel(); + String[] columns = new String[this.getColumnCount()]; + for (int i = 0; i < this.getColumnCount(); i++) { + config.setColumnWidth(i, this.getColumn(this.getColumnName(i)).getWidth()); + columns[i] = this.getColumnName(i); + } + + config.setColumns(columns); + return config; + } + + public class BeanTableModel extends AbstractTableModel { + + @Override + public int getColumnCount() { + return config.getColumnCount(); + } + + @Override + public int getRowCount() { + return 1; + } + + @Override + public String getColumnName(int column) { + return config.getColumnName(column); + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + return config.getTableDataName() + "." + config.getColumnName(columnIndex); + } + + } + + class MouseAdapterListener extends MouseAdapter { + private JTable table; + int oldY = 0; + int newY = 0; + int row = 0; + int oldHeight = 0; + boolean drag = false; + int increase = 0; + JPopupMenu popupMenu; + + public MouseAdapterListener(JTable table) { + this.table = table; + popupMenu = new JPopupMenu(); + + popupMenu.add(new CutAction()); + popupMenu.add(new CutAction()); + popupMenu.add(new CutAction()); + popupMenu.add(new CutAction()); + } + + class CutAction extends UpdateAction { + + /** + * Constructor + */ + public CutAction() { + this.setName(Inter.getLocText("M_Edit-Cut")); + this.setMnemonic('T'); + this.setSmallIcon(BaseUtils.readIcon("/com/fr/design/images/m_edit/cut.png")); + this.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, DEFAULT_MODIFIER)); + } + + @Override + public void actionPerformed(ActionEvent e) { + int row = table.getSelectedRow(); + int column = table.getSelectedColumn(); + table.getColumnModel().removeColumn(table.getColumn(table.getColumnName(column))); + DataTableConfigPane.this.propertyChange(); + } + } + + public void mouseMoved(MouseEvent e) { + int onRow = table.rowAtPoint(e.getPoint()); + + int height = 0; + for (int i = 0; i <= onRow; i++) { + height = height + table.getRowHeight(i); + } + + if (height - e.getY() < 3) { + drag = true; + table.setCursor(new Cursor(Cursor.N_RESIZE_CURSOR)); + } else { + drag = false; + table.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + } + + } + + private void trigger_popup(MouseEvent e) { + + popupMenu.show(table, e.getX(), e.getY()); + } + + public void mouseDragged(MouseEvent e) { + if (drag) { + int value = oldHeight + e.getY() - oldY; + if (value < 30) { + table.setRowHeight(row, 30); + } else { + table.setRowHeight(row, oldHeight + e.getY() - oldY); + } + DataTableConfigPane.this.propertyChange(); + } + } + + public void mousePressed(MouseEvent e) { + oldY = e.getY(); + row = table.rowAtPoint(e.getPoint()); + oldHeight = table.getRowHeight(row); + if (e.getButton() == MouseEvent.BUTTON3) { + trigger_popup(e); + } + } + + public void mouseReleased(MouseEvent e) { + newY = e.getY(); + table.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + } + } + } + + private ArrayList changetList = new ArrayList(); + + public void addpropertyChangeListener(PropertyChangeListener l) { + changetList.add(l); + } + + @Override + public void propertyChange() { + for (PropertyChangeListener l : changetList) { + l.propertyChange(); + } + } @Override public void propertyChange(Object mark) { } - @Override - public void propertyChange(Object[] marks) { + @Override + public void propertyChange(Object[] marks) { - } + } } \ No newline at end of file From 16925fe0ae01aacfe41a36ba3a51a6ead48fdb75 Mon Sep 17 00:00:00 2001 From: hzzz Date: Thu, 25 May 2017 14:38:04 +0800 Subject: [PATCH 21/41] PMD --- .../autocomplete/AutoCompletePopupWindow.java | 14 ++-- .../gui/autocomplete/AutoCompletion.java | 6 +- .../ParameterizedCompletionContext.java | 71 ++++++++----------- .../gui/itabpane/UITabsHeaderIconPane.java | 15 ++-- 4 files changed, 48 insertions(+), 58 deletions(-) diff --git a/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletePopupWindow.java b/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletePopupWindow.java index 40b3d7ca26..4dced3a833 100644 --- a/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletePopupWindow.java +++ b/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletePopupWindow.java @@ -10,6 +10,7 @@ package com.fr.design.gui.autocomplete; import com.fr.design.gui.syntax.ui.rsyntaxtextarea.PopupWindowDecorator; +import com.fr.general.FRLogger; import javax.swing.*; import javax.swing.event.CaretEvent; @@ -301,7 +302,7 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, private void installKeyBindings() { if (AutoCompletion.isDebug()) { - System.out.println("PopupWindow: Installing keybindings"); + FRLogger.getLogger().debug("PopupWindow: Installing keybindings"); } if (escapeKap == null) { // Lazily create actions. @@ -386,15 +387,16 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, // Try to position to the right first (LTR) int x; + int dis = 5; if (ac.getTextComponentOrientation().isLeftToRight()) { - x = getX() + getWidth() + 5; + x = getX() + getWidth() + dis; if (x + descWindow.getWidth() > screenBounds.x + screenBounds.width) { // doesn't fit - x = getX() - 5 - descWindow.getWidth(); + x = getX() - dis - descWindow.getWidth(); } } else { // RTL - x = getX() - 5 - descWindow.getWidth(); + x = getX() - dis - descWindow.getWidth(); if (x < screenBounds.x) { // Doesn't fit - x = getX() + getWidth() + 5; + x = getX() + getWidth() + dis; } } @@ -709,7 +711,7 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, private void uninstallKeyBindings() { if (AutoCompletion.isDebug()) { - System.out.println("PopupWindow: Removing keybindings"); + FRLogger.getLogger().debug("PopupWindow: Removing keybindings"); } JTextComponent comp = ac.getTextComponent(); diff --git a/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletion.java b/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletion.java index d5447880b1..fb5f2b7639 100644 --- a/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletion.java +++ b/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletion.java @@ -277,7 +277,7 @@ public class AutoCompletion { * @return Whether to auto-complete single choices. * @see #setAutoCompleteSingleChoices(boolean) */ - public boolean getAutoCompleteSingleChoices() { + public boolean isAutoCompleteSingleChoices() { return autoCompleteSingleChoices; } @@ -730,7 +730,7 @@ public class AutoCompletion { private boolean needSetPopupWindow(int count, int textLen) { return (count == 1 && (isPopupVisible() || textLen == 0)) - || (count == 1 && !getAutoCompleteSingleChoices()) + || (count == 1 && !isAutoCompleteSingleChoices()) || count > 1; } @@ -809,7 +809,7 @@ public class AutoCompletion { * be automatically inserted, without displaying the popup menu. * * @param autoComplete Whether to auto-complete single choices. - * @see #getAutoCompleteSingleChoices() + * @see #isAutoCompleteSingleChoices() */ public void setAutoCompleteSingleChoices(boolean autoComplete) { autoCompleteSingleChoices = autoComplete; diff --git a/designer_base/src/com/fr/design/gui/autocomplete/ParameterizedCompletionContext.java b/designer_base/src/com/fr/design/gui/autocomplete/ParameterizedCompletionContext.java index 966035b894..11bab3a7e6 100644 --- a/designer_base/src/com/fr/design/gui/autocomplete/ParameterizedCompletionContext.java +++ b/designer_base/src/com/fr/design/gui/autocomplete/ParameterizedCompletionContext.java @@ -14,6 +14,7 @@ import com.fr.design.gui.autocomplete.ParameterizedCompletionInsertionInfo.Repla import com.fr.design.gui.syntax.ui.rsyntaxtextarea.DocumentRange; import com.fr.design.gui.syntax.ui.rsyntaxtextarea.RSyntaxTextArea; import com.fr.design.gui.syntax.ui.rtextarea.ChangeableHighlightPainter; +import com.fr.general.FRLogger; import javax.swing.*; import javax.swing.event.CaretEvent; @@ -254,7 +255,7 @@ class ParameterizedCompletionContext { * * @param offs The offset into the document. * @return The text of the parameter containing the offset, or - * null if the offset is not in a parameter. + * null if the offset is not in a parameter. */ public String getArgumentText(int offs) { List paramHighlights = getParameterHighlights(); @@ -284,7 +285,7 @@ class ParameterizedCompletionContext { * Returns the highlight of the current parameter. * * @return The current parameter's highlight, or null if - * the caret is not in a parameter's bounds. + * the caret is not in a parameter's bounds. * @see #getCurrentParameterStartOffset() */ private Highlight getCurrentParameterHighlight() { @@ -332,7 +333,7 @@ class ParameterizedCompletionContext { * Returns the starting offset of the current parameter. * * @return The current parameter's starting offset, or -1 if - * the caret is not in a parameter's bounds. + * the caret is not in a parameter's bounds. * @see #getCurrentParameterHighlight() */ private int getCurrentParameterStartOffset() { @@ -407,7 +408,7 @@ class ParameterizedCompletionContext { * Inserts the choice selected in the parameter choices window. * * @return Whether the choice was inserted. This will be false - * if the window is not visible, or no choice is selected. + * if the window is not visible, or no choice is selected. */ boolean insertSelectedChoice() { if (paramChoicesWindow != null && paramChoicesWindow.isVisible()) { @@ -438,11 +439,9 @@ class ParameterizedCompletionContext { * @see #uninstallKeyBindings() */ private void installKeyBindings() { - if (AutoCompletion.isDebug()) { - System.out.println("CompletionContext: Installing keybindings"); + FRLogger.getLogger().debug("CompletionContext: Installing keybindings"); } - JTextComponent tc = ac.getTextComponent(); InputMap im = tc.getInputMap(); ActionMap am = tc.getActionMap(); @@ -489,7 +488,6 @@ class ParameterizedCompletionContext { im.put(ks, IM_KEY_CLOSING); oldClosingAction = am.get(IM_KEY_CLOSING); am.put(IM_KEY_CLOSING, new ClosingAction()); - } @@ -513,12 +511,7 @@ class ParameterizedCompletionContext { List highlights = getParameterHighlights(); for (int i = 0; i < highlights.size(); i++) { Highlight hl = highlights.get(i); - // Check "< dot", not "<= dot" as OutlineHighlightPainter paints - // starting at one char AFTER the highlight starts, to work around - // Java issue. Thanks to Matthew Adereth! - if (currentNext == null || currentNext.getStartOffset() dot && - hl.getStartOffset() <= currentNext.getStartOffset())) { + if (needUpdate(currentNext, hl, dot)) { currentNext = hl; pos = i; } @@ -538,6 +531,15 @@ class ParameterizedCompletionContext { } + private boolean needUpdate(Highlight currentNext, Highlight hl, int dot) { + // Check "< dot", not "<= dot" as OutlineHighlightPainter paints + // starting at one char AFTER the highlight starts, to work around + // Java issue. Thanks to Matthew Adereth! + return currentNext == null || currentNext.getStartOffset() dot && + hl.getStartOffset() <= currentNext.getStartOffset()); + } + /** * Moves to and selects the previous parameter. @@ -562,10 +564,7 @@ class ParameterizedCompletionContext { for (int i = 0; i < highlights.size(); i++) { Highlight h = highlights.get(i); - if (currentPrev == null || currentPrev.getStartOffset() >= dot || - (h.getStartOffset() < selStart && - (h.getStartOffset() > currentPrev.getStartOffset() || - pos == lastSelectedParam))) { + if (pos == lastSelectedParam || needUpdate(currentPrev, dot, h, selStart)) { currentPrev = h; pos = i; } @@ -593,6 +592,12 @@ class ParameterizedCompletionContext { } + private boolean needUpdate(Highlight currentPrev, int dot, Highlight h, int selStart) { + return currentPrev == null + || currentPrev.getStartOffset() >= dot + || (currentPrev.getStartOffset() < h.getStartOffset() && h.getStartOffset() < selStart); + } + private void possiblyUpdateParamCopies(Document doc) { @@ -616,7 +621,7 @@ class ParameterizedCompletionContext { try { replacement = doc.getText(start, len); } catch (BadLocationException ble) { - // Never happens + // Never happens } // Replace any param copies tracking this parameter with the @@ -718,7 +723,7 @@ class ParameterizedCompletionContext { return h; } catch (BadLocationException ble) { - // Never happens + // Never happens } return null; @@ -734,7 +739,7 @@ class ParameterizedCompletionContext { private void uninstallKeyBindings() { if (AutoCompletion.isDebug()) { - System.out.println("CompletionContext Uninstalling keybindings"); + FRLogger.getLogger().debug("CompletionContext Uninstalling keybindings"); } JTextComponent tc = ac.getTextComponent(); @@ -1037,7 +1042,6 @@ class ParameterizedCompletionContext { * @see #uninstall() */ public void install(JTextComponent tc) { - boolean replaceTabs = false; if (tc instanceof RSyntaxTextArea) { RSyntaxTextArea textArea = (RSyntaxTextArea) tc; @@ -1047,14 +1051,10 @@ class ParameterizedCompletionContext { } Highlighter h = tc.getHighlighter(); - try { - // Insert the parameter text - ParameterizedCompletionInsertionInfo info = - pc.getInsertionInfo(tc, replaceTabs); + ParameterizedCompletionInsertionInfo info = pc.getInsertionInfo(tc, replaceTabs); tc.replaceSelection(info.getTextToInsert()); - // Add highlights around the parameters. final int replacementCount = info.getReplacementCount(); for (int i = 0; i < replacementCount; i++) { @@ -1067,40 +1067,31 @@ class ParameterizedCompletionContext { for (int i = 0; i < info.getReplacementCopyCount(); i++) { ReplacementCopy rc = info.getReplacementCopy(i); paramCopyInfos.add(new ParamCopyInfo(rc.getId(), - (Highlight) h.addHighlight(rc.getStart(), rc.getEnd(), - paramCopyP))); + (Highlight) h.addHighlight(rc.getStart(), rc.getEnd(), paramCopyP))); } - // Go back and start at the first parameter. tc.setCaretPosition(info.getSelectionStart()); if (info.hasSelection()) { tc.moveCaretPosition(info.getSelectionEnd()); } - minPos = info.getMinOffset(); maxPos = info.getMaxOffset(); try { - defaultEndOffs = tc.getDocument().createPosition( - info.getDefaultEndOffs()); + defaultEndOffs = tc.getDocument().createPosition(info.getDefaultEndOffs()); } catch (BadLocationException ble) { - // Never happens + // Never happens } - // Listen for document events AFTER we insert tc.getDocument().addDocumentListener(this); - } catch (BadLocationException ble) { - // Never happens + // Never happens } - // Add listeners to the text component, AFTER text insertion. tc.addCaretListener(this); tc.addFocusListener(this); installKeyBindings(); - } - public void removeUpdate(DocumentEvent e) { handleDocumentEvent(e); } diff --git a/designer_base/src/com/fr/design/gui/itabpane/UITabsHeaderIconPane.java b/designer_base/src/com/fr/design/gui/itabpane/UITabsHeaderIconPane.java index ba77523520..8bb2f7b05f 100644 --- a/designer_base/src/com/fr/design/gui/itabpane/UITabsHeaderIconPane.java +++ b/designer_base/src/com/fr/design/gui/itabpane/UITabsHeaderIconPane.java @@ -10,6 +10,7 @@ import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import javax.swing.AbstractAction; @@ -145,9 +146,7 @@ public class UITabsHeaderIconPane extends JPanel implements UITabComponent { private void show(final JPanel panel) { int count = centerPane.getComponentCount();// 获取centerPanel中控件数 List list = new ArrayList();// - for (Component comp : centerPane.getComponents()) { - list.add(comp); - } + list.addAll(Arrays.asList(centerPane.getComponents())); if (count > 0) {// 如果centerPanel中控件数大于0就执行效果 for (int i = 0; i < count; i++) { Component comp = centerPane.getComponent(i);// 获得该位置的控件 @@ -160,14 +159,12 @@ public class UITabsHeaderIconPane extends JPanel implements UITabComponent { public void run() { int height = centerPane.getHeight(); int width = centerPane.getWidth(); - int step = 30; - int x = 0; int y = -height; - for (int i = 0; i <= height; i += step) { + for (int i = 0; i <= height; i += 30) { // 设置面板位置 - currentPanel.setBounds(x, i, width, height); - panel.setBounds(x, y, width, height); - y += step; + currentPanel.setBounds(0, i, width, height); + panel.setBounds(0, y, width, height); + y += 30; try { Thread.sleep(3); } catch (InterruptedException e) { From e959791ed3f17ae10d31edce3707d697cacf5b7d Mon Sep 17 00:00:00 2001 From: hzzz Date: Thu, 25 May 2017 14:43:48 +0800 Subject: [PATCH 22/41] =?UTF-8?q?=E5=B1=80=E9=83=A8=E5=8F=98=E9=87=8F?= =?UTF-8?q?=E4=B8=8D=E8=A1=8C..=E8=BF=98=E6=98=AF=E6=94=B9=E5=9B=9E?= =?UTF-8?q?=E5=8E=BB=E5=90=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../design/gui/autocomplete/AutoCompletePopupWindow.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletePopupWindow.java b/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletePopupWindow.java index 4dced3a833..ec303ee44f 100644 --- a/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletePopupWindow.java +++ b/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletePopupWindow.java @@ -387,16 +387,15 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, // Try to position to the right first (LTR) int x; - int dis = 5; if (ac.getTextComponentOrientation().isLeftToRight()) { - x = getX() + getWidth() + dis; + x = getX() + getWidth() + 5; if (x + descWindow.getWidth() > screenBounds.x + screenBounds.width) { // doesn't fit - x = getX() - dis - descWindow.getWidth(); + x = getX() - 5 - descWindow.getWidth(); } } else { // RTL - x = getX() - dis - descWindow.getWidth(); + x = getX() - 5 - descWindow.getWidth(); if (x < screenBounds.x) { // Doesn't fit - x = getX() + getWidth() + dis; + x = getX() + getWidth() + 5; } } From c6d1d6d9eedc600c78d03416a6132531444d8164 Mon Sep 17 00:00:00 2001 From: hzzz Date: Thu, 25 May 2017 14:53:59 +0800 Subject: [PATCH 23/41] PMD --- .../autocomplete/AutoCompletePopupWindow.java | 9 ++-- .../gui/itabpane/UITabsHeaderIconPane.java | 44 ++++++------------- .../widget/editors/DataTableConfigPane.java | 8 ++-- 3 files changed, 24 insertions(+), 37 deletions(-) diff --git a/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletePopupWindow.java b/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletePopupWindow.java index ec303ee44f..22bb4edf77 100644 --- a/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletePopupWindow.java +++ b/designer_base/src/com/fr/design/gui/autocomplete/AutoCompletePopupWindow.java @@ -41,6 +41,7 @@ import java.util.List; class AutoCompletePopupWindow extends JWindow implements CaretListener, ListSelectionListener, MouseListener { + private final static int DIS = 5; /** * The parent AutoCompletion instance. */ @@ -388,14 +389,14 @@ class AutoCompletePopupWindow extends JWindow implements CaretListener, // Try to position to the right first (LTR) int x; if (ac.getTextComponentOrientation().isLeftToRight()) { - x = getX() + getWidth() + 5; + x = getX() + getWidth() + DIS; if (x + descWindow.getWidth() > screenBounds.x + screenBounds.width) { // doesn't fit - x = getX() - 5 - descWindow.getWidth(); + x = getX() - DIS - descWindow.getWidth(); } } else { // RTL - x = getX() - 5 - descWindow.getWidth(); + x = getX() - DIS - descWindow.getWidth(); if (x < screenBounds.x) { // Doesn't fit - x = getX() + getWidth() + 5; + x = getX() + getWidth() + DIS; } } diff --git a/designer_base/src/com/fr/design/gui/itabpane/UITabsHeaderIconPane.java b/designer_base/src/com/fr/design/gui/itabpane/UITabsHeaderIconPane.java index 8bb2f7b05f..84f0cd35f6 100644 --- a/designer_base/src/com/fr/design/gui/itabpane/UITabsHeaderIconPane.java +++ b/designer_base/src/com/fr/design/gui/itabpane/UITabsHeaderIconPane.java @@ -1,38 +1,22 @@ package com.fr.design.gui.itabpane; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.GradientPaint; -import java.awt.Graphics2D; -import java.awt.GridLayout; +import com.fr.base.BaseUtils; +import com.fr.design.constants.UIConstants; +import com.fr.design.gui.core.UITabComponent; +import com.fr.design.gui.ibutton.UITabButton; +import com.fr.design.gui.ilable.UILabel; +import com.fr.stable.StringUtils; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import javax.swing.AbstractAction; -import javax.swing.ActionMap; -import javax.swing.BorderFactory; -import javax.swing.Icon; -import javax.swing.InputMap; -import javax.swing.JComponent; - -import com.fr.design.constants.UIConstants; -import com.fr.design.gui.ilable.UILabel; -import javax.swing.JPanel; -import javax.swing.KeyStroke; -import javax.swing.SwingConstants; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; - -import com.fr.base.BaseUtils; -import com.fr.design.gui.core.UITabComponent; -import com.fr.design.gui.ibutton.UITabButton; -import com.fr.stable.StringUtils; - import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_MODIFIER; /** @@ -43,6 +27,7 @@ import static com.fr.design.gui.syntax.ui.rtextarea.RTADefaultInputMap.DEFAULT_M */ public class UITabsHeaderIconPane extends JPanel implements UITabComponent { private static final long serialVersionUID = 1L; + private static final int DIS = 30; private UILabel nameLabel; @@ -160,11 +145,11 @@ public class UITabsHeaderIconPane extends JPanel implements UITabComponent { int height = centerPane.getHeight(); int width = centerPane.getWidth(); int y = -height; - for (int i = 0; i <= height; i += 30) { + for (int i = 0; i <= height; i += DIS) { // 设置面板位置 currentPanel.setBounds(0, i, width, height); panel.setBounds(0, y, width, height); - y += 30; + y += DIS; try { Thread.sleep(3); } catch (InterruptedException e) { @@ -174,7 +159,6 @@ public class UITabsHeaderIconPane extends JPanel implements UITabComponent { centerPane.remove(currentPanel);// 移除当前面板 } panel.setBounds(0, 0, width, height); - } }.start(); break; diff --git a/designer_form/src/com/fr/design/mainframe/widget/editors/DataTableConfigPane.java b/designer_form/src/com/fr/design/mainframe/widget/editors/DataTableConfigPane.java index a45d9fa255..00d70bd1e7 100644 --- a/designer_form/src/com/fr/design/mainframe/widget/editors/DataTableConfigPane.java +++ b/designer_form/src/com/fr/design/mainframe/widget/editors/DataTableConfigPane.java @@ -157,6 +157,8 @@ public class DataTableConfigPane extends JComponent implements PropertyChangeLis } class MouseAdapterListener extends MouseAdapter { + private final static int DIS = 30; + private final static int SMALL_DIS = 3; private JTable table; int oldY = 0; int newY = 0; @@ -205,7 +207,7 @@ public class DataTableConfigPane extends JComponent implements PropertyChangeLis height = height + table.getRowHeight(i); } - if (height - e.getY() < 3) { + if (height - e.getY() < SMALL_DIS) { drag = true; table.setCursor(new Cursor(Cursor.N_RESIZE_CURSOR)); } else { @@ -223,8 +225,8 @@ public class DataTableConfigPane extends JComponent implements PropertyChangeLis public void mouseDragged(MouseEvent e) { if (drag) { int value = oldHeight + e.getY() - oldY; - if (value < 30) { - table.setRowHeight(row, 30); + if (value < DIS) { + table.setRowHeight(row, DIS); } else { table.setRowHeight(row, oldHeight + e.getY() - oldY); } From 1f5114ede1d693529a6f0a2ad9cc8dd4b44d5d43 Mon Sep 17 00:00:00 2001 From: hzzz Date: Fri, 26 May 2017 09:31:27 +0800 Subject: [PATCH 24/41] =?UTF-8?q?REPORT-2773=20mac=E4=B8=AD=E5=A4=8D?= =?UTF-8?q?=E5=88=B6=E5=BF=AB=E6=8D=B7=E9=94=AE=E7=9A=84=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- designer/src/com/fr/grid/GridKeyListener.java | 397 +++++++++--------- 1 file changed, 200 insertions(+), 197 deletions(-) diff --git a/designer/src/com/fr/grid/GridKeyListener.java b/designer/src/com/fr/grid/GridKeyListener.java index cf2258a4fb..6c82a9dcd1 100644 --- a/designer/src/com/fr/grid/GridKeyListener.java +++ b/designer/src/com/fr/grid/GridKeyListener.java @@ -1,212 +1,215 @@ package com.fr.grid; -import java.awt.Toolkit; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; - import com.fr.design.mainframe.ElementCasePane; import com.fr.grid.selection.CellSelection; import com.fr.grid.selection.FloatSelection; import com.fr.grid.selection.Selection; import com.fr.report.elementcase.ElementCase; +import com.fr.stable.OperatingSystem; + +import java.awt.*; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; /** - * * @editor zhou * @since 2012-3-23上午10:55:36 */ public class GridKeyListener implements KeyListener { - private Grid grid; - // Keypressed last time - private long keyPressedLastTime = 0; - private boolean isKeyPressedContentChanged = false; - - public GridKeyListener(Grid grid) { - this.grid = grid; - } - - public void keyPressed(KeyEvent evt) { - if (!grid.isEnabled() || evt.isConsumed()) {// 如果用户在自己的KyeListener里面consume了.就不执行下面的代码了. - return; - } - KeyEvent newEvt = KeyEventWork.processKeyEvent(evt); - if (newEvt == null) { - return; - } - long systemCurrentTime = System.currentTimeMillis(); - int code = evt.getKeyCode(); - boolean isNeedRepaint = false; - ElementCasePane reportPane = grid.getElementCasePane(); - ElementCase report = reportPane.getEditingElementCase(); - if (reportPane.getSelection() instanceof FloatSelection) { - if (systemCurrentTime - keyPressedLastTime <= 2) { - return; - } else { - keyPressedLastTime = systemCurrentTime; - } - dealWithFloatSelection(reportPane, code); - - } else { - if (systemCurrentTime - keyPressedLastTime <= 32) { - return; - } else { - keyPressedLastTime = systemCurrentTime; - } - dealWithCellSelection(evt, code); - - } - - switch (code) { - case KeyEvent.VK_PAGE_UP: {// page up - reportPane.getVerticalScrollBar().setValue(Math.max(0, grid.getVerticalValue() - grid.getVerticalExtent())); - isNeedRepaint = true; - break; - } - case KeyEvent.VK_PAGE_DOWN: {// page down - reportPane.getVerticalScrollBar().setValue(grid.getVerticalValue() + grid.getVerticalExtent()); - isNeedRepaint = true; - break; - } - // Richie:Ctrl + A全选单元格 - case KeyEvent.VK_A: - if (code == KeyEvent.VK_A && evt.isControlDown()) { - reportPane.setSelection(new CellSelection(0, 0, report.getColumnCount(), report.getRowCount())); - isNeedRepaint = true; - } - isNeedRepaint = true; - break; - } - - if (isNeedRepaint) { - reportPane.repaint(); - } - } - - /** - * 单选中悬浮元素时,只处理4个方向键 - * - * @param reportPane - * @param code - */ - private void dealWithFloatSelection(ElementCasePane reportPane, int code) { - boolean isContentChanged = false; - FloatSelection floatselection = (FloatSelection)reportPane.getSelection(); - - switch (code) { - case KeyEvent.VK_LEFT: {// left - floatselection.moveLeft(reportPane); - isContentChanged = true; - break; - } - case KeyEvent.VK_RIGHT: {// right - floatselection.moveRight(reportPane); - isContentChanged = true; - break; - } - case KeyEvent.VK_UP: {// up - floatselection.moveUp(reportPane); - isContentChanged = true; - break; - } - case KeyEvent.VK_DOWN: {// down - floatselection.moveDown(reportPane); - isContentChanged = true; - break; - } - } - - if (isContentChanged) { - grid.getElementCasePane().repaint(); - this.isKeyPressedContentChanged = true; - } - } - - private void dealWithCellSelection(KeyEvent evt, int code) { - switch (code) { - case KeyEvent.VK_ESCAPE: { - if (grid.isCellEditing()) { - grid.cancelEditing(); - } - break; - } - case KeyEvent.VK_F2: { - if (!grid.isCellEditing()) { - grid.startEditing(); - } - - break; - } - } - - // 支持小键盘 - if (IS_NUM_PAD_KEY(code)) { - keyTyped(evt); - } - } - - public void keyReleased(KeyEvent evt) { - if (!grid.isEnabled() || evt.isConsumed()) { - return; - } - KeyEvent newEvt = KeyEventWork.processKeyEvent(evt); - if (newEvt == null) { - return; - } - - if (this.isKeyPressedContentChanged) { - grid.getElementCasePane().fireTargetModified(); - - this.isKeyPressedContentChanged = false; - } - } - - public void keyTyped(KeyEvent evt) { - if (!grid.isEnabled() || evt.isConsumed()) { - return; - } - KeyEvent newEvt = KeyEventWork.processKeyEvent(evt); - if (newEvt == null || evt.isControlDown()) {// uneditable. - return; - } - char ch = evt.getKeyChar(); - if (ch == KeyEvent.VK_TAB) {// 禁止Tab键. - return; - } - int code = evt.getKeyCode(); - if (Character.isDefined(ch)) {// VK_SUBTRACT小键盘的减号 - Selection s = grid.getElementCasePane().getSelection(); - if (s instanceof CellSelection) { - if (!grid.getElementCasePane().isSelectedOneCell()) { - Toolkit.getDefaultToolkit().beep(); - return; - } - if (!grid.isCellEditing()) { - grid.startEditing(true); - } - - if (grid.getCellEditor() != null && grid.editorComponent != null) { - if (IS_NUM_PAD_KEY(code)) { - // 103 - 55 = 48, 小键盘和大键盘数字的差值 48 - KeyEvent ke = new KeyEvent(grid, KeyEvent.KEY_PRESSED, 0, 0, code - 48, ch); - grid.editorComponent.dispatchEvent(ke); - ke.consume(); - } else { - if (!evt.isConsumed()) { - grid.editorComponent.dispatchEvent(evt); - } - } - } - } - } - } - /** - * 小键盘 - * @param code - * @return - */ - private static boolean IS_NUM_PAD_KEY(int code){ - return code == KeyEvent.VK_NUMPAD0 || code == KeyEvent.VK_NUMPAD1 + private Grid grid; + // Keypressed last time + private long keyPressedLastTime = 0; + private boolean isKeyPressedContentChanged = false; + + public GridKeyListener(Grid grid) { + this.grid = grid; + } + + public void keyPressed(KeyEvent evt) { + if (!grid.isEnabled() || evt.isConsumed()) {// 如果用户在自己的KyeListener里面consume了.就不执行下面的代码了. + return; + } + KeyEvent newEvt = KeyEventWork.processKeyEvent(evt); + if (newEvt == null) { + return; + } + long systemCurrentTime = System.currentTimeMillis(); + int code = evt.getKeyCode(); + boolean isNeedRepaint = false; + ElementCasePane reportPane = grid.getElementCasePane(); + ElementCase report = reportPane.getEditingElementCase(); + if (reportPane.getSelection() instanceof FloatSelection) { + if (systemCurrentTime - keyPressedLastTime <= 2) { + return; + } else { + keyPressedLastTime = systemCurrentTime; + } + dealWithFloatSelection(reportPane, code); + + } else { + if (systemCurrentTime - keyPressedLastTime <= 32) { + return; + } else { + keyPressedLastTime = systemCurrentTime; + } + dealWithCellSelection(evt, code); + + } + + switch (code) { + case KeyEvent.VK_PAGE_UP: {// page up + reportPane.getVerticalScrollBar().setValue(Math.max(0, grid.getVerticalValue() - grid.getVerticalExtent())); + isNeedRepaint = true; + break; + } + case KeyEvent.VK_PAGE_DOWN: {// page down + reportPane.getVerticalScrollBar().setValue(grid.getVerticalValue() + grid.getVerticalExtent()); + isNeedRepaint = true; + break; + } + // Richie:Ctrl + A全选单元格 + case KeyEvent.VK_A: + if ((OperatingSystem.isWindows() && evt.isControlDown()) + || OperatingSystem.isMacOS() && evt.isMetaDown()) { + reportPane.setSelection(new CellSelection(0, 0, report.getColumnCount(), report.getRowCount())); + isNeedRepaint = true; + } + isNeedRepaint = true; + break; + } + + if (isNeedRepaint) { + reportPane.repaint(); + } + } + + /** + * 单选中悬浮元素时,只处理4个方向键 + * + * @param reportPane + * @param code + */ + private void dealWithFloatSelection(ElementCasePane reportPane, int code) { + boolean isContentChanged = false; + FloatSelection floatselection = (FloatSelection) reportPane.getSelection(); + + switch (code) { + case KeyEvent.VK_LEFT: {// left + floatselection.moveLeft(reportPane); + isContentChanged = true; + break; + } + case KeyEvent.VK_RIGHT: {// right + floatselection.moveRight(reportPane); + isContentChanged = true; + break; + } + case KeyEvent.VK_UP: {// up + floatselection.moveUp(reportPane); + isContentChanged = true; + break; + } + case KeyEvent.VK_DOWN: {// down + floatselection.moveDown(reportPane); + isContentChanged = true; + break; + } + } + + if (isContentChanged) { + grid.getElementCasePane().repaint(); + this.isKeyPressedContentChanged = true; + } + } + + private void dealWithCellSelection(KeyEvent evt, int code) { + switch (code) { + case KeyEvent.VK_ESCAPE: { + if (grid.isCellEditing()) { + grid.cancelEditing(); + } + break; + } + case KeyEvent.VK_F2: { + if (!grid.isCellEditing()) { + grid.startEditing(); + } + + break; + } + } + + // 支持小键盘 + if (IS_NUM_PAD_KEY(code)) { + keyTyped(evt); + } + } + + public void keyReleased(KeyEvent evt) { + if (!grid.isEnabled() || evt.isConsumed()) { + return; + } + KeyEvent newEvt = KeyEventWork.processKeyEvent(evt); + if (newEvt == null) { + return; + } + + if (this.isKeyPressedContentChanged) { + grid.getElementCasePane().fireTargetModified(); + + this.isKeyPressedContentChanged = false; + } + } + + public void keyTyped(KeyEvent evt) { + if (!grid.isEnabled() || evt.isConsumed()) { + return; + } + KeyEvent newEvt = KeyEventWork.processKeyEvent(evt); + if (newEvt == null || evt.isControlDown()) {// uneditable. + return; + } + char ch = evt.getKeyChar(); + if (ch == KeyEvent.VK_TAB) {// 禁止Tab键. + return; + } + int code = evt.getKeyCode(); + if (Character.isDefined(ch)) {// VK_SUBTRACT小键盘的减号 + Selection s = grid.getElementCasePane().getSelection(); + if (s instanceof CellSelection) { + if (!grid.getElementCasePane().isSelectedOneCell()) { + Toolkit.getDefaultToolkit().beep(); + return; + } + if (!grid.isCellEditing()) { + grid.startEditing(true); + } + + if (grid.getCellEditor() != null && grid.editorComponent != null) { + if (IS_NUM_PAD_KEY(code)) { + // 103 - 55 = 48, 小键盘和大键盘数字的差值 48 + KeyEvent ke = new KeyEvent(grid, KeyEvent.KEY_PRESSED, 0, 0, code - 48, ch); + grid.editorComponent.dispatchEvent(ke); + ke.consume(); + } else { + if (!evt.isConsumed()) { + grid.editorComponent.dispatchEvent(evt); + } + } + } + } + } + } + + /** + * 小键盘 + * + * @param code + * @return + */ + private static boolean IS_NUM_PAD_KEY(int code) { + return code == KeyEvent.VK_NUMPAD0 || code == KeyEvent.VK_NUMPAD1 || code == KeyEvent.VK_NUMPAD2 || code == KeyEvent.VK_NUMPAD3 || code == KeyEvent.VK_NUMPAD4 @@ -215,10 +218,10 @@ public class GridKeyListener implements KeyListener { || code == KeyEvent.VK_NUMPAD7 || code == KeyEvent.VK_NUMPAD8 || code == KeyEvent.VK_NUMPAD9 - || code == KeyEvent.VK_MULTIPLY + || code == KeyEvent.VK_MULTIPLY || code == KeyEvent.VK_ADD || code == KeyEvent.VK_SUBTRACT || code == KeyEvent.VK_DECIMAL || code == KeyEvent.VK_DIVIDE; - } + } } \ No newline at end of file From d257489ee45f057161b837deba99a408f4159852 Mon Sep 17 00:00:00 2001 From: hzzz Date: Fri, 26 May 2017 09:33:02 +0800 Subject: [PATCH 25/41] =?UTF-8?q?REPORT-2773=20mac=E4=B8=AD=E5=A4=8D?= =?UTF-8?q?=E5=88=B6=E5=BF=AB=E6=8D=B7=E9=94=AE=E7=9A=84=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- designer_base/src/com/fr/design/actions/help/AboutPane.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/designer_base/src/com/fr/design/actions/help/AboutPane.java b/designer_base/src/com/fr/design/actions/help/AboutPane.java index 9c8953597d..1155f4e921 100644 --- a/designer_base/src/com/fr/design/actions/help/AboutPane.java +++ b/designer_base/src/com/fr/design/actions/help/AboutPane.java @@ -47,7 +47,7 @@ public class AboutPane extends JPanel { BoxCenterAlignmentCopyablePane buildCopyPane = new BoxCenterAlignmentCopyablePane( getBuildTitle(), - GeneralUtils.readBuildNO(), + GeneralUtils.readFullBuildNO(), new String[]{ Inter.getLocText("FR-Designer-Basic_Copy_Build_NO"), Inter.getLocText("FR-Designer-Basic_Copy_Build_NO_OK") From 3f29a1be5aa602c1b369a84be1fac7af05cec03a Mon Sep 17 00:00:00 2001 From: hzzz Date: Fri, 26 May 2017 09:34:42 +0800 Subject: [PATCH 26/41] PMD --- designer/src/com/fr/grid/GridKeyListener.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/designer/src/com/fr/grid/GridKeyListener.java b/designer/src/com/fr/grid/GridKeyListener.java index 6c82a9dcd1..a7d6eb3545 100644 --- a/designer/src/com/fr/grid/GridKeyListener.java +++ b/designer/src/com/fr/grid/GridKeyListener.java @@ -70,8 +70,9 @@ public class GridKeyListener implements KeyListener { } // Richie:Ctrl + A全选单元格 case KeyEvent.VK_A: - if ((OperatingSystem.isWindows() && evt.isControlDown()) - || OperatingSystem.isMacOS() && evt.isMetaDown()) { + boolean macOS = OperatingSystem.isMacOS() && evt.isMetaDown(); + boolean windows = OperatingSystem.isWindows() && evt.isControlDown(); + if (macOS || windows) { reportPane.setSelection(new CellSelection(0, 0, report.getColumnCount(), report.getRowCount())); isNeedRepaint = true; } From 9c6a862e4337919dfc5abb76275ac7f0513e040a Mon Sep 17 00:00:00 2001 From: hzzz Date: Fri, 26 May 2017 09:37:07 +0800 Subject: [PATCH 27/41] PMD --- designer/src/com/fr/grid/GridKeyListener.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/designer/src/com/fr/grid/GridKeyListener.java b/designer/src/com/fr/grid/GridKeyListener.java index a7d6eb3545..8e3148bf56 100644 --- a/designer/src/com/fr/grid/GridKeyListener.java +++ b/designer/src/com/fr/grid/GridKeyListener.java @@ -16,7 +16,7 @@ import java.awt.event.KeyListener; * @since 2012-3-23上午10:55:36 */ public class GridKeyListener implements KeyListener { - + private static final int DIFF = 48; // 103 - 55 = 48, 小键盘和大键盘数字的差值 48 private Grid grid; // Keypressed last time private long keyPressedLastTime = 0; @@ -189,8 +189,7 @@ public class GridKeyListener implements KeyListener { if (grid.getCellEditor() != null && grid.editorComponent != null) { if (IS_NUM_PAD_KEY(code)) { - // 103 - 55 = 48, 小键盘和大键盘数字的差值 48 - KeyEvent ke = new KeyEvent(grid, KeyEvent.KEY_PRESSED, 0, 0, code - 48, ch); + KeyEvent ke = new KeyEvent(grid, KeyEvent.KEY_PRESSED, 0, 0, code - DIFF, ch); grid.editorComponent.dispatchEvent(ke); ke.consume(); } else { From 84f091a2f46203d0e5fe2a40448d6e0f45018b88 Mon Sep 17 00:00:00 2001 From: hzzz Date: Fri, 26 May 2017 09:53:18 +0800 Subject: [PATCH 28/41] =?UTF-8?q?REPORT-2773=20mac=E4=B8=AD=E5=A4=8D?= =?UTF-8?q?=E5=88=B6=E5=BF=AB=E6=8D=B7=E9=94=AE=E7=9A=84=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mainframe/AuthorityToolBarPane.java | 366 +++- designer/src/com/fr/grid/GridKeyListener.java | 5 +- .../src/com/fr/grid/GridMouseAdapter.java | 1605 ++++++++--------- .../common/inputevent/InputEventBaseOnOS.java | 21 + .../gui/icombobox/ExtendedComboBox.java | 4 +- .../fr/design/gui/icombobox/UIComboBoxUI.java | 3 +- .../com/fr/design/gui/ilist/CheckBoxList.java | 3 +- .../com/fr/design/gui/itable/TableSorter.java | 4 +- .../UserObjectRefreshJTree.java | 3 +- .../fr/design/roleAuthority/UIRoleTreeUI.java | 3 +- .../designer/beans/models/SelectionModel.java | 5 +- 11 files changed, 1205 insertions(+), 817 deletions(-) create mode 100644 designer_base/src/com/fr/common/inputevent/InputEventBaseOnOS.java diff --git a/designer/src/com/fr/design/mainframe/AuthorityToolBarPane.java b/designer/src/com/fr/design/mainframe/AuthorityToolBarPane.java index 80f40cadfe..fcb6988b95 100644 --- a/designer/src/com/fr/design/mainframe/AuthorityToolBarPane.java +++ b/designer/src/com/fr/design/mainframe/AuthorityToolBarPane.java @@ -1 +1,365 @@ -package com.fr.design.mainframe; import com.fr.base.ConfigManager; import com.fr.base.ConfigManagerProvider; import com.fr.base.FRContext; import com.fr.design.beans.BasicBeanPane; import com.fr.design.file.HistoryTemplateListPane; import com.fr.design.gui.icombobox.UIComboBox; import com.fr.design.gui.ilable.UILabel; import com.fr.design.mainframe.toolbar.AuthorityEditToolBarComponent; import com.fr.design.mainframe.toolbar.ToolBarMenuDock; import com.fr.design.roleAuthority.RolesAlreadyEditedPane; import com.fr.design.webattr.ReportWebWidgetConstants; import com.fr.design.webattr.ToolBarButton; import com.fr.design.webattr.ToolBarPane; import com.fr.form.ui.Button; import com.fr.form.ui.ToolBar; import com.fr.form.ui.Widget; import com.fr.general.ComparatorUtils; import com.fr.general.Inter; import com.fr.main.TemplateWorkBook; import com.fr.report.web.Location; import com.fr.report.web.ToolBarManager; import com.fr.report.web.WebContent; import com.fr.stable.ArrayUtils; import com.fr.web.attr.ReportWebAttr; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.List; /** * Author : daisy * Date: 13-9-9 * Time: 下午4:58 */ public class AuthorityToolBarPane extends BasicBeanPane implements AuthorityEditToolBarComponent { private static final int SMALL_GAP = 13; private static final int GAP = 25; private static final int PRE_GAP = 9; private static final int COMBOX_WIDTH = 144; private static final String[] CHOOSEITEM = new String[]{Inter.getLocText("M-Page_Preview"), Inter.getLocText(new String[]{"Face_Write", "PageSetup-Page"}), Inter.getLocText("M-Data_Analysis")}; private UIComboBox choseComboBox; private ToolBarPane toolBarPane; private AuthorityEditToolBarPane authorityEditToolBarPane = null; private int selectedIndex = -1; private UILabel title = null; private MouseListener mouseListener = new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (!toolBarPane.isEnabled()) { return; } java.util.List buttonlists = toolBarPane.getToolBarButtons(); int oldIndex = selectedIndex; selectedIndex = pressButtonIndex(e, buttonlists); //实现shift多选 if (e.isShiftDown()) { if (oldIndex == -1) { removeSelection(); ((ToolBarButton) e.getSource()).setSelected(true); } else { int max = oldIndex >= selectedIndex ? oldIndex : selectedIndex; int min = oldIndex <= selectedIndex ? oldIndex : selectedIndex; for (int i = min; i <= max; i++) { buttonlists.get(i).setSelected(true); } } } else if (!e.isControlDown()) { //实现单选 removeSelection(); if (selectedIndex != -1) { ((ToolBarButton) e.getSource()).setSelected(true); } } authorityEditToolBarPane.populate(); EastRegionContainerPane.getInstance().replaceUpPane(authorityEditToolBarPane); } }; private int pressButtonIndex(MouseEvent e, java.util.List buttonlists) { if (!(e.getSource() instanceof ToolBarButton)) { return -1; } ToolBarButton button = (ToolBarButton) e.getSource(); for (int i = 0; i < buttonlists.size(); i++) { if (ComparatorUtils.equals(button, buttonlists.get(i))) { return i; } } return -1; } /** * 去掉选择 */ public void removeSelection() { for (ToolBarButton button : toolBarPane.getToolBarButtons()) { button.setSelected(false); } } private ItemListener itemListener = new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.DESELECTED) { selectedIndex = -1; populateToolBarPane(); authorityEditToolBarPane = new AuthorityEditToolBarPane(toolBarPane.getToolBarButtons()); authorityEditToolBarPane.setAuthorityToolBarPane(AuthorityToolBarPane.this); EastRegionContainerPane.getInstance().replaceUpPane(authorityEditToolBarPane); EastRegionContainerPane.getInstance().replaceDownPane(RolesAlreadyEditedPane.getInstance()); } } }; public AuthorityToolBarPane() { this.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 3)); this.setBorder(BorderFactory.createEmptyBorder(0, PRE_GAP, 0, 0)); title = new UILabel(Inter.getLocText(new String[]{"ReportServerP-Toolbar", "Choose_Role"})); title.setHorizontalAlignment(SwingConstants.CENTER); this.add(title, 0); choseComboBox = new UIComboBox(CHOOSEITEM) { public Dimension getPreferredSize() { Dimension dim = super.getPreferredSize(); dim.width = COMBOX_WIDTH; return dim; } }; choseComboBox.addItemListener(itemListener); //默认选择第一个 choseComboBox.setSelectedIndex(0); this.add(createGapPanel(SMALL_GAP)); this.add(choseComboBox); toolBarPane = new ToolBarPane(); toolBarPane.setBorder(null); toolBarPane.removeDefaultMouseListener(); this.add(createGapPanel(GAP)); this.add(toolBarPane); populateDefaultToolBarWidgets(); populateBean(getReportWebAttr()); toolBarPane.addAuthorityListener(mouseListener); authorityEditToolBarPane = new AuthorityEditToolBarPane(toolBarPane.getToolBarButtons()); authorityEditToolBarPane.setAuthorityToolBarPane(this); checkToolBarPaneEnable(); } private JPanel createGapPanel(final int gap) { return new JPanel() { public Dimension getPreferredSize() { Dimension dim = super.getPreferredSize(); dim.width = gap; return dim; } }; } private void populateToolBarPane() { toolBarPane.removeAll(); populateDefaultToolBarWidgets(); populateBean(getReportWebAttr()); toolBarPane.addAuthorityListener(mouseListener); toolBarPane.repaint(); authorityEditToolBarPane = new AuthorityEditToolBarPane(toolBarPane.getToolBarButtons()); checkToolBarPaneEnable(); } /** * 使用普通用户远程设计时,如果工具栏使用的是“采用服务器设置”,则工具栏按钮为灰不可用 */ private void checkToolBarPaneEnable() { List toolBarButtons = toolBarPane.getToolBarButtons(); boolean isnotEnable = ComparatorUtils.equals(title.getText(), Inter.getLocText(new String[]{"Server", "ReportServerP-Toolbar", "Choose_Role"})) && !FRContext.getCurrentEnv().isRoot(); for (ToolBarButton button : toolBarButtons) { button.setEnabled(!isnotEnable); } toolBarPane.setEnabled(!isnotEnable); } /** * 更新权限工具栏面板 */ public void populateAuthority() { toolBarPane.repaint(); } private ReportWebAttr getReportWebAttr() { JTemplate editingTemplate = HistoryTemplateListPane.getInstance().getCurrentEditingTemplate(); if (!editingTemplate.isJWorkBook()) { return null; } JWorkBook editingWorkBook = (JWorkBook) editingTemplate; TemplateWorkBook wbTpl = editingWorkBook.getTarget(); return wbTpl.getReportWebAttr(); } //将该报表的设置过权限的属性记录一下 public void setAuthorityWebAttr(Widget widget, boolean isSelected, String selectedRole) { JTemplate editingTemplate = HistoryTemplateListPane.getInstance().getCurrentEditingTemplate(); if (!editingTemplate.isJWorkBook()) { return; } JWorkBook editingWorkBook = (JWorkBook) editingTemplate; TemplateWorkBook wbTpl = editingWorkBook.getTarget(); ReportWebAttr rw = wbTpl.getReportWebAttr(); ConfigManagerProvider cm = ConfigManager.getProviderInstance(); ReportWebAttr webAttr = ((ReportWebAttr) cm.getGlobalAttribute(ReportWebAttr.class)); //wbTpl.clear先清空 //再将所有的保存进去 //看是存在服务器还存在模板里面 if (choseComboBox.getSelectedIndex() == 0) { //分页 if (rw == null || rw.getWebPage() == null) { dealWithWebContent(webAttr.getWebPage(), widget, isSelected, selectedRole); } } else if (choseComboBox.getSelectedIndex() == 1) { //填报 if (rw == null || rw.getWebPage() == null) { dealWithWebContent(webAttr.getWebWrite(), widget, isSelected, selectedRole); } } else { //view if (rw == null || rw.getWebPage() == null) { dealWithWebContent(webAttr.getWebView(), widget, isSelected, selectedRole); } } } private void dealWithWebContent(WebContent wc, Widget widget, boolean isSelected, String selectedRole) { ToolBarManager[] managers = wc.getToolBarManagers(); if (managers == null) { return; } for (int i = 0; i < managers.length; i++) { ToolBar tb = managers[i].getToolBar(); for (int j = 0; j < tb.getWidgetSize(); j++) { if (widget instanceof Button && tb.getWidget(j) instanceof Button) { if (ComparatorUtils.equals(((Button) widget).getIconName(), ((Button) tb.getWidget(j)).getIconName())) { if (!isSelected) { tb.getWidget(j).getWidgetPrivilegeControl().addInvisibleRole(selectedRole); } else { tb.getWidget(j).getWidgetPrivilegeControl().removeInvisibleRole(selectedRole); } } } } } wc.setToolBarManagers(managers); } public void populateBean(ReportWebAttr reportWebAttr) { this.remove(title); // 如果是空值就说明采用服务器配置了 if (reportWebAttr == null || this.getWebContent(reportWebAttr) == null) { title = new UILabel(Inter.getLocText(new String[]{"Server", "ReportServerP-Toolbar", "Choose_Role"})); populateServerSettings(); this.add(title, 0); return; } // 模板设置 T webContent = this.getWebContent(reportWebAttr); title = new UILabel(Inter.getLocText(new String[]{"the_template", "ReportServerP-Toolbar", "Choose_Role"})); this.add(title, 0); populate(webContent.getToolBarManagers()); } public ReportWebAttr updateBean() { return null; } public void populate(ToolBarManager[] toolBarManager) { if (ArrayUtils.isEmpty(toolBarManager)) { return; } if (toolBarManager.length == 0) { return; } for (int i = 0; i < toolBarManager.length; i++) { toolBarPane.populateBean(toolBarManager[i].getToolBar()); } } public Dimension getPreferredSize() { Dimension dim = super.getPreferredSize(); dim.height = ToolBarMenuDock.PANLE_HEIGNT; return dim; } public void populateBean(ToolBarManager[] toolBarManager) { if (ArrayUtils.isEmpty(toolBarManager)) { return; } for (int i = 0; i < toolBarManager.length; i++) { Location location = toolBarManager[i].getToolBarLocation(); if (location instanceof Location.Embed) { toolBarPane.populateBean(toolBarManager[i].getToolBar()); } } } private void populateServerSettings() { ConfigManagerProvider cm = ConfigManager.getProviderInstance(); ReportWebAttr webAttr = ((ReportWebAttr) cm.getGlobalAttribute(ReportWebAttr.class)); if (this.getWebContent(webAttr) != null) { populate(this.getWebContent(webAttr).getToolBarManagers()); } } protected String title4PopupWindow() { return null; } private T getWebContent(ReportWebAttr reportWebAttr) { if (choseComboBox.getSelectedIndex() == 0) { return reportWebAttr == null ? null : (T) reportWebAttr.getWebPage(); } else if (choseComboBox.getSelectedIndex() == 1) { return reportWebAttr == null ? null : (T) reportWebAttr.getWebWrite(); } else { return reportWebAttr == null ? null : (T) reportWebAttr.getWebView(); } } private void populateDefaultToolBarWidgets() { if (choseComboBox.getSelectedIndex() == 0) { ReportWebWidgetConstants.getPageToolBarInstance(); } else if (choseComboBox.getSelectedIndex() == 1) { ReportWebWidgetConstants.getWriteToolBarInstance(); } else { ReportWebWidgetConstants.getViewToolBarInstance(); } } private ToolBarManager getDefaultToolBarManager() { if (choseComboBox.getSelectedIndex() == 0) { return ToolBarManager.createDefaultToolBar(); } else if (choseComboBox.getSelectedIndex() == 1) { return ToolBarManager.createDefaultWriteToolBar(); } else { return ToolBarManager.createDefaultViewToolBar(); } } } \ No newline at end of file +package com.fr.design.mainframe; + +import com.fr.base.ConfigManager; +import com.fr.base.ConfigManagerProvider; +import com.fr.base.FRContext; +import com.fr.common.inputevent.InputEventBaseOnOS; +import com.fr.design.beans.BasicBeanPane; +import com.fr.design.file.HistoryTemplateListPane; +import com.fr.design.gui.icombobox.UIComboBox; +import com.fr.design.gui.ilable.UILabel; +import com.fr.design.mainframe.toolbar.AuthorityEditToolBarComponent; +import com.fr.design.mainframe.toolbar.ToolBarMenuDock; +import com.fr.design.roleAuthority.RolesAlreadyEditedPane; +import com.fr.design.webattr.ReportWebWidgetConstants; +import com.fr.design.webattr.ToolBarButton; +import com.fr.design.webattr.ToolBarPane; +import com.fr.form.ui.Button; +import com.fr.form.ui.ToolBar; +import com.fr.form.ui.Widget; +import com.fr.general.ComparatorUtils; +import com.fr.general.Inter; +import com.fr.main.TemplateWorkBook; +import com.fr.report.web.Location; +import com.fr.report.web.ToolBarManager; +import com.fr.report.web.WebContent; +import com.fr.stable.ArrayUtils; +import com.fr.web.attr.ReportWebAttr; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.util.List; + +/** + * Author : daisy + * Date: 13-9-9 + * Time: 下午4:58 + */ +public class AuthorityToolBarPane extends BasicBeanPane implements AuthorityEditToolBarComponent { + private static final int SMALL_GAP = 13; + private static final int GAP = 25; + private static final int PRE_GAP = 9; + private static final int COMBOX_WIDTH = 144; + + private static final String[] CHOOSEITEM = new String[]{Inter.getLocText("M-Page_Preview"), Inter.getLocText(new String[]{"Face_Write", "PageSetup-Page"}), Inter.getLocText("M-Data_Analysis")}; + private UIComboBox choseComboBox; + private ToolBarPane toolBarPane; + private AuthorityEditToolBarPane authorityEditToolBarPane = null; + private int selectedIndex = -1; + private UILabel title = null; + private MouseListener mouseListener = new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + if (!toolBarPane.isEnabled()) { + return; + } + java.util.List buttonlists = toolBarPane.getToolBarButtons(); + int oldIndex = selectedIndex; + selectedIndex = pressButtonIndex(e, buttonlists); + //实现shift多选 + if (e.isShiftDown()) { + if (oldIndex == -1) { + removeSelection(); + ((ToolBarButton) e.getSource()).setSelected(true); + } else { + int max = oldIndex >= selectedIndex ? oldIndex : selectedIndex; + int min = oldIndex <= selectedIndex ? oldIndex : selectedIndex; + for (int i = min; i <= max; i++) { + buttonlists.get(i).setSelected(true); + } + } + } else if (!InputEventBaseOnOS.isControlDown(e)) { + //实现单选 + removeSelection(); + if (selectedIndex != -1) { + ((ToolBarButton) e.getSource()).setSelected(true); + } + } + authorityEditToolBarPane.populate(); + EastRegionContainerPane.getInstance().replaceUpPane(authorityEditToolBarPane); + } + + }; + + + private int pressButtonIndex(MouseEvent e, java.util.List buttonlists) { + if (!(e.getSource() instanceof ToolBarButton)) { + return -1; + } + ToolBarButton button = (ToolBarButton) e.getSource(); + for (int i = 0; i < buttonlists.size(); i++) { + if (ComparatorUtils.equals(button, buttonlists.get(i))) { + return i; + } + } + return -1; + } + + /** + * 去掉选择 + */ + public void removeSelection() { + for (ToolBarButton button : toolBarPane.getToolBarButtons()) { + button.setSelected(false); + } + } + + + private ItemListener itemListener = new ItemListener() { + + @Override + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.DESELECTED) { + selectedIndex = -1; + populateToolBarPane(); + authorityEditToolBarPane = new AuthorityEditToolBarPane(toolBarPane.getToolBarButtons()); + authorityEditToolBarPane.setAuthorityToolBarPane(AuthorityToolBarPane.this); + EastRegionContainerPane.getInstance().replaceUpPane(authorityEditToolBarPane); + EastRegionContainerPane.getInstance().replaceDownPane(RolesAlreadyEditedPane.getInstance()); + } + } + }; + + public AuthorityToolBarPane() { + this.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 3)); + this.setBorder(BorderFactory.createEmptyBorder(0, PRE_GAP, 0, 0)); + title = new UILabel(Inter.getLocText(new String[]{"ReportServerP-Toolbar", "Choose_Role"})); + title.setHorizontalAlignment(SwingConstants.CENTER); + this.add(title, 0); + choseComboBox = new UIComboBox(CHOOSEITEM) { + public Dimension getPreferredSize() { + Dimension dim = super.getPreferredSize(); + dim.width = COMBOX_WIDTH; + return dim; + } + }; + choseComboBox.addItemListener(itemListener); + //默认选择第一个 + choseComboBox.setSelectedIndex(0); + this.add(createGapPanel(SMALL_GAP)); + this.add(choseComboBox); + toolBarPane = new ToolBarPane(); + toolBarPane.setBorder(null); + toolBarPane.removeDefaultMouseListener(); + this.add(createGapPanel(GAP)); + this.add(toolBarPane); + populateDefaultToolBarWidgets(); + populateBean(getReportWebAttr()); + toolBarPane.addAuthorityListener(mouseListener); + authorityEditToolBarPane = new AuthorityEditToolBarPane(toolBarPane.getToolBarButtons()); + authorityEditToolBarPane.setAuthorityToolBarPane(this); + checkToolBarPaneEnable(); + } + + private JPanel createGapPanel(final int gap) { + return new JPanel() { + public Dimension getPreferredSize() { + Dimension dim = super.getPreferredSize(); + dim.width = gap; + return dim; + } + }; + } + + + private void populateToolBarPane() { + toolBarPane.removeAll(); + populateDefaultToolBarWidgets(); + populateBean(getReportWebAttr()); + toolBarPane.addAuthorityListener(mouseListener); + toolBarPane.repaint(); + authorityEditToolBarPane = new AuthorityEditToolBarPane(toolBarPane.getToolBarButtons()); + checkToolBarPaneEnable(); + } + + /** + * 使用普通用户远程设计时,如果工具栏使用的是“采用服务器设置”,则工具栏按钮为灰不可用 + */ + private void checkToolBarPaneEnable() { + List toolBarButtons = toolBarPane.getToolBarButtons(); + boolean isnotEnable = ComparatorUtils.equals(title.getText(), Inter.getLocText(new String[]{"Server", "ReportServerP-Toolbar", "Choose_Role"})) + && !FRContext.getCurrentEnv().isRoot(); + for (ToolBarButton button : toolBarButtons) { + button.setEnabled(!isnotEnable); + } + toolBarPane.setEnabled(!isnotEnable); + } + + /** + * 更新权限工具栏面板 + */ + public void populateAuthority() { + toolBarPane.repaint(); + } + + + private ReportWebAttr getReportWebAttr() { + JTemplate editingTemplate = HistoryTemplateListPane.getInstance().getCurrentEditingTemplate(); + if (!editingTemplate.isJWorkBook()) { + return null; + } + JWorkBook editingWorkBook = (JWorkBook) editingTemplate; + TemplateWorkBook wbTpl = editingWorkBook.getTarget(); + return wbTpl.getReportWebAttr(); + } + + + //将该报表的设置过权限的属性记录一下 + public void setAuthorityWebAttr(Widget widget, boolean isSelected, String selectedRole) { + JTemplate editingTemplate = HistoryTemplateListPane.getInstance().getCurrentEditingTemplate(); + if (!editingTemplate.isJWorkBook()) { + return; + } + JWorkBook editingWorkBook = (JWorkBook) editingTemplate; + TemplateWorkBook wbTpl = editingWorkBook.getTarget(); + + ReportWebAttr rw = wbTpl.getReportWebAttr(); + ConfigManagerProvider cm = ConfigManager.getProviderInstance(); + ReportWebAttr webAttr = ((ReportWebAttr) cm.getGlobalAttribute(ReportWebAttr.class)); + + //wbTpl.clear先清空 + //再将所有的保存进去 + //看是存在服务器还存在模板里面 + if (choseComboBox.getSelectedIndex() == 0) { + //分页 + if (rw == null || rw.getWebPage() == null) { + dealWithWebContent(webAttr.getWebPage(), widget, isSelected, selectedRole); + } + } else if (choseComboBox.getSelectedIndex() == 1) { + //填报 + if (rw == null || rw.getWebPage() == null) { + dealWithWebContent(webAttr.getWebWrite(), widget, isSelected, selectedRole); + } + } else { + //view + if (rw == null || rw.getWebPage() == null) { + dealWithWebContent(webAttr.getWebView(), widget, isSelected, selectedRole); + } + } + + } + + private void dealWithWebContent(WebContent wc, Widget widget, boolean isSelected, String selectedRole) { + ToolBarManager[] managers = wc.getToolBarManagers(); + if (managers == null) { + return; + } + for (int i = 0; i < managers.length; i++) { + ToolBar tb = managers[i].getToolBar(); + for (int j = 0; j < tb.getWidgetSize(); j++) { + if (widget instanceof Button && tb.getWidget(j) instanceof Button) { + if (ComparatorUtils.equals(((Button) widget).getIconName(), + ((Button) tb.getWidget(j)).getIconName())) { + if (!isSelected) { + tb.getWidget(j).getWidgetPrivilegeControl().addInvisibleRole(selectedRole); + } else { + tb.getWidget(j).getWidgetPrivilegeControl().removeInvisibleRole(selectedRole); + } + } + } + } + } + wc.setToolBarManagers(managers); + } + + + public void populateBean(ReportWebAttr reportWebAttr) { + this.remove(title); + // 如果是空值就说明采用服务器配置了 + if (reportWebAttr == null || this.getWebContent(reportWebAttr) == null) { + title = new UILabel(Inter.getLocText(new String[]{"Server", "ReportServerP-Toolbar", "Choose_Role"})); + populateServerSettings(); + this.add(title, 0); + return; + } + // 模板设置 + T webContent = this.getWebContent(reportWebAttr); + title = new UILabel(Inter.getLocText(new String[]{"the_template", "ReportServerP-Toolbar", "Choose_Role"})); + this.add(title, 0); + populate(webContent.getToolBarManagers()); + } + + public ReportWebAttr updateBean() { + return null; + } + + public void populate(ToolBarManager[] toolBarManager) { + if (ArrayUtils.isEmpty(toolBarManager)) { + return; + } + if (toolBarManager.length == 0) { + return; + } + for (int i = 0; i < toolBarManager.length; i++) { + toolBarPane.populateBean(toolBarManager[i].getToolBar()); + } + } + + + public Dimension getPreferredSize() { + Dimension dim = super.getPreferredSize(); + dim.height = ToolBarMenuDock.PANLE_HEIGNT; + return dim; + } + + + public void populateBean(ToolBarManager[] toolBarManager) { + if (ArrayUtils.isEmpty(toolBarManager)) { + return; + } + for (int i = 0; i < toolBarManager.length; i++) { + Location location = toolBarManager[i].getToolBarLocation(); + if (location instanceof Location.Embed) { + toolBarPane.populateBean(toolBarManager[i].getToolBar()); + } + } + } + + + private void populateServerSettings() { + ConfigManagerProvider cm = ConfigManager.getProviderInstance(); + ReportWebAttr webAttr = ((ReportWebAttr) cm.getGlobalAttribute(ReportWebAttr.class)); + if (this.getWebContent(webAttr) != null) { + populate(this.getWebContent(webAttr).getToolBarManagers()); + } + } + + protected String title4PopupWindow() { + return null; + } + + + private T getWebContent(ReportWebAttr reportWebAttr) { + if (choseComboBox.getSelectedIndex() == 0) { + return reportWebAttr == null ? null : (T) reportWebAttr.getWebPage(); + } else if (choseComboBox.getSelectedIndex() == 1) { + return reportWebAttr == null ? null : (T) reportWebAttr.getWebWrite(); + } else { + return reportWebAttr == null ? null : (T) reportWebAttr.getWebView(); + } + + } + + private void populateDefaultToolBarWidgets() { + if (choseComboBox.getSelectedIndex() == 0) { + ReportWebWidgetConstants.getPageToolBarInstance(); + } else if (choseComboBox.getSelectedIndex() == 1) { + ReportWebWidgetConstants.getWriteToolBarInstance(); + } else { + ReportWebWidgetConstants.getViewToolBarInstance(); + } + } + + private ToolBarManager getDefaultToolBarManager() { + if (choseComboBox.getSelectedIndex() == 0) { + return ToolBarManager.createDefaultToolBar(); + } else if (choseComboBox.getSelectedIndex() == 1) { + return ToolBarManager.createDefaultWriteToolBar(); + } else { + return ToolBarManager.createDefaultViewToolBar(); + } + + } + + +} \ No newline at end of file diff --git a/designer/src/com/fr/grid/GridKeyListener.java b/designer/src/com/fr/grid/GridKeyListener.java index 8e3148bf56..e60097fd6f 100644 --- a/designer/src/com/fr/grid/GridKeyListener.java +++ b/designer/src/com/fr/grid/GridKeyListener.java @@ -1,5 +1,6 @@ package com.fr.grid; +import com.fr.common.inputevent.InputEventBaseOnOS; import com.fr.design.mainframe.ElementCasePane; import com.fr.grid.selection.CellSelection; import com.fr.grid.selection.FloatSelection; @@ -71,7 +72,7 @@ public class GridKeyListener implements KeyListener { // Richie:Ctrl + A全选单元格 case KeyEvent.VK_A: boolean macOS = OperatingSystem.isMacOS() && evt.isMetaDown(); - boolean windows = OperatingSystem.isWindows() && evt.isControlDown(); + boolean windows = OperatingSystem.isWindows() && InputEventBaseOnOS.isControlDown(evt); if (macOS || windows) { reportPane.setSelection(new CellSelection(0, 0, report.getColumnCount(), report.getRowCount())); isNeedRepaint = true; @@ -168,7 +169,7 @@ public class GridKeyListener implements KeyListener { return; } KeyEvent newEvt = KeyEventWork.processKeyEvent(evt); - if (newEvt == null || evt.isControlDown()) {// uneditable. + if (newEvt == null || InputEventBaseOnOS.isControlDown(evt)) {// uneditable. return; } char ch = evt.getKeyChar(); diff --git a/designer/src/com/fr/grid/GridMouseAdapter.java b/designer/src/com/fr/grid/GridMouseAdapter.java index 9f14df471d..8a40533530 100644 --- a/designer/src/com/fr/grid/GridMouseAdapter.java +++ b/designer/src/com/fr/grid/GridMouseAdapter.java @@ -1,26 +1,14 @@ package com.fr.grid; -import java.awt.Cursor; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.awt.event.MouseMotionListener; -import java.awt.event.MouseWheelEvent; -import java.awt.event.MouseWheelListener; -import java.util.HashMap; -import java.util.Map; - -import javax.swing.JPopupMenu; -import javax.swing.SwingUtilities; - import com.fr.base.BaseUtils; import com.fr.base.DynamicUnitList; import com.fr.base.ScreenResolution; +import com.fr.common.inputevent.InputEventBaseOnOS; import com.fr.design.constants.UIConstants; import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.ElementCasePane; import com.fr.design.present.CellWriteAttrPane; +import com.fr.design.utils.gui.GUICoreUtils; import com.fr.grid.selection.CellSelection; import com.fr.grid.selection.FloatSelection; import com.fr.grid.selection.Selection; @@ -37,7 +25,12 @@ import com.fr.stable.ColumnRow; import com.fr.stable.StringUtils; import com.fr.stable.unit.FU; import com.fr.stable.unit.OLDPIX; -import com.fr.design.utils.gui.GUICoreUtils; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.util.HashMap; +import java.util.Map; /** * the MouseListener of the Grid @@ -45,800 +38,800 @@ import com.fr.design.utils.gui.GUICoreUtils; * @editor zhou 2012-3-22下午1:53:59 */ public class GridMouseAdapter implements MouseListener, MouseWheelListener, MouseMotionListener { - private static final int WIDGET_WIDTH = 13; - private static final int TIME_DELAY = 100; - private static final int TOOLTIP_X = 30; - private static final int TOOLTIP_X_Y_FIX = 4; - private static final double COPY_CROSS_INNER_DISTANCE = 1.5; - private static final double COPY_CROSS_OUTER_DISTANCE = 2.5; - /** - * 拖拽时候刷新时间间隔 - */ - private static int DRAG_REFRESH_TIME = 10; - /** - * 对应的表格-Grid - */ - private Grid grid; - /** - * the Point(x,y) where the mouse pressed - */ - private int oldEvtX = 0; - private int oldEvtY = 0; - // the old location, used for Move float element. - private int oldLocationX; - private int oldLocationY; - private long lastMouseMoveTime = 0; // 最后的MouseMove时间. - // 保存各个悬浮元素到oldLocation距离 - private Map floatNamePointMap; - /** - * august:因为CellSelection里面没有记录的变量了,必须要有个变量来存按住shift键的位置之前的鼠标的位置 - * 用户可能一直按住shift键不放,所以按住shift键之前的鼠标位置是必须有的. - */ - private ColumnRow tempOldSelectedCell; - - private int ECBlockGap = 40; - - protected GridMouseAdapter(Grid grid) { - this.grid = grid; - } - - /** - * @param evt - */ - public void mousePressed(MouseEvent evt) { - if (!grid.isEnabled()) { - return; - } - oldEvtX = evt.getX(); - oldEvtY = evt.getY(); - grid.stopEditing(); - - if (!grid.hasFocus() && grid.isRequestFocusEnabled()) { - grid.requestFocus(); - } - - if (grid.getDrawingFloatElement() != null) { - doWithDrawingFloatElement(); - } else { - if (SwingUtilities.isRightMouseButton(evt)) { - doWithRightButtonPressed(); - } else { - doWithLeftButtonPressed(evt); - } - // 用户没有按住Shift键时,tempOldSelectedCell是一直变化的。如果一直按住shift,是不变的 - ElementCasePane ePane = grid.getElementCasePane(); - if (!evt.isShiftDown() && ePane.getSelection() instanceof CellSelection) { - tempOldSelectedCell = GridUtils.getAdjustEventColumnRow(ePane, oldEvtX, oldEvtY); - } - } - - } - - /** - * 将悬浮元素(只有文本和公式)添加到鼠标点击的位置 - */ - private void doWithDrawingFloatElement() { - ElementCasePane reportPane = grid.getElementCasePane(); - TemplateElementCase report = reportPane.getEditingElementCase(); - DynamicUnitList columnWidthList = ReportHelper.getColumnWidthList(report); - DynamicUnitList rowHeightList = ReportHelper.getRowHeightList(report); - - int horizentalScrollValue = grid.getHorizontalValue(); - int verticalScrollValue = grid.getVerticalValue(); - int resolution = ScreenResolution.getScreenResolution(); - FU evtX_fu = FU.valueOfPix(this.oldEvtX, resolution); - FU evtY_fu = FU.valueOfPix(this.oldEvtY, resolution); - - FU leftDistance = FU.getInstance(evtX_fu.toFU() + columnWidthList.getRangeValue(0, horizentalScrollValue).toFU()); - FU topDistance = FU.getInstance(evtY_fu.toFU() + rowHeightList.getRangeValue(0, verticalScrollValue).toFU()); - - grid.getDrawingFloatElement().setLeftDistance(leftDistance); - grid.getDrawingFloatElement().setTopDistance(topDistance); - - report.addFloatElement(grid.getDrawingFloatElement()); - reportPane.setSelection(new FloatSelection(grid.getDrawingFloatElement().getName())); - } - - /** - * 处理右击事件,弹出右键菜单. - */ - private void doWithRightButtonPressed() { - ElementCasePane reportPane = grid.getElementCasePane(); - Object[] tmpFloatElementCursor = GridUtils.getAboveFloatElementCursor(reportPane, this.oldEvtX, this.oldEvtY); - if (!ArrayUtils.isEmpty(tmpFloatElementCursor)) { - FloatElement selectedFloatElement = (FloatElement) tmpFloatElementCursor[0]; - reportPane.setSelection(new FloatSelection(selectedFloatElement.getName())); - } else { - ColumnRow selectedCellPoint = GridUtils.getAdjustEventColumnRow(reportPane, this.oldEvtX, this.oldEvtY); - if (!reportPane.getSelection().containsColumnRow(selectedCellPoint)) { - GridUtils.doSelectCell(reportPane, selectedCellPoint.getColumn(), selectedCellPoint.getRow()); - } - } - reportPane.repaint(); - JPopupMenu cellPopupMenu = reportPane.createPopupMenu(); - if (cellPopupMenu != null) { - GUICoreUtils.showPopupMenu(cellPopupMenu, this.grid, this.oldEvtX - 1, this.oldEvtY - 1); - } - } - - /** - * 处理左击事件 - */ - private void doWithLeftButtonPressed(MouseEvent evt) { - if(BaseUtils.isAuthorityEditing()){ - grid.setEditable(false); - } - - ElementCasePane reportPane = grid.getElementCasePane(); - TemplateElementCase report = reportPane.getEditingElementCase(); - boolean isShiftDown = evt.isShiftDown(); - boolean isControlDown = evt.isControlDown(); - int clickCount = evt.getClickCount(); - // peter:需要判断是否在可移动CellSelection的区域 - grid.setDragType(isMoveCellSelection(this.oldEvtX, this.oldEvtY)); - if (clickCount >= 2) { - grid.setDragType(GridUtils.DRAG_NONE); - } - if (grid.getDragType() != GridUtils.DRAG_NONE) {// Drag的标志. - Selection selection = reportPane.getSelection(); - if (selection instanceof CellSelection) { - // peter:设置DragRecatagle的标志. - if (grid.getDragRectangle() == null) { - grid.setDragRectangle(new Rectangle()); - } - CellSelection cs = ((CellSelection) selection).clone(); - grid.getDragRectangle().setBounds(cs.toRectangle()); - return; - } - } - // peter:选择GridSelection,支持Shift - doOneClickSelection(this.oldEvtX, this.oldEvtY, isShiftDown, isControlDown); - // 得到点击所在的column and row - ColumnRow columnRow = GridUtils.getEventColumnRow(reportPane, this.oldEvtX, this.oldEvtY); - TemplateCellElement cellElement = report.getTemplateCellElement(columnRow.getColumn(), columnRow.getRow()); - if (clickCount >= 2 && !BaseUtils.isAuthorityEditing()) { - grid.startEditing(); - } - if (clickCount == 1 && cellElement != null && cellElement.getWidget() != null && !BaseUtils.isAuthorityEditing()) { - showWidetWindow(cellElement, report); - } - reportPane.repaint(); - } - - /** - * 显示控件编辑窗口 - * - * @param cellElement - * @param report - */ - - private void showWidetWindow(TemplateCellElement cellElement, TemplateElementCase report) { - int resolution = ScreenResolution.getScreenResolution(); - DynamicUnitList columnWidthList = ReportHelper.getColumnWidthList(report); - DynamicUnitList rowHeightList = ReportHelper.getRowHeightList(report); - double fixed_pos_x = this.oldEvtX - columnWidthList.getRangeValue(grid.getHorizontalValue(), cellElement.getColumn()).toPixD(resolution); - double fixed_pos_y = this.oldEvtY - rowHeightList.getRangeValue(grid.getVerticalValue(), cellElement.getRow()).toPixD(resolution); - double cell_width = columnWidthList.getRangeValue(cellElement.getColumn(), cellElement.getColumn() + cellElement.getColumnSpan()).toPixD(resolution); - double cell_height = rowHeightList.getRangeValue(cellElement.getRow(), cellElement.getRow() + cellElement.getRowSpan()).toPixD(resolution); - if (fitSizeToShow(cell_width, cell_height, fixed_pos_x, fixed_pos_y)) { - CellWriteAttrPane.showWidgetWindow(grid.getElementCasePane()); - } - } - - private boolean fitSizeToShow(double cell_width, double cell_height, double fixed_pos_x, double fixed_pos_y) { - return cell_width - fixed_pos_x > 0 && cell_height - fixed_pos_y > 0 - && cell_width - fixed_pos_x < WIDGET_WIDTH && cell_height - fixed_pos_y < WIDGET_WIDTH; - } - - /** - * @param evt - */ - public void mouseReleased(MouseEvent evt) { - if (!grid.isEnabled() || !grid.isEditable()) { - return; - } - boolean isDataChanged = false; - ElementCasePane reportPane = grid.getElementCasePane(); - Selection selection = reportPane.getSelection(); - if (grid.getDrawingFloatElement() != null) { - if (grid.getDrawingFloatElement().getWidth().equal_zero() && grid.getDrawingFloatElement().getHeight().equal_zero()) { - grid.getDrawingFloatElement().setWidth(new OLDPIX(100)); - grid.getDrawingFloatElement().setHeight(new OLDPIX(100)); - } - grid.setDrawingFloatElement(null); - } else if (selection instanceof FloatSelection) { - grid.setCursor(Cursor.getDefaultCursor()); - } - if (grid.getDragType() == GridUtils.DRAG_CELLSELECTION) { - if (selection instanceof CellSelection) { - grid.getElementCasePane().cut(); - // mouse release的时候要判断下是否在reportPane范围内 - if (outOfBounds(evt, reportPane)) { - GridUtils.doSelectCell(reportPane, grid.getDragRectangle().x, grid.getDragRectangle().y); - } else { - mousePressed(evt); - } - grid.getElementCasePane().paste(); - isDataChanged = true; - } - } else if (grid.getDragType() == GridUtils.DRAG_CELLSELECTION_BOTTOMRIGHT_CORNER) { - if (selection instanceof CellSelection) { - CellSelection cs = (CellSelection) selection; - // august:智能拖拽扩展单元格值 - IntelliElements.iterating(reportPane, cs.toRectangle(), grid.getDragRectangle()); - if (grid.getDragRectangle() != null) { - reportPane.setSelection(new CellSelection(grid.getDragRectangle().x, grid.getDragRectangle().y, grid.getDragRectangle().width, grid.getDragRectangle().height)); - } - isDataChanged = true; - } - } else if (grid.getDragType() == GridUtils.DRAG_FLOAT) { - isDataChanged = true; - } - grid.setDragType(GridUtils.DRAG_NONE); - grid.setDragRectangle(null); - if (isDataChanged) { + private static final int WIDGET_WIDTH = 13; + private static final int TIME_DELAY = 100; + private static final int TOOLTIP_X = 30; + private static final int TOOLTIP_X_Y_FIX = 4; + private static final double COPY_CROSS_INNER_DISTANCE = 1.5; + private static final double COPY_CROSS_OUTER_DISTANCE = 2.5; + /** + * 拖拽时候刷新时间间隔 + */ + private static int DRAG_REFRESH_TIME = 10; + /** + * 对应的表格-Grid + */ + private Grid grid; + /** + * the Point(x,y) where the mouse pressed + */ + private int oldEvtX = 0; + private int oldEvtY = 0; + // the old location, used for Move float element. + private int oldLocationX; + private int oldLocationY; + private long lastMouseMoveTime = 0; // 最后的MouseMove时间. + // 保存各个悬浮元素到oldLocation距离 + private Map floatNamePointMap; + /** + * august:因为CellSelection里面没有记录的变量了,必须要有个变量来存按住shift键的位置之前的鼠标的位置 + * 用户可能一直按住shift键不放,所以按住shift键之前的鼠标位置是必须有的. + */ + private ColumnRow tempOldSelectedCell; + + private int ECBlockGap = 40; + + protected GridMouseAdapter(Grid grid) { + this.grid = grid; + } + + /** + * @param evt + */ + public void mousePressed(MouseEvent evt) { + if (!grid.isEnabled()) { + return; + } + oldEvtX = evt.getX(); + oldEvtY = evt.getY(); + grid.stopEditing(); + + if (!grid.hasFocus() && grid.isRequestFocusEnabled()) { + grid.requestFocus(); + } + + if (grid.getDrawingFloatElement() != null) { + doWithDrawingFloatElement(); + } else { + if (SwingUtilities.isRightMouseButton(evt)) { + doWithRightButtonPressed(); + } else { + doWithLeftButtonPressed(evt); + } + // 用户没有按住Shift键时,tempOldSelectedCell是一直变化的。如果一直按住shift,是不变的 + ElementCasePane ePane = grid.getElementCasePane(); + if (!evt.isShiftDown() && ePane.getSelection() instanceof CellSelection) { + tempOldSelectedCell = GridUtils.getAdjustEventColumnRow(ePane, oldEvtX, oldEvtY); + } + } + + } + + /** + * 将悬浮元素(只有文本和公式)添加到鼠标点击的位置 + */ + private void doWithDrawingFloatElement() { + ElementCasePane reportPane = grid.getElementCasePane(); + TemplateElementCase report = reportPane.getEditingElementCase(); + DynamicUnitList columnWidthList = ReportHelper.getColumnWidthList(report); + DynamicUnitList rowHeightList = ReportHelper.getRowHeightList(report); + + int horizentalScrollValue = grid.getHorizontalValue(); + int verticalScrollValue = grid.getVerticalValue(); + int resolution = ScreenResolution.getScreenResolution(); + FU evtX_fu = FU.valueOfPix(this.oldEvtX, resolution); + FU evtY_fu = FU.valueOfPix(this.oldEvtY, resolution); + + FU leftDistance = FU.getInstance(evtX_fu.toFU() + columnWidthList.getRangeValue(0, horizentalScrollValue).toFU()); + FU topDistance = FU.getInstance(evtY_fu.toFU() + rowHeightList.getRangeValue(0, verticalScrollValue).toFU()); + + grid.getDrawingFloatElement().setLeftDistance(leftDistance); + grid.getDrawingFloatElement().setTopDistance(topDistance); + + report.addFloatElement(grid.getDrawingFloatElement()); + reportPane.setSelection(new FloatSelection(grid.getDrawingFloatElement().getName())); + } + + /** + * 处理右击事件,弹出右键菜单. + */ + private void doWithRightButtonPressed() { + ElementCasePane reportPane = grid.getElementCasePane(); + Object[] tmpFloatElementCursor = GridUtils.getAboveFloatElementCursor(reportPane, this.oldEvtX, this.oldEvtY); + if (!ArrayUtils.isEmpty(tmpFloatElementCursor)) { + FloatElement selectedFloatElement = (FloatElement) tmpFloatElementCursor[0]; + reportPane.setSelection(new FloatSelection(selectedFloatElement.getName())); + } else { + ColumnRow selectedCellPoint = GridUtils.getAdjustEventColumnRow(reportPane, this.oldEvtX, this.oldEvtY); + if (!reportPane.getSelection().containsColumnRow(selectedCellPoint)) { + GridUtils.doSelectCell(reportPane, selectedCellPoint.getColumn(), selectedCellPoint.getRow()); + } + } + reportPane.repaint(); + JPopupMenu cellPopupMenu = reportPane.createPopupMenu(); + if (cellPopupMenu != null) { + GUICoreUtils.showPopupMenu(cellPopupMenu, this.grid, this.oldEvtX - 1, this.oldEvtY - 1); + } + } + + /** + * 处理左击事件 + */ + private void doWithLeftButtonPressed(MouseEvent evt) { + if (BaseUtils.isAuthorityEditing()) { + grid.setEditable(false); + } + + ElementCasePane reportPane = grid.getElementCasePane(); + TemplateElementCase report = reportPane.getEditingElementCase(); + boolean isShiftDown = evt.isShiftDown(); + boolean isControlDown = InputEventBaseOnOS.isControlDown(evt); + int clickCount = evt.getClickCount(); + // peter:需要判断是否在可移动CellSelection的区域 + grid.setDragType(isMoveCellSelection(this.oldEvtX, this.oldEvtY)); + if (clickCount >= 2) { + grid.setDragType(GridUtils.DRAG_NONE); + } + if (grid.getDragType() != GridUtils.DRAG_NONE) {// Drag的标志. + Selection selection = reportPane.getSelection(); + if (selection instanceof CellSelection) { + // peter:设置DragRecatagle的标志. + if (grid.getDragRectangle() == null) { + grid.setDragRectangle(new Rectangle()); + } + CellSelection cs = ((CellSelection) selection).clone(); + grid.getDragRectangle().setBounds(cs.toRectangle()); + return; + } + } + // peter:选择GridSelection,支持Shift + doOneClickSelection(this.oldEvtX, this.oldEvtY, isShiftDown, isControlDown); + // 得到点击所在的column and row + ColumnRow columnRow = GridUtils.getEventColumnRow(reportPane, this.oldEvtX, this.oldEvtY); + TemplateCellElement cellElement = report.getTemplateCellElement(columnRow.getColumn(), columnRow.getRow()); + if (clickCount >= 2 && !BaseUtils.isAuthorityEditing()) { + grid.startEditing(); + } + if (clickCount == 1 && cellElement != null && cellElement.getWidget() != null && !BaseUtils.isAuthorityEditing()) { + showWidetWindow(cellElement, report); + } + reportPane.repaint(); + } + + /** + * 显示控件编辑窗口 + * + * @param cellElement + * @param report + */ + + private void showWidetWindow(TemplateCellElement cellElement, TemplateElementCase report) { + int resolution = ScreenResolution.getScreenResolution(); + DynamicUnitList columnWidthList = ReportHelper.getColumnWidthList(report); + DynamicUnitList rowHeightList = ReportHelper.getRowHeightList(report); + double fixed_pos_x = this.oldEvtX - columnWidthList.getRangeValue(grid.getHorizontalValue(), cellElement.getColumn()).toPixD(resolution); + double fixed_pos_y = this.oldEvtY - rowHeightList.getRangeValue(grid.getVerticalValue(), cellElement.getRow()).toPixD(resolution); + double cell_width = columnWidthList.getRangeValue(cellElement.getColumn(), cellElement.getColumn() + cellElement.getColumnSpan()).toPixD(resolution); + double cell_height = rowHeightList.getRangeValue(cellElement.getRow(), cellElement.getRow() + cellElement.getRowSpan()).toPixD(resolution); + if (fitSizeToShow(cell_width, cell_height, fixed_pos_x, fixed_pos_y)) { + CellWriteAttrPane.showWidgetWindow(grid.getElementCasePane()); + } + } + + private boolean fitSizeToShow(double cell_width, double cell_height, double fixed_pos_x, double fixed_pos_y) { + return cell_width - fixed_pos_x > 0 && cell_height - fixed_pos_y > 0 + && cell_width - fixed_pos_x < WIDGET_WIDTH && cell_height - fixed_pos_y < WIDGET_WIDTH; + } + + /** + * @param evt + */ + public void mouseReleased(MouseEvent evt) { + if (!grid.isEnabled() || !grid.isEditable()) { + return; + } + boolean isDataChanged = false; + ElementCasePane reportPane = grid.getElementCasePane(); + Selection selection = reportPane.getSelection(); + if (grid.getDrawingFloatElement() != null) { + if (grid.getDrawingFloatElement().getWidth().equal_zero() && grid.getDrawingFloatElement().getHeight().equal_zero()) { + grid.getDrawingFloatElement().setWidth(new OLDPIX(100)); + grid.getDrawingFloatElement().setHeight(new OLDPIX(100)); + } + grid.setDrawingFloatElement(null); + } else if (selection instanceof FloatSelection) { + grid.setCursor(Cursor.getDefaultCursor()); + } + if (grid.getDragType() == GridUtils.DRAG_CELLSELECTION) { + if (selection instanceof CellSelection) { + grid.getElementCasePane().cut(); + // mouse release的时候要判断下是否在reportPane范围内 + if (outOfBounds(evt, reportPane)) { + GridUtils.doSelectCell(reportPane, grid.getDragRectangle().x, grid.getDragRectangle().y); + } else { + mousePressed(evt); + } + grid.getElementCasePane().paste(); + isDataChanged = true; + } + } else if (grid.getDragType() == GridUtils.DRAG_CELLSELECTION_BOTTOMRIGHT_CORNER) { + if (selection instanceof CellSelection) { + CellSelection cs = (CellSelection) selection; + // august:智能拖拽扩展单元格值 + IntelliElements.iterating(reportPane, cs.toRectangle(), grid.getDragRectangle()); + if (grid.getDragRectangle() != null) { + reportPane.setSelection(new CellSelection(grid.getDragRectangle().x, grid.getDragRectangle().y, grid.getDragRectangle().width, grid.getDragRectangle().height)); + } + isDataChanged = true; + } + } else if (grid.getDragType() == GridUtils.DRAG_FLOAT) { + isDataChanged = true; + } + grid.setDragType(GridUtils.DRAG_NONE); + grid.setDragRectangle(null); + if (isDataChanged) { reportPane.setSupportDefaultParentCalculate(true); - reportPane.fireTargetModified(); + reportPane.fireTargetModified(); reportPane.setSupportDefaultParentCalculate(false); - } - doWithFormatBrush(reportPane); - reportPane.repaint(); - } - - private void doWithFormatBrush(ElementCasePane reportPane) { - if (DesignerContext.getFormatState() == DesignerContext.FORMAT_STATE_NULL) { - return; - } - - if (reportPane.getCellNeedTOFormat() != null) { - reportPane.getFormatBrushAction().updateFormatBrush(DesignerContext.getReferencedStyle(), reportPane.getCellNeedTOFormat(), reportPane); - reportPane.fireTargetModified(); - - } - if (DesignerContext.getFormatState() == DesignerContext.FORMAT_STATE_ONCE) { - reportPane.cancelFormatBrush(); - } - if (DesignerContext.getFormatState() == DesignerContext.FORMAT_STATE_MORE) { - reportPane.getFormatBrush().setSelected(true); - } - } - - private boolean outOfBounds(MouseEvent evt, ElementCasePane reportPane) { - return evt.getY() > reportPane.getHeight() || evt.getY() < 0 || evt.getX() > reportPane.getWidth() || evt.getX() < 0; - } - - /** - * @param evt - */ - public void mouseMoved(final MouseEvent evt) { - ElementCasePane reportPane = grid.getElementCasePane(); - boolean isGridForSelection = !grid.isEnabled() || !grid.isEditable(); - if (isGridForSelection || grid.isEditing()) { - if (grid.IsNotShowingTableSelectPane()) { - grid.setCursor(UIConstants.CELL_DEFAULT_CURSOR); - return; - } - if (DesignerContext.getFormatState() != DesignerContext.FORMAT_STATE_NULL) { - grid.setCursor(UIConstants.FORMAT_BRUSH_CURSOR); - } else { - grid.setCursor(GUICoreUtils.createCustomCursor(BaseUtils.readImage("com/fr/design/images/buttonicon/select.png"), - new Point(0, 0), "select", grid)); - } - - return; - } - // peter:停留一段时间. - long systemCurrentTime = System.currentTimeMillis(); - if (systemCurrentTime - lastMouseMoveTime <= TIME_DELAY) { - return; - } - lastMouseMoveTime = systemCurrentTime;// 记录最后一次的时间. - mouseMoveOnGrid(evt.getX(), evt.getY()); - } - - /** - * @param evt - */ - public void mouseDragged(MouseEvent evt) { - if (!grid.isEnabled()) { - return; - } - - boolean isControlDown = evt.isControlDown(); - - long systemCurrentTime = System.currentTimeMillis(); - if (systemCurrentTime - lastMouseMoveTime <= DRAG_REFRESH_TIME) {// alex:Drag - return; - } else { - lastMouseMoveTime = systemCurrentTime; - } - - // right mouse cannot Drag.. - if (SwingUtilities.isRightMouseButton(evt)) { - return; - } - - doWithMouseDragged(evt.getX(), evt.getY(), isControlDown); - } - - private void doWithMouseDragged(int evtX, int evtY, boolean isControlDown) { - ElementCasePane reportPane = grid.getElementCasePane(); - - if (reportPane.mustInVisibleRange()) { - Grid grid = reportPane.getGrid(); - if (evtX > grid.getWidth() - 2 || evtY > grid.getHeight() - 2) { - return; - } - } - Selection selection = reportPane.getSelection(); - - if (selection instanceof FloatSelection && !BaseUtils.isAuthorityEditing()) { - doWithFloatElementDragged(evtX, evtY, (FloatSelection) selection); - grid.setDragType(GridUtils.DRAG_FLOAT); - } else if (grid.getDragType() == GridUtils.DRAG_CELLSELECTION_BOTTOMRIGHT_CORNER && !BaseUtils.isAuthorityEditing()) { - doWithCellElementDragged(evtX, evtY, (CellSelection) selection); - } else if (grid.getDragType() == GridUtils.DRAG_CELLSELECTION && !BaseUtils.isAuthorityEditing()) { - // peter:获得调整过的Selected Column Row. - ColumnRow selectedCellPoint = GridUtils.getAdjustEventColumnRow(reportPane, evtX, evtY); - if (selectedCellPoint.getColumn() != grid.getDragRectangle().x || selectedCellPoint.getRow() != grid.getDragRectangle().y) { - grid.getDragRectangle().x = selectedCellPoint.getColumn(); - grid.getDragRectangle().y = selectedCellPoint.getRow(); - } - } else {// august: 拖拽选中多个单元格 - doShiftSelectCell(evtX, evtY); - } - grid.getElementCasePane().repaint(); - } - - /** - * 拖拽悬浮元素 - * - * @param evtX - * @param evtY - * @param fs - */ - - private void doWithFloatElementDragged(int evtX, int evtY, FloatSelection fs) { - ElementCase report = grid.getElementCasePane().getEditingElementCase(); - int resolution = ScreenResolution.getScreenResolution(); - String floatName = fs.getSelectedFloatName(); - FloatElement floatElement = report.getFloatElement(floatName); - int cursorType = grid.getCursor().getType(); - - if (cursorType == Cursor.NW_RESIZE_CURSOR || cursorType == Cursor.NE_RESIZE_CURSOR || cursorType == Cursor.SE_RESIZE_CURSOR || cursorType == Cursor.SW_RESIZE_CURSOR) { - DynamicUnitList columnWidthList = ReportHelper.getColumnWidthList(report); - DynamicUnitList rowHeightList = ReportHelper.getRowHeightList(report); - FU floatX1_fu = FU.valueOfPix(Math.min(oldEvtX, evtX), resolution); - FU floatY1_fu = FU.valueOfPix(Math.min(oldEvtY, evtY), resolution); - FU leftDistance = floatX1_fu.add(columnWidthList.getRangeValue(0, grid.getHorizontalValue())); - FU topDistance = floatY1_fu.add(rowHeightList.getRangeValue(0, grid.getVerticalValue())); - floatElement.setLeftDistance(leftDistance); - floatElement.setTopDistance(topDistance); - floatElement.setWidth(FU.valueOfPix(Math.max(oldEvtX, evtX), resolution).subtract(floatX1_fu)); - floatElement.setHeight(FU.valueOfPix(Math.max(oldEvtY, evtY), resolution).subtract(floatY1_fu)); - } else if (cursorType == Cursor.S_RESIZE_CURSOR || cursorType == Cursor.N_RESIZE_CURSOR) { - DynamicUnitList rowHeightList = ReportHelper.getRowHeightList(report); - FU floatY1_fu = FU.valueOfPix(Math.min(oldEvtY, evtY), resolution); - FU topDistance = floatY1_fu.add(rowHeightList.getRangeValue(0, grid.getVerticalValue())); - floatElement.setTopDistance(topDistance); - floatElement.setHeight(FU.valueOfPix(Math.max(oldEvtY, evtY), resolution).subtract(floatY1_fu)); - } else if (cursorType == Cursor.W_RESIZE_CURSOR || cursorType == Cursor.E_RESIZE_CURSOR) { - DynamicUnitList columnWidthList = ReportHelper.getColumnWidthList(report); - FU floatX1_fu = FU.valueOfPix(Math.min(oldEvtX, evtX), resolution); - FU leftDistance = floatX1_fu.add(columnWidthList.getRangeValue(0, grid.getHorizontalValue())); - floatElement.setLeftDistance(leftDistance); - floatElement.setWidth(FU.valueOfPix(Math.max(oldEvtX, evtX), resolution).subtract(floatX1_fu)); - } else if (cursorType == Cursor.MOVE_CURSOR) { - DynamicUnitList columnWidthList = ReportHelper.getColumnWidthList(report); - DynamicUnitList rowHeightList = ReportHelper.getRowHeightList(report); - int horizentalValue = grid.getHorizontalValue(); - int verticalValue = grid.getVerticalValue(); - String floatElementName = fs.getSelectedFloatName(); - FloatElement tempFolatElement = report.getFloatElement(floatElementName); - Point tempFolatElementPoint = floatNamePointMap.get(floatElementName); - int floatX1ForTempFloatElement = tempFolatElementPoint.x + Math.max(oldLocationX + (evtX - oldEvtX), 0); - int floatY1ForTempFloatElement = tempFolatElementPoint.y + Math.max(oldLocationY + (evtY - oldEvtY), 0); - FU floatX1ForTempFloatElement_fu = FU.valueOfPix(floatX1ForTempFloatElement, resolution); - FU leftDistance = floatX1ForTempFloatElement_fu.add(columnWidthList.getRangeValue(0, horizentalValue)); - FU floatY1ForTempFloatElement_fu = FU.valueOfPix(floatY1ForTempFloatElement, resolution); - FU topDistance = floatY1ForTempFloatElement_fu.add(rowHeightList.getRangeValue(0, verticalValue)); - tempFolatElement.setLeftDistance(leftDistance); - tempFolatElement.setTopDistance(topDistance); - } - - } - - /** - * 拖拽单元格 - * - * @param evtX - * @param evtY - * @param cs - */ - - private void doWithCellElementDragged(int evtX, int evtY, CellSelection cs) { - ElementCasePane reportPane = grid.getElementCasePane(); - java.awt.Rectangle cellRectangle = cs.toRectangle(); - - ColumnRow selectedCellPoint = GridUtils.getAdjustEventColumnRow(reportPane, evtX, evtY); - if (cellRectangle.contains(selectedCellPoint.getColumn(), selectedCellPoint.getRow())) { - grid.getDragRectangle().setBounds(cellRectangle); - } else { - int xDistance = evtX - this.oldEvtX; - int yDistance = evtY - this.oldEvtY; - if (Math.abs(yDistance) > Math.abs(xDistance)) { - grid.getDragRectangle().x = cellRectangle.x; - grid.getDragRectangle().width = cellRectangle.width; - if (yDistance >= 0) { - // 聚合报表要求拖拽的时候要在本块的内部进行 不能无限往下拖 - if (reportPane instanceof ECBlockPane && evtY > reportPane.getBounds().height - ECBlockGap) { - return; - } - grid.getDragRectangle().y = cellRectangle.y; - grid.getDragRectangle().height = selectedCellPoint.getRow() - cellRectangle.y + 1; - } else { - if (selectedCellPoint.getRow() >= cellRectangle.y && selectedCellPoint.getRow() < cellRectangle.y + cellRectangle.height) { - grid.getDragRectangle().y = cellRectangle.y; - grid.getDragRectangle().height = cellRectangle.height; - } else { - grid.getDragRectangle().y = cellRectangle.y; - grid.getDragRectangle().height = cellRectangle.y - selectedCellPoint.getRow() + cellRectangle.height; - } - } - } else { - grid.getDragRectangle().y = cellRectangle.y; - grid.getDragRectangle().height = cellRectangle.height; - if (xDistance >= 0) { - if (reportPane instanceof ECBlockPane && evtX > reportPane.getBounds().width - ECBlockGap) { - return; - } - grid.getDragRectangle().x = cellRectangle.x; - grid.getDragRectangle().width = selectedCellPoint.getColumn() - cellRectangle.x + 1; - } else { - if (selectedCellPoint.getColumn() >= cellRectangle.x && selectedCellPoint.getColumn() < cellRectangle.x + cellRectangle.width) { - grid.getDragRectangle().x = cellRectangle.x; - grid.getDragRectangle().width = cellRectangle.width; - } else { - grid.getDragRectangle().x = selectedCellPoint.getColumn(); - grid.getDragRectangle().width = cellRectangle.x - selectedCellPoint.getColumn() + cellRectangle.width; - } - } - } - } - reportPane.ensureColumnRowVisible(selectedCellPoint.getColumn() + 1, selectedCellPoint.getRow() + 1); - } - - private void doShiftSelectCell(double evtX, double evtY) { - ElementCasePane reportPane = grid.getElementCasePane(); - Selection s = reportPane.getSelection(); - if (s instanceof FloatSelection) { - return; - } - ColumnRow selectedCellPoint = GridUtils.getAdjustEventColumnRow(reportPane, evtX, evtY); - int selectedCellPointX = selectedCellPoint.getColumn(); - int selectedCellPointY = selectedCellPoint.getRow(); - CellSelection gridSelection = ((CellSelection) s).clone(); - //反向选择单元格 - int tempOldSelectedCellX = tempOldSelectedCell.getColumn(); - int tempOldSelectedCellY = tempOldSelectedCell.getRow(); + } + doWithFormatBrush(reportPane); + reportPane.repaint(); + } + + private void doWithFormatBrush(ElementCasePane reportPane) { + if (DesignerContext.getFormatState() == DesignerContext.FORMAT_STATE_NULL) { + return; + } + + if (reportPane.getCellNeedTOFormat() != null) { + reportPane.getFormatBrushAction().updateFormatBrush(DesignerContext.getReferencedStyle(), reportPane.getCellNeedTOFormat(), reportPane); + reportPane.fireTargetModified(); + + } + if (DesignerContext.getFormatState() == DesignerContext.FORMAT_STATE_ONCE) { + reportPane.cancelFormatBrush(); + } + if (DesignerContext.getFormatState() == DesignerContext.FORMAT_STATE_MORE) { + reportPane.getFormatBrush().setSelected(true); + } + } + + private boolean outOfBounds(MouseEvent evt, ElementCasePane reportPane) { + return evt.getY() > reportPane.getHeight() || evt.getY() < 0 || evt.getX() > reportPane.getWidth() || evt.getX() < 0; + } + + /** + * @param evt + */ + public void mouseMoved(final MouseEvent evt) { + ElementCasePane reportPane = grid.getElementCasePane(); + boolean isGridForSelection = !grid.isEnabled() || !grid.isEditable(); + if (isGridForSelection || grid.isEditing()) { + if (grid.IsNotShowingTableSelectPane()) { + grid.setCursor(UIConstants.CELL_DEFAULT_CURSOR); + return; + } + if (DesignerContext.getFormatState() != DesignerContext.FORMAT_STATE_NULL) { + grid.setCursor(UIConstants.FORMAT_BRUSH_CURSOR); + } else { + grid.setCursor(GUICoreUtils.createCustomCursor(BaseUtils.readImage("com/fr/design/images/buttonicon/select.png"), + new Point(0, 0), "select", grid)); + } + + return; + } + // peter:停留一段时间. + long systemCurrentTime = System.currentTimeMillis(); + if (systemCurrentTime - lastMouseMoveTime <= TIME_DELAY) { + return; + } + lastMouseMoveTime = systemCurrentTime;// 记录最后一次的时间. + mouseMoveOnGrid(evt.getX(), evt.getY()); + } + + /** + * @param evt + */ + public void mouseDragged(MouseEvent evt) { + if (!grid.isEnabled()) { + return; + } + + boolean isControlDown = InputEventBaseOnOS.isControlDown(evt); + + long systemCurrentTime = System.currentTimeMillis(); + if (systemCurrentTime - lastMouseMoveTime <= DRAG_REFRESH_TIME) {// alex:Drag + return; + } else { + lastMouseMoveTime = systemCurrentTime; + } + + // right mouse cannot Drag.. + if (SwingUtilities.isRightMouseButton(evt)) { + return; + } + + doWithMouseDragged(evt.getX(), evt.getY(), isControlDown); + } + + private void doWithMouseDragged(int evtX, int evtY, boolean isControlDown) { + ElementCasePane reportPane = grid.getElementCasePane(); + + if (reportPane.mustInVisibleRange()) { + Grid grid = reportPane.getGrid(); + if (evtX > grid.getWidth() - 2 || evtY > grid.getHeight() - 2) { + return; + } + } + Selection selection = reportPane.getSelection(); + + if (selection instanceof FloatSelection && !BaseUtils.isAuthorityEditing()) { + doWithFloatElementDragged(evtX, evtY, (FloatSelection) selection); + grid.setDragType(GridUtils.DRAG_FLOAT); + } else if (grid.getDragType() == GridUtils.DRAG_CELLSELECTION_BOTTOMRIGHT_CORNER && !BaseUtils.isAuthorityEditing()) { + doWithCellElementDragged(evtX, evtY, (CellSelection) selection); + } else if (grid.getDragType() == GridUtils.DRAG_CELLSELECTION && !BaseUtils.isAuthorityEditing()) { + // peter:获得调整过的Selected Column Row. + ColumnRow selectedCellPoint = GridUtils.getAdjustEventColumnRow(reportPane, evtX, evtY); + if (selectedCellPoint.getColumn() != grid.getDragRectangle().x || selectedCellPoint.getRow() != grid.getDragRectangle().y) { + grid.getDragRectangle().x = selectedCellPoint.getColumn(); + grid.getDragRectangle().y = selectedCellPoint.getRow(); + } + } else {// august: 拖拽选中多个单元格 + doShiftSelectCell(evtX, evtY); + } + grid.getElementCasePane().repaint(); + } + + /** + * 拖拽悬浮元素 + * + * @param evtX + * @param evtY + * @param fs + */ + + private void doWithFloatElementDragged(int evtX, int evtY, FloatSelection fs) { + ElementCase report = grid.getElementCasePane().getEditingElementCase(); + int resolution = ScreenResolution.getScreenResolution(); + String floatName = fs.getSelectedFloatName(); + FloatElement floatElement = report.getFloatElement(floatName); + int cursorType = grid.getCursor().getType(); + + if (cursorType == Cursor.NW_RESIZE_CURSOR || cursorType == Cursor.NE_RESIZE_CURSOR || cursorType == Cursor.SE_RESIZE_CURSOR || cursorType == Cursor.SW_RESIZE_CURSOR) { + DynamicUnitList columnWidthList = ReportHelper.getColumnWidthList(report); + DynamicUnitList rowHeightList = ReportHelper.getRowHeightList(report); + FU floatX1_fu = FU.valueOfPix(Math.min(oldEvtX, evtX), resolution); + FU floatY1_fu = FU.valueOfPix(Math.min(oldEvtY, evtY), resolution); + FU leftDistance = floatX1_fu.add(columnWidthList.getRangeValue(0, grid.getHorizontalValue())); + FU topDistance = floatY1_fu.add(rowHeightList.getRangeValue(0, grid.getVerticalValue())); + floatElement.setLeftDistance(leftDistance); + floatElement.setTopDistance(topDistance); + floatElement.setWidth(FU.valueOfPix(Math.max(oldEvtX, evtX), resolution).subtract(floatX1_fu)); + floatElement.setHeight(FU.valueOfPix(Math.max(oldEvtY, evtY), resolution).subtract(floatY1_fu)); + } else if (cursorType == Cursor.S_RESIZE_CURSOR || cursorType == Cursor.N_RESIZE_CURSOR) { + DynamicUnitList rowHeightList = ReportHelper.getRowHeightList(report); + FU floatY1_fu = FU.valueOfPix(Math.min(oldEvtY, evtY), resolution); + FU topDistance = floatY1_fu.add(rowHeightList.getRangeValue(0, grid.getVerticalValue())); + floatElement.setTopDistance(topDistance); + floatElement.setHeight(FU.valueOfPix(Math.max(oldEvtY, evtY), resolution).subtract(floatY1_fu)); + } else if (cursorType == Cursor.W_RESIZE_CURSOR || cursorType == Cursor.E_RESIZE_CURSOR) { + DynamicUnitList columnWidthList = ReportHelper.getColumnWidthList(report); + FU floatX1_fu = FU.valueOfPix(Math.min(oldEvtX, evtX), resolution); + FU leftDistance = floatX1_fu.add(columnWidthList.getRangeValue(0, grid.getHorizontalValue())); + floatElement.setLeftDistance(leftDistance); + floatElement.setWidth(FU.valueOfPix(Math.max(oldEvtX, evtX), resolution).subtract(floatX1_fu)); + } else if (cursorType == Cursor.MOVE_CURSOR) { + DynamicUnitList columnWidthList = ReportHelper.getColumnWidthList(report); + DynamicUnitList rowHeightList = ReportHelper.getRowHeightList(report); + int horizentalValue = grid.getHorizontalValue(); + int verticalValue = grid.getVerticalValue(); + String floatElementName = fs.getSelectedFloatName(); + FloatElement tempFolatElement = report.getFloatElement(floatElementName); + Point tempFolatElementPoint = floatNamePointMap.get(floatElementName); + int floatX1ForTempFloatElement = tempFolatElementPoint.x + Math.max(oldLocationX + (evtX - oldEvtX), 0); + int floatY1ForTempFloatElement = tempFolatElementPoint.y + Math.max(oldLocationY + (evtY - oldEvtY), 0); + FU floatX1ForTempFloatElement_fu = FU.valueOfPix(floatX1ForTempFloatElement, resolution); + FU leftDistance = floatX1ForTempFloatElement_fu.add(columnWidthList.getRangeValue(0, horizentalValue)); + FU floatY1ForTempFloatElement_fu = FU.valueOfPix(floatY1ForTempFloatElement, resolution); + FU topDistance = floatY1ForTempFloatElement_fu.add(rowHeightList.getRangeValue(0, verticalValue)); + tempFolatElement.setLeftDistance(leftDistance); + tempFolatElement.setTopDistance(topDistance); + } + + } + + /** + * 拖拽单元格 + * + * @param evtX + * @param evtY + * @param cs + */ + + private void doWithCellElementDragged(int evtX, int evtY, CellSelection cs) { + ElementCasePane reportPane = grid.getElementCasePane(); + java.awt.Rectangle cellRectangle = cs.toRectangle(); + + ColumnRow selectedCellPoint = GridUtils.getAdjustEventColumnRow(reportPane, evtX, evtY); + if (cellRectangle.contains(selectedCellPoint.getColumn(), selectedCellPoint.getRow())) { + grid.getDragRectangle().setBounds(cellRectangle); + } else { + int xDistance = evtX - this.oldEvtX; + int yDistance = evtY - this.oldEvtY; + if (Math.abs(yDistance) > Math.abs(xDistance)) { + grid.getDragRectangle().x = cellRectangle.x; + grid.getDragRectangle().width = cellRectangle.width; + if (yDistance >= 0) { + // 聚合报表要求拖拽的时候要在本块的内部进行 不能无限往下拖 + if (reportPane instanceof ECBlockPane && evtY > reportPane.getBounds().height - ECBlockGap) { + return; + } + grid.getDragRectangle().y = cellRectangle.y; + grid.getDragRectangle().height = selectedCellPoint.getRow() - cellRectangle.y + 1; + } else { + if (selectedCellPoint.getRow() >= cellRectangle.y && selectedCellPoint.getRow() < cellRectangle.y + cellRectangle.height) { + grid.getDragRectangle().y = cellRectangle.y; + grid.getDragRectangle().height = cellRectangle.height; + } else { + grid.getDragRectangle().y = cellRectangle.y; + grid.getDragRectangle().height = cellRectangle.y - selectedCellPoint.getRow() + cellRectangle.height; + } + } + } else { + grid.getDragRectangle().y = cellRectangle.y; + grid.getDragRectangle().height = cellRectangle.height; + if (xDistance >= 0) { + if (reportPane instanceof ECBlockPane && evtX > reportPane.getBounds().width - ECBlockGap) { + return; + } + grid.getDragRectangle().x = cellRectangle.x; + grid.getDragRectangle().width = selectedCellPoint.getColumn() - cellRectangle.x + 1; + } else { + if (selectedCellPoint.getColumn() >= cellRectangle.x && selectedCellPoint.getColumn() < cellRectangle.x + cellRectangle.width) { + grid.getDragRectangle().x = cellRectangle.x; + grid.getDragRectangle().width = cellRectangle.width; + } else { + grid.getDragRectangle().x = selectedCellPoint.getColumn(); + grid.getDragRectangle().width = cellRectangle.x - selectedCellPoint.getColumn() + cellRectangle.width; + } + } + } + } + reportPane.ensureColumnRowVisible(selectedCellPoint.getColumn() + 1, selectedCellPoint.getRow() + 1); + } + + private void doShiftSelectCell(double evtX, double evtY) { + ElementCasePane reportPane = grid.getElementCasePane(); + Selection s = reportPane.getSelection(); + if (s instanceof FloatSelection) { + return; + } + ColumnRow selectedCellPoint = GridUtils.getAdjustEventColumnRow(reportPane, evtX, evtY); + int selectedCellPointX = selectedCellPoint.getColumn(); + int selectedCellPointY = selectedCellPoint.getRow(); + CellSelection gridSelection = ((CellSelection) s).clone(); + //反向选择单元格 + int tempOldSelectedCellX = tempOldSelectedCell.getColumn(); + int tempOldSelectedCellY = tempOldSelectedCell.getRow(); // int tempOldSelectedCellX = gridSelection.getEditRectangle().x; // int tempOldSelectedCellY = gridSelection.getEditRectangle().y; - int column = selectedCellPointX >= tempOldSelectedCellX ? tempOldSelectedCellX : selectedCellPointX; - int row = selectedCellPointY >= tempOldSelectedCellY ? tempOldSelectedCellY : selectedCellPointY; - int columnSpan = Math.abs(selectedCellPointX - tempOldSelectedCellX) + 1; - int rowSpan = Math.abs(selectedCellPointY - tempOldSelectedCellY) + 1; - Rectangle oldrectangle = new Rectangle(column, row, columnSpan, rowSpan); - // ajust them to got the correct selected bounds. - Rectangle newrectangle = grid.caculateIntersectsUnion(reportPane.getEditingElementCase(), oldrectangle); - gridSelection.setBounds(newrectangle.x, newrectangle.y, newrectangle.width, newrectangle.height); - gridSelection.clearCellRectangles(gridSelection.getCellRectangleCount() - 1); - gridSelection.addCellRectangle(newrectangle); - reportPane.setSelection(gridSelection); - if (!reportPane.mustInVisibleRange()) { - reportPane.ensureColumnRowVisible(selectedCellPointX, selectedCellPointY); - } - } - - - private void doControlSelectCell(double evtX, double evtY) { - ElementCasePane reportPane = grid.getElementCasePane(); - ElementCase report = reportPane.getEditingElementCase(); - //上一次选中的单元格 - Selection s = reportPane.getSelection(); - if (s instanceof FloatSelection) { - return; - } - - ColumnRow selectedCellPoint = GridUtils.getAdjustEventColumnRow(reportPane, evtX, evtY); - //拷贝,而不是直接强制使用以监听单元格选择变化 - CellSelection gridSelection = ((CellSelection) s).clone(); - gridSelection.setSelectedType(((CellSelection) s).getSelectedType()); - CellElement cellElement = report.getCellElement(selectedCellPoint.getColumn(), selectedCellPoint.getRow()); - if (cellElement == null) { - gridSelection.setBounds(selectedCellPoint.getColumn(), selectedCellPoint.getRow(), 1, 1); - int point = gridSelection.containsCell(selectedCellPoint.getColumn(), selectedCellPoint.getRow()); - if (point == -1) { - gridSelection.addCellRectangle(new Rectangle(selectedCellPoint.getColumn(), selectedCellPoint.getRow(), 1, 1)); - } else { - gridSelection.clearCellRectangles(point); - } - - } else { - gridSelection.setBounds(cellElement.getColumn(), cellElement.getRow(), cellElement.getColumnSpan(), cellElement.getRowSpan()); - gridSelection.addCellRectangle(new Rectangle(cellElement.getColumn(), cellElement.getRow(), cellElement.getColumnSpan(), cellElement.getRowSpan())); - - - } - - reportPane.setSelection(gridSelection); - - if (!reportPane.mustInVisibleRange()) { - reportPane.ensureColumnRowVisible(selectedCellPoint.getColumn(), selectedCellPoint.getRow()); - } - - - } - - - /** - * 鼠标在Grid上面移动. - */ - private void mouseMoveOnGrid(int evtX, int evtY) { - grid.setToolTipText(null); - if (grid.getDrawingFloatElement() != null) { - grid.setCursor(UIConstants.DRAW_CURSOR); // august:是否是将要画悬浮元素,就是那个笔的形状 - } else { - Object[] floatElementCursor = GridUtils.getAboveFloatElementCursor(grid.getElementCasePane(), evtX, evtY); - if (!ArrayUtils.isEmpty(floatElementCursor)) {// 鼠标在悬浮元素上移动 - grid.setCursor((Cursor) floatElementCursor[1]); - } else {// 鼠标在单元格上移动 - doMouseMoveOnCells(evtX, evtY); - } - } - } - - /** - * 鼠标在单元格上移动 - * - * @param evtX - * @param evtY - */ - private void doMouseMoveOnCells(int evtX, int evtY) { - ElementCasePane reportPane = grid.getElementCasePane(); - TemplateElementCase report = reportPane.getEditingElementCase(); - //如果是格式刷状态 - if (DesignerContext.getFormatState() != DesignerContext.FORMAT_STATE_NULL) { - grid.setCursor(UIConstants.FORMAT_BRUSH_CURSOR); - } else { - grid.setCursor(UIConstants.CELL_DEFAULT_CURSOR); - } - ColumnRow selectedCellColumnRow = GridUtils.getEventColumnRow(reportPane, evtX, evtY); - TemplateCellElement curCellElement = report.getTemplateCellElement(selectedCellColumnRow.getColumn(), selectedCellColumnRow.getRow()); - - if (curCellElement != null) { - setCursorAndToolTips(curCellElement, report); - } - - int dragType = isMoveCellSelection(evtX, evtY); - if (dragType == GridUtils.DRAG_CELLSELECTION) {// 判断是否移动选中的区域. - grid.setCursor(new Cursor(Cursor.MOVE_CURSOR)); - } // peter:判断是否复制移动的角落. - else if (dragType == GridUtils.DRAG_CELLSELECTION_BOTTOMRIGHT_CORNER) { - grid.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR)); - } - - } - - /** - * 只根据CellGUIAttr里面的tooltips显示了,原先的显示条件属性、形态、控件等无意义 - * - * @param curCellElement - * @param report - */ - private void setCursorAndToolTips(TemplateCellElement curCellElement, TemplateElementCase report) { - int resolution = ScreenResolution.getScreenResolution(); - // 计算相对Grid的显示位置. - DynamicUnitList columnWidthList = ReportHelper.getColumnWidthList(report); - DynamicUnitList rowHeightList = ReportHelper.getRowHeightList(report); - - CellGUIAttr cellGUIAttr = curCellElement.getCellGUIAttr(); - if (cellGUIAttr == null) { - cellGUIAttr = CellGUIAttr.DEFAULT_CELLGUIATTR; - } - grid.setToolTipText(cellGUIAttr.getTooltipText()); - double tooltipX = columnWidthList.getRangeValue(grid.getHorizontalValue(), curCellElement.getColumn()).toPixD(resolution) + TOOLTIP_X_Y_FIX; - double tooltipY = rowHeightList.getRangeValue(grid.getVerticalValue(), curCellElement.getRow() + curCellElement.getRowSpan()).toPixD(resolution) + TOOLTIP_X_Y_FIX; - - // peter:显示tooltip - if (StringUtils.isNotBlank(grid.getToolTipText())) { - grid.setTooltipLocation(tooltipX + TOOLTIP_X, tooltipY); - } - } - - /** - * 是否移动CellSelection - */ - private int isMoveCellSelection(double evtX, double evtY) { - ElementCasePane reportPane = grid.getElementCasePane(); - - // p:判断是否在选中区域的边框,可以移动CellSelelction选中区域 - Selection selection = reportPane.getSelection(); - if (!(selection instanceof CellSelection)) { - return GridUtils.DRAG_NONE; - } - - if ((selection instanceof CellSelection) - && ((CellSelection) selection).getCellRectangleCount() != 1) {// p:没有选择Cell. - return GridUtils.DRAG_NONE; - } - - CellSelection cs = (CellSelection) selection; - - ElementCase report = reportPane.getEditingElementCase(); - - // peter:计算相对Grid的显示位置. - DynamicUnitList columnWidthList = ReportHelper.getColumnWidthList(report); - DynamicUnitList rowHeightList = ReportHelper.getRowHeightList(report); - - int resolution = ScreenResolution.getScreenResolution(); - - double leftColDistance = columnWidthList.getRangeValue(grid.getHorizontalValue(), cs.getColumn()).toPixD(resolution); - double rightColDistance = columnWidthList.getRangeValue(grid.getHorizontalValue(), cs.getColumn() + cs.getColumnSpan()).toPixD(resolution); - double topRowDistance = rowHeightList.getRangeValue(grid.getVerticalValue(), cs.getRow()).toPixD(resolution); - double bottomRowDistance = rowHeightList.getRangeValue(grid.getVerticalValue(), cs.getRow() + cs.getRowSpan()).toPixD(resolution); - - // 首先判断是否在可以复制的右下角落. - if (fitCellSelectionBottomRight(evtX, evtY, rightColDistance, bottomRowDistance)) { - return GridUtils.DRAG_CELLSELECTION_BOTTOMRIGHT_CORNER; - } - - // 这个dist值调小一点,尽量让用户不使用drag and drop 来编辑报表支持 - double dist = 1.0; - if (fitCellSelection(evtX, leftColDistance, rightColDistance, dist)) { - if (evtY >= (topRowDistance - dist) && evtY <= (bottomRowDistance + dist)) { - return GridUtils.DRAG_CELLSELECTION; - } - } else if (fitCellSelection(evtY, topRowDistance, bottomRowDistance, dist)) { - if (evtX >= (leftColDistance - dist) && evtX <= (rightColDistance + dist)) { - return GridUtils.DRAG_CELLSELECTION; - } - } - - return GridUtils.DRAG_NONE; - } - - private boolean fitCellSelection(double evt, double d1, double d2, double dist) { - return (evt >= (d1 - dist) && evt <= (d1 + dist)) - || (evt >= (d2 - dist) && evt <= (d2 + dist)); - } - - private boolean fitCellSelectionBottomRight(double evtX, double evtY, double rightColDistance, double bottomRowDistance) { - return evtX > rightColDistance - COPY_CROSS_INNER_DISTANCE && evtX < rightColDistance + COPY_CROSS_OUTER_DISTANCE - && evtY > bottomRowDistance - COPY_CROSS_INNER_DISTANCE && bottomRowDistance < bottomRowDistance + COPY_CROSS_OUTER_DISTANCE; - } - - /** - * Do one click selection - */ - private void doOneClickSelection(int evtX, int evtY, boolean isShiftDown, boolean isControlDown) { - ElementCasePane reportPane = grid.getElementCasePane(); - // check float elements. - Object[] tmpFloatElementCursor = GridUtils.getAboveFloatElementCursor(reportPane, evtX, evtY); - if (!ArrayUtils.isEmpty(tmpFloatElementCursor)) {// p:选中了悬浮元素. - doSelectFloatElement(tmpFloatElementCursor, evtX, evtY); - } else if (isShiftDown) { - doShiftSelectCell(evtX, evtY); - } else if (isControlDown) { - doControlSelectCell(evtX, evtY); - } else { - ColumnRow selectedCellPoint = GridUtils.getEventColumnRow(reportPane, evtX, evtY); - int type = reportPane.ensureColumnRowVisible(selectedCellPoint.getColumn(), selectedCellPoint.getRow()); - if (type == ElementCasePane.NO_OVER) { - GridUtils.doSelectCell(reportPane, selectedCellPoint.getColumn(), selectedCellPoint.getRow()); - } else if (type == ElementCasePane.VERTICAL_OVER) { - //聚合报表块选在下边界的时候,有时会向下移,阻止向下移 - GridUtils.doSelectCell(reportPane, selectedCellPoint.getColumn(), selectedCellPoint.getRow() - 1); - } else if (type == ElementCasePane.HORIZONTAL_OVER) { - //聚合报表块选在右边界的时候,有时会向右移,阻止向右移 - GridUtils.doSelectCell(reportPane, selectedCellPoint.getColumn() - 1, selectedCellPoint.getRow()); - } else { - GridUtils.doSelectCell(reportPane, selectedCellPoint.getColumn() - 1, selectedCellPoint.getRow() - 1); - } - - return; - } - - } - - /** - * 选中悬浮元素 - * - * @param tmpFloatElementCursor - * @param evtX - * @param evtY - */ - - private void doSelectFloatElement(Object[] tmpFloatElementCursor, int evtX, int evtY) { - ElementCasePane reportPane = grid.getElementCasePane(); - ElementCase report = reportPane.getEditingElementCase(); - FloatElement floatElement = (FloatElement) tmpFloatElementCursor[0]; - String floatName = floatElement.getName(); - reportPane.setSelection(new FloatSelection(floatName)); - double[] floatArray = GridUtils.caculateFloatElementLocations(floatElement, ReportHelper.getColumnWidthList(report), ReportHelper.getRowHeightList(report), reportPane - .getGrid().getVerticalValue(), reportPane.getGrid().getHorizontalValue()); - - int cursorType = ((Cursor) tmpFloatElementCursor[1]).getType(); - if (cursorType == Cursor.MOVE_CURSOR) { - this.oldEvtX = evtX; - this.oldEvtY = evtY; - FloatElement el = report.getFloatElement(floatName); - int resolution = ScreenResolution.getScreenResolution(); - int verticalValue = grid.getVerticalValue(); - int horizentalValue = grid.getHorizontalValue(); - DynamicUnitList columnWidthList = ReportHelper.getColumnWidthList(report); - DynamicUnitList rowHeightList = ReportHelper.getRowHeightList(report); - this.oldLocationX = FU.getInstance(el.getLeftDistance().toFU() - columnWidthList.getRangeValue(0, horizentalValue).toFU()).toPixI(resolution); - this.oldLocationY = FU.getInstance(el.getTopDistance().toFU() - rowHeightList.getRangeValue(0, verticalValue).toFU()).toPixI(resolution); - if (floatNamePointMap == null) { - floatNamePointMap = new HashMap(); - } - floatNamePointMap.clear(); - FloatElement tempFolatElement = report.getFloatElement(floatName); - int floatX1ForTempFloatElement = FU.getInstance(tempFolatElement.getLeftDistance().toFU() - columnWidthList.getRangeValue(0, horizentalValue).toFU()) - .toPixI(resolution) - oldLocationX; - int floatY1ForTempFloatElement = FU.getInstance(tempFolatElement.getTopDistance().toFU() - rowHeightList.getRangeValue(0, verticalValue).toFU()).toPixI(resolution) - - oldLocationY; - floatNamePointMap.put(floatName, new Point(floatX1ForTempFloatElement, floatY1ForTempFloatElement)); - } else if (cursorType == Cursor.NW_RESIZE_CURSOR) { - setOld_X_AndOld_Y(floatArray[2], floatArray[3]); - } else if (cursorType == Cursor.NE_RESIZE_CURSOR) { - setOld_X_AndOld_Y(floatArray[0], floatArray[3]); - } else if (cursorType == Cursor.SE_RESIZE_CURSOR) { - setOld_X_AndOld_Y(floatArray[0], floatArray[1]); - } else if (cursorType == Cursor.SW_RESIZE_CURSOR) { - setOld_X_AndOld_Y(floatArray[2], floatArray[1]); - } else if (cursorType == Cursor.N_RESIZE_CURSOR) { - setOld_X_AndOld_Y(floatArray[0], floatArray[3]); - } else if (cursorType == Cursor.S_RESIZE_CURSOR) { - setOld_X_AndOld_Y(floatArray[0], floatArray[1]); - } else if (cursorType == Cursor.W_RESIZE_CURSOR) { - setOld_X_AndOld_Y(floatArray[2], floatArray[1]); - } else if (cursorType == Cursor.E_RESIZE_CURSOR) { - setOld_X_AndOld_Y(floatArray[0], floatArray[1]); - } - } - - private void setOld_X_AndOld_Y(double x, double y) { - this.oldEvtX = (int) x; - this.oldEvtY = (int) y; - } - - /** - * @param e - */ - public void mouseWheelMoved(MouseWheelEvent e) { - ElementCasePane reportPane = grid.getElementCasePane(); - if (reportPane.isHorizontalScrollBarVisible()) { - reportPane.getVerticalScrollBar().setValue(reportPane.getVerticalScrollBar().getValue() + e.getWheelRotation() * 3); - } - } - - /** - * @param e - */ - public void mouseClicked(MouseEvent e) { - } - - /** - * @param e - */ - public void mouseEntered(MouseEvent e) { - } - - /** - * @param e - */ - public void mouseExited(MouseEvent e) { - } + int column = selectedCellPointX >= tempOldSelectedCellX ? tempOldSelectedCellX : selectedCellPointX; + int row = selectedCellPointY >= tempOldSelectedCellY ? tempOldSelectedCellY : selectedCellPointY; + int columnSpan = Math.abs(selectedCellPointX - tempOldSelectedCellX) + 1; + int rowSpan = Math.abs(selectedCellPointY - tempOldSelectedCellY) + 1; + Rectangle oldrectangle = new Rectangle(column, row, columnSpan, rowSpan); + // ajust them to got the correct selected bounds. + Rectangle newrectangle = grid.caculateIntersectsUnion(reportPane.getEditingElementCase(), oldrectangle); + gridSelection.setBounds(newrectangle.x, newrectangle.y, newrectangle.width, newrectangle.height); + gridSelection.clearCellRectangles(gridSelection.getCellRectangleCount() - 1); + gridSelection.addCellRectangle(newrectangle); + reportPane.setSelection(gridSelection); + if (!reportPane.mustInVisibleRange()) { + reportPane.ensureColumnRowVisible(selectedCellPointX, selectedCellPointY); + } + } + + + private void doControlSelectCell(double evtX, double evtY) { + ElementCasePane reportPane = grid.getElementCasePane(); + ElementCase report = reportPane.getEditingElementCase(); + //上一次选中的单元格 + Selection s = reportPane.getSelection(); + if (s instanceof FloatSelection) { + return; + } + + ColumnRow selectedCellPoint = GridUtils.getAdjustEventColumnRow(reportPane, evtX, evtY); + //拷贝,而不是直接强制使用以监听单元格选择变化 + CellSelection gridSelection = ((CellSelection) s).clone(); + gridSelection.setSelectedType(((CellSelection) s).getSelectedType()); + CellElement cellElement = report.getCellElement(selectedCellPoint.getColumn(), selectedCellPoint.getRow()); + if (cellElement == null) { + gridSelection.setBounds(selectedCellPoint.getColumn(), selectedCellPoint.getRow(), 1, 1); + int point = gridSelection.containsCell(selectedCellPoint.getColumn(), selectedCellPoint.getRow()); + if (point == -1) { + gridSelection.addCellRectangle(new Rectangle(selectedCellPoint.getColumn(), selectedCellPoint.getRow(), 1, 1)); + } else { + gridSelection.clearCellRectangles(point); + } + + } else { + gridSelection.setBounds(cellElement.getColumn(), cellElement.getRow(), cellElement.getColumnSpan(), cellElement.getRowSpan()); + gridSelection.addCellRectangle(new Rectangle(cellElement.getColumn(), cellElement.getRow(), cellElement.getColumnSpan(), cellElement.getRowSpan())); + + + } + + reportPane.setSelection(gridSelection); + + if (!reportPane.mustInVisibleRange()) { + reportPane.ensureColumnRowVisible(selectedCellPoint.getColumn(), selectedCellPoint.getRow()); + } + + + } + + + /** + * 鼠标在Grid上面移动. + */ + private void mouseMoveOnGrid(int evtX, int evtY) { + grid.setToolTipText(null); + if (grid.getDrawingFloatElement() != null) { + grid.setCursor(UIConstants.DRAW_CURSOR); // august:是否是将要画悬浮元素,就是那个笔的形状 + } else { + Object[] floatElementCursor = GridUtils.getAboveFloatElementCursor(grid.getElementCasePane(), evtX, evtY); + if (!ArrayUtils.isEmpty(floatElementCursor)) {// 鼠标在悬浮元素上移动 + grid.setCursor((Cursor) floatElementCursor[1]); + } else {// 鼠标在单元格上移动 + doMouseMoveOnCells(evtX, evtY); + } + } + } + + /** + * 鼠标在单元格上移动 + * + * @param evtX + * @param evtY + */ + private void doMouseMoveOnCells(int evtX, int evtY) { + ElementCasePane reportPane = grid.getElementCasePane(); + TemplateElementCase report = reportPane.getEditingElementCase(); + //如果是格式刷状态 + if (DesignerContext.getFormatState() != DesignerContext.FORMAT_STATE_NULL) { + grid.setCursor(UIConstants.FORMAT_BRUSH_CURSOR); + } else { + grid.setCursor(UIConstants.CELL_DEFAULT_CURSOR); + } + ColumnRow selectedCellColumnRow = GridUtils.getEventColumnRow(reportPane, evtX, evtY); + TemplateCellElement curCellElement = report.getTemplateCellElement(selectedCellColumnRow.getColumn(), selectedCellColumnRow.getRow()); + + if (curCellElement != null) { + setCursorAndToolTips(curCellElement, report); + } + + int dragType = isMoveCellSelection(evtX, evtY); + if (dragType == GridUtils.DRAG_CELLSELECTION) {// 判断是否移动选中的区域. + grid.setCursor(new Cursor(Cursor.MOVE_CURSOR)); + } // peter:判断是否复制移动的角落. + else if (dragType == GridUtils.DRAG_CELLSELECTION_BOTTOMRIGHT_CORNER) { + grid.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR)); + } + + } + + /** + * 只根据CellGUIAttr里面的tooltips显示了,原先的显示条件属性、形态、控件等无意义 + * + * @param curCellElement + * @param report + */ + private void setCursorAndToolTips(TemplateCellElement curCellElement, TemplateElementCase report) { + int resolution = ScreenResolution.getScreenResolution(); + // 计算相对Grid的显示位置. + DynamicUnitList columnWidthList = ReportHelper.getColumnWidthList(report); + DynamicUnitList rowHeightList = ReportHelper.getRowHeightList(report); + + CellGUIAttr cellGUIAttr = curCellElement.getCellGUIAttr(); + if (cellGUIAttr == null) { + cellGUIAttr = CellGUIAttr.DEFAULT_CELLGUIATTR; + } + grid.setToolTipText(cellGUIAttr.getTooltipText()); + double tooltipX = columnWidthList.getRangeValue(grid.getHorizontalValue(), curCellElement.getColumn()).toPixD(resolution) + TOOLTIP_X_Y_FIX; + double tooltipY = rowHeightList.getRangeValue(grid.getVerticalValue(), curCellElement.getRow() + curCellElement.getRowSpan()).toPixD(resolution) + TOOLTIP_X_Y_FIX; + + // peter:显示tooltip + if (StringUtils.isNotBlank(grid.getToolTipText())) { + grid.setTooltipLocation(tooltipX + TOOLTIP_X, tooltipY); + } + } + + /** + * 是否移动CellSelection + */ + private int isMoveCellSelection(double evtX, double evtY) { + ElementCasePane reportPane = grid.getElementCasePane(); + + // p:判断是否在选中区域的边框,可以移动CellSelelction选中区域 + Selection selection = reportPane.getSelection(); + if (!(selection instanceof CellSelection)) { + return GridUtils.DRAG_NONE; + } + + if ((selection instanceof CellSelection) + && ((CellSelection) selection).getCellRectangleCount() != 1) {// p:没有选择Cell. + return GridUtils.DRAG_NONE; + } + + CellSelection cs = (CellSelection) selection; + + ElementCase report = reportPane.getEditingElementCase(); + + // peter:计算相对Grid的显示位置. + DynamicUnitList columnWidthList = ReportHelper.getColumnWidthList(report); + DynamicUnitList rowHeightList = ReportHelper.getRowHeightList(report); + + int resolution = ScreenResolution.getScreenResolution(); + + double leftColDistance = columnWidthList.getRangeValue(grid.getHorizontalValue(), cs.getColumn()).toPixD(resolution); + double rightColDistance = columnWidthList.getRangeValue(grid.getHorizontalValue(), cs.getColumn() + cs.getColumnSpan()).toPixD(resolution); + double topRowDistance = rowHeightList.getRangeValue(grid.getVerticalValue(), cs.getRow()).toPixD(resolution); + double bottomRowDistance = rowHeightList.getRangeValue(grid.getVerticalValue(), cs.getRow() + cs.getRowSpan()).toPixD(resolution); + + // 首先判断是否在可以复制的右下角落. + if (fitCellSelectionBottomRight(evtX, evtY, rightColDistance, bottomRowDistance)) { + return GridUtils.DRAG_CELLSELECTION_BOTTOMRIGHT_CORNER; + } + + // 这个dist值调小一点,尽量让用户不使用drag and drop 来编辑报表支持 + double dist = 1.0; + if (fitCellSelection(evtX, leftColDistance, rightColDistance, dist)) { + if (evtY >= (topRowDistance - dist) && evtY <= (bottomRowDistance + dist)) { + return GridUtils.DRAG_CELLSELECTION; + } + } else if (fitCellSelection(evtY, topRowDistance, bottomRowDistance, dist)) { + if (evtX >= (leftColDistance - dist) && evtX <= (rightColDistance + dist)) { + return GridUtils.DRAG_CELLSELECTION; + } + } + + return GridUtils.DRAG_NONE; + } + + private boolean fitCellSelection(double evt, double d1, double d2, double dist) { + return (evt >= (d1 - dist) && evt <= (d1 + dist)) + || (evt >= (d2 - dist) && evt <= (d2 + dist)); + } + + private boolean fitCellSelectionBottomRight(double evtX, double evtY, double rightColDistance, double bottomRowDistance) { + return evtX > rightColDistance - COPY_CROSS_INNER_DISTANCE && evtX < rightColDistance + COPY_CROSS_OUTER_DISTANCE + && evtY > bottomRowDistance - COPY_CROSS_INNER_DISTANCE && bottomRowDistance < bottomRowDistance + COPY_CROSS_OUTER_DISTANCE; + } + + /** + * Do one click selection + */ + private void doOneClickSelection(int evtX, int evtY, boolean isShiftDown, boolean isControlDown) { + ElementCasePane reportPane = grid.getElementCasePane(); + // check float elements. + Object[] tmpFloatElementCursor = GridUtils.getAboveFloatElementCursor(reportPane, evtX, evtY); + if (!ArrayUtils.isEmpty(tmpFloatElementCursor)) {// p:选中了悬浮元素. + doSelectFloatElement(tmpFloatElementCursor, evtX, evtY); + } else if (isShiftDown) { + doShiftSelectCell(evtX, evtY); + } else if (isControlDown) { + doControlSelectCell(evtX, evtY); + } else { + ColumnRow selectedCellPoint = GridUtils.getEventColumnRow(reportPane, evtX, evtY); + int type = reportPane.ensureColumnRowVisible(selectedCellPoint.getColumn(), selectedCellPoint.getRow()); + if (type == ElementCasePane.NO_OVER) { + GridUtils.doSelectCell(reportPane, selectedCellPoint.getColumn(), selectedCellPoint.getRow()); + } else if (type == ElementCasePane.VERTICAL_OVER) { + //聚合报表块选在下边界的时候,有时会向下移,阻止向下移 + GridUtils.doSelectCell(reportPane, selectedCellPoint.getColumn(), selectedCellPoint.getRow() - 1); + } else if (type == ElementCasePane.HORIZONTAL_OVER) { + //聚合报表块选在右边界的时候,有时会向右移,阻止向右移 + GridUtils.doSelectCell(reportPane, selectedCellPoint.getColumn() - 1, selectedCellPoint.getRow()); + } else { + GridUtils.doSelectCell(reportPane, selectedCellPoint.getColumn() - 1, selectedCellPoint.getRow() - 1); + } + + return; + } + + } + + /** + * 选中悬浮元素 + * + * @param tmpFloatElementCursor + * @param evtX + * @param evtY + */ + + private void doSelectFloatElement(Object[] tmpFloatElementCursor, int evtX, int evtY) { + ElementCasePane reportPane = grid.getElementCasePane(); + ElementCase report = reportPane.getEditingElementCase(); + FloatElement floatElement = (FloatElement) tmpFloatElementCursor[0]; + String floatName = floatElement.getName(); + reportPane.setSelection(new FloatSelection(floatName)); + double[] floatArray = GridUtils.caculateFloatElementLocations(floatElement, ReportHelper.getColumnWidthList(report), ReportHelper.getRowHeightList(report), reportPane + .getGrid().getVerticalValue(), reportPane.getGrid().getHorizontalValue()); + + int cursorType = ((Cursor) tmpFloatElementCursor[1]).getType(); + if (cursorType == Cursor.MOVE_CURSOR) { + this.oldEvtX = evtX; + this.oldEvtY = evtY; + FloatElement el = report.getFloatElement(floatName); + int resolution = ScreenResolution.getScreenResolution(); + int verticalValue = grid.getVerticalValue(); + int horizentalValue = grid.getHorizontalValue(); + DynamicUnitList columnWidthList = ReportHelper.getColumnWidthList(report); + DynamicUnitList rowHeightList = ReportHelper.getRowHeightList(report); + this.oldLocationX = FU.getInstance(el.getLeftDistance().toFU() - columnWidthList.getRangeValue(0, horizentalValue).toFU()).toPixI(resolution); + this.oldLocationY = FU.getInstance(el.getTopDistance().toFU() - rowHeightList.getRangeValue(0, verticalValue).toFU()).toPixI(resolution); + if (floatNamePointMap == null) { + floatNamePointMap = new HashMap(); + } + floatNamePointMap.clear(); + FloatElement tempFolatElement = report.getFloatElement(floatName); + int floatX1ForTempFloatElement = FU.getInstance(tempFolatElement.getLeftDistance().toFU() - columnWidthList.getRangeValue(0, horizentalValue).toFU()) + .toPixI(resolution) - oldLocationX; + int floatY1ForTempFloatElement = FU.getInstance(tempFolatElement.getTopDistance().toFU() - rowHeightList.getRangeValue(0, verticalValue).toFU()).toPixI(resolution) + - oldLocationY; + floatNamePointMap.put(floatName, new Point(floatX1ForTempFloatElement, floatY1ForTempFloatElement)); + } else if (cursorType == Cursor.NW_RESIZE_CURSOR) { + setOld_X_AndOld_Y(floatArray[2], floatArray[3]); + } else if (cursorType == Cursor.NE_RESIZE_CURSOR) { + setOld_X_AndOld_Y(floatArray[0], floatArray[3]); + } else if (cursorType == Cursor.SE_RESIZE_CURSOR) { + setOld_X_AndOld_Y(floatArray[0], floatArray[1]); + } else if (cursorType == Cursor.SW_RESIZE_CURSOR) { + setOld_X_AndOld_Y(floatArray[2], floatArray[1]); + } else if (cursorType == Cursor.N_RESIZE_CURSOR) { + setOld_X_AndOld_Y(floatArray[0], floatArray[3]); + } else if (cursorType == Cursor.S_RESIZE_CURSOR) { + setOld_X_AndOld_Y(floatArray[0], floatArray[1]); + } else if (cursorType == Cursor.W_RESIZE_CURSOR) { + setOld_X_AndOld_Y(floatArray[2], floatArray[1]); + } else if (cursorType == Cursor.E_RESIZE_CURSOR) { + setOld_X_AndOld_Y(floatArray[0], floatArray[1]); + } + } + + private void setOld_X_AndOld_Y(double x, double y) { + this.oldEvtX = (int) x; + this.oldEvtY = (int) y; + } + + /** + * @param e + */ + public void mouseWheelMoved(MouseWheelEvent e) { + ElementCasePane reportPane = grid.getElementCasePane(); + if (reportPane.isHorizontalScrollBarVisible()) { + reportPane.getVerticalScrollBar().setValue(reportPane.getVerticalScrollBar().getValue() + e.getWheelRotation() * 3); + } + } + + /** + * @param e + */ + public void mouseClicked(MouseEvent e) { + } + + /** + * @param e + */ + public void mouseEntered(MouseEvent e) { + } + + /** + * @param e + */ + public void mouseExited(MouseEvent e) { + } } \ No newline at end of file diff --git a/designer_base/src/com/fr/common/inputevent/InputEventBaseOnOS.java b/designer_base/src/com/fr/common/inputevent/InputEventBaseOnOS.java new file mode 100644 index 0000000000..cee80d334a --- /dev/null +++ b/designer_base/src/com/fr/common/inputevent/InputEventBaseOnOS.java @@ -0,0 +1,21 @@ +package com.fr.common.inputevent; + +import com.fr.stable.OperatingSystem; + +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; + +/** + * Created by hzzz on 2017/5/26. + */ +public class InputEventBaseOnOS { + private static final boolean isMacOS = OperatingSystem.isMacOS(); + + public static boolean isControlDown(MouseEvent e) { + return isMacOS ? e.isMetaDown() : e.isControlDown(); + } + + public static boolean isControlDown(KeyEvent e) { + return isMacOS ? e.isMetaDown() : e.isControlDown(); + } +} diff --git a/designer_base/src/com/fr/design/gui/icombobox/ExtendedComboBox.java b/designer_base/src/com/fr/design/gui/icombobox/ExtendedComboBox.java index 47ddbdac3b..512b5713b3 100644 --- a/designer_base/src/com/fr/design/gui/icombobox/ExtendedComboBox.java +++ b/designer_base/src/com/fr/design/gui/icombobox/ExtendedComboBox.java @@ -1,5 +1,7 @@ package com.fr.design.gui.icombobox; +import com.fr.common.inputevent.InputEventBaseOnOS; + import java.awt.Component; import java.awt.Dimension; import java.awt.Point; @@ -76,7 +78,7 @@ public class ExtendedComboBox extends UIComboBox { protected JList createList() { return new JList(comboBox.getModel()) { public void processMouseEvent(MouseEvent e) { - if (e.isControlDown()) { + if (InputEventBaseOnOS.isControlDown(e)) { // Fix for 4234053. Filter out the Control // Key from the list. // ie., don't allow CTRL key deselection. diff --git a/designer_base/src/com/fr/design/gui/icombobox/UIComboBoxUI.java b/designer_base/src/com/fr/design/gui/icombobox/UIComboBoxUI.java index ae1089fa92..f5cd1eabbc 100644 --- a/designer_base/src/com/fr/design/gui/icombobox/UIComboBoxUI.java +++ b/designer_base/src/com/fr/design/gui/icombobox/UIComboBoxUI.java @@ -16,6 +16,7 @@ import javax.swing.plaf.basic.BasicComboBoxUI; import javax.swing.plaf.basic.BasicComboPopup; import javax.swing.plaf.basic.ComboPopup; +import com.fr.common.inputevent.InputEventBaseOnOS; import com.fr.design.constants.UIConstants; import sun.swing.DefaultLookup; @@ -209,7 +210,7 @@ public class UIComboBoxUI extends BasicComboBoxUI implements MouseListener { @Override public void processMouseEvent(MouseEvent e) { - if (e.isControlDown()) { + if (InputEventBaseOnOS.isControlDown(e)) { e = new MouseEvent((Component) e.getSource(), e.getID(), e.getWhen(), e.getModifiers() ^ DEFAULT_MODIFIER, e.getX(), e.getY(), e.getClickCount(), e.isPopupTrigger()); } diff --git a/designer_base/src/com/fr/design/gui/ilist/CheckBoxList.java b/designer_base/src/com/fr/design/gui/ilist/CheckBoxList.java index 0ef0f829a0..fa21465cb7 100644 --- a/designer_base/src/com/fr/design/gui/ilist/CheckBoxList.java +++ b/designer_base/src/com/fr/design/gui/ilist/CheckBoxList.java @@ -22,6 +22,7 @@ import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.border.EmptyBorder; +import com.fr.common.inputevent.InputEventBaseOnOS; import com.fr.design.gui.icheckbox.UICheckBox; import com.fr.stable.StringUtils; @@ -176,7 +177,7 @@ public class CheckBoxList extends JComponent { @Override protected void processMouseEvent(MouseEvent e) { if (e.getX() < 20) { - if (e.isControlDown() || e.isAltDown() || e.isShiftDown() || e.isMetaDown()) { + if (InputEventBaseOnOS.isControlDown(e) || e.isAltDown() || e.isShiftDown() || e.isMetaDown()) { int[] indices = getSelectedIndices(); if (indices.length == 0) { super.processMouseEvent(e); diff --git a/designer_base/src/com/fr/design/gui/itable/TableSorter.java b/designer_base/src/com/fr/design/gui/itable/TableSorter.java index 0ea84af03d..93b2c51542 100644 --- a/designer_base/src/com/fr/design/gui/itable/TableSorter.java +++ b/designer_base/src/com/fr/design/gui/itable/TableSorter.java @@ -15,6 +15,8 @@ import java.util.List; import java.util.Map; import javax.swing.Icon; + +import com.fr.common.inputevent.InputEventBaseOnOS; import com.fr.design.gui.ilable.UILabel; import javax.swing.JTable; import javax.swing.event.TableModelEvent; @@ -396,7 +398,7 @@ public class TableSorter extends AbstractTableModel { int column = columnModel.getColumn(viewColumn).getModelIndex(); if (column != -1) { int status = getSortingStatus(column); - if (!e.isControlDown()) { + if (!InputEventBaseOnOS.isControlDown(e)) { cancelSorting(); } // Cycle the sorting states through {NOT_SORTED, ASCENDING, DESCENDING} or diff --git a/designer_base/src/com/fr/design/gui/itree/refreshabletree/UserObjectRefreshJTree.java b/designer_base/src/com/fr/design/gui/itree/refreshabletree/UserObjectRefreshJTree.java index b463ca7eb6..0224a4349d 100644 --- a/designer_base/src/com/fr/design/gui/itree/refreshabletree/UserObjectRefreshJTree.java +++ b/designer_base/src/com/fr/design/gui/itree/refreshabletree/UserObjectRefreshJTree.java @@ -1,5 +1,6 @@ package com.fr.design.gui.itree.refreshabletree; +import com.fr.common.inputevent.InputEventBaseOnOS; import com.fr.general.NameObject; import com.fr.design.gui.itree.refreshabletree.loader.ChildrenLoaderFactory; import com.fr.general.ComparatorUtils; @@ -147,7 +148,7 @@ public abstract class UserObjectRefreshJTree> extends } } // marks:鼠标在上次选中的paths上,则将上次的paths设为的树的路径,否则将鼠标所在的节点设为选中的节点 - if (!(e.isShiftDown() || e.isControlDown())) { + if (!(e.isShiftDown() || InputEventBaseOnOS.isControlDown(e))) { if (isFind) { setSelectionPaths(oldPaths); } else { diff --git a/designer_base/src/com/fr/design/roleAuthority/UIRoleTreeUI.java b/designer_base/src/com/fr/design/roleAuthority/UIRoleTreeUI.java index e6b049b33b..9b996410ac 100644 --- a/designer_base/src/com/fr/design/roleAuthority/UIRoleTreeUI.java +++ b/designer_base/src/com/fr/design/roleAuthority/UIRoleTreeUI.java @@ -1,5 +1,6 @@ package com.fr.design.roleAuthority; +import com.fr.common.inputevent.InputEventBaseOnOS; import com.fr.design.gui.itree.UITreeUI; import javax.swing.tree.TreePath; @@ -15,7 +16,7 @@ import java.awt.event.MouseEvent; public class UIRoleTreeUI extends UITreeUI { protected void selectPathForEvent(TreePath path, MouseEvent event) { /* Adjust from the anchor point. */ - if (event.isControlDown() && tree.isPathSelected(path)) { + if (InputEventBaseOnOS.isControlDown(event) && tree.isPathSelected(path)) { tree.removeSelectionPath(path); } else if (event.isShiftDown()) { tree.setAnchorSelectionPath(null); diff --git a/designer_form/src/com/fr/design/designer/beans/models/SelectionModel.java b/designer_form/src/com/fr/design/designer/beans/models/SelectionModel.java index 13eaa18ac3..2fde27019b 100644 --- a/designer_form/src/com/fr/design/designer/beans/models/SelectionModel.java +++ b/designer_form/src/com/fr/design/designer/beans/models/SelectionModel.java @@ -1,5 +1,6 @@ package com.fr.design.designer.beans.models; +import com.fr.common.inputevent.InputEventBaseOnOS; import com.fr.design.designer.beans.AdapterBus; import com.fr.design.designer.beans.LayoutAdapter; import com.fr.design.designer.beans.events.DesignerEvent; @@ -61,7 +62,7 @@ public class SelectionModel { * @param e 鼠标事件 */ public void selectACreatorAtMouseEvent(MouseEvent e) { - if (!e.isControlDown() && !e.isShiftDown()) { + if (!InputEventBaseOnOS.isControlDown(e) && !e.isShiftDown()) { // 如果Ctrl或者Shift键盘没有按下,则清除已经选择的组件 selection.reset(); } @@ -372,7 +373,7 @@ public class SelectionModel { public Direction getDirectionAt(MouseEvent e) { Direction dir; - if (e.isControlDown() || e.isShiftDown()) { + if (InputEventBaseOnOS.isControlDown(e) || e.isShiftDown()) { XCreator creator = designer.getComponentAt(e.getX(), e.getY(), selection.getSelectedCreators()); if (creator != designer.getRootComponent() && selection.addedable(creator)) { return Location.add; From 082987e03ce28d22fcb691cb93e23c035d62f53e Mon Sep 17 00:00:00 2001 From: hzzz Date: Fri, 26 May 2017 10:12:54 +0800 Subject: [PATCH 29/41] PMD --- designer/src/com/fr/grid/GridKeyListener.java | 16 +++------- .../common/inputevent/InputEventBaseOnOS.java | 6 ++-- .../com/fr/design/gui/ilist/CheckBoxList.java | 29 +++++++++---------- .../com/fr/design/gui/itable/TableSorter.java | 16 ++++------ 4 files changed, 27 insertions(+), 40 deletions(-) diff --git a/designer/src/com/fr/grid/GridKeyListener.java b/designer/src/com/fr/grid/GridKeyListener.java index e60097fd6f..b3d57ab673 100644 --- a/designer/src/com/fr/grid/GridKeyListener.java +++ b/designer/src/com/fr/grid/GridKeyListener.java @@ -6,7 +6,6 @@ import com.fr.grid.selection.CellSelection; import com.fr.grid.selection.FloatSelection; import com.fr.grid.selection.Selection; import com.fr.report.elementcase.ElementCase; -import com.fr.stable.OperatingSystem; import java.awt.*; import java.awt.event.KeyEvent; @@ -18,6 +17,7 @@ import java.awt.event.KeyListener; */ public class GridKeyListener implements KeyListener { private static final int DIFF = 48; // 103 - 55 = 48, 小键盘和大键盘数字的差值 48 + private static final int DELAY = 32; private Grid grid; // Keypressed last time private long keyPressedLastTime = 0; @@ -31,8 +31,7 @@ public class GridKeyListener implements KeyListener { if (!grid.isEnabled() || evt.isConsumed()) {// 如果用户在自己的KyeListener里面consume了.就不执行下面的代码了. return; } - KeyEvent newEvt = KeyEventWork.processKeyEvent(evt); - if (newEvt == null) { + if (KeyEventWork.processKeyEvent(evt) == null) { return; } long systemCurrentTime = System.currentTimeMillis(); @@ -47,17 +46,14 @@ public class GridKeyListener implements KeyListener { keyPressedLastTime = systemCurrentTime; } dealWithFloatSelection(reportPane, code); - } else { - if (systemCurrentTime - keyPressedLastTime <= 32) { + if (systemCurrentTime - keyPressedLastTime <= DELAY) { return; } else { keyPressedLastTime = systemCurrentTime; } dealWithCellSelection(evt, code); - } - switch (code) { case KeyEvent.VK_PAGE_UP: {// page up reportPane.getVerticalScrollBar().setValue(Math.max(0, grid.getVerticalValue() - grid.getVerticalExtent())); @@ -71,16 +67,12 @@ public class GridKeyListener implements KeyListener { } // Richie:Ctrl + A全选单元格 case KeyEvent.VK_A: - boolean macOS = OperatingSystem.isMacOS() && evt.isMetaDown(); - boolean windows = OperatingSystem.isWindows() && InputEventBaseOnOS.isControlDown(evt); - if (macOS || windows) { + if (InputEventBaseOnOS.isControlDown(evt)) { reportPane.setSelection(new CellSelection(0, 0, report.getColumnCount(), report.getRowCount())); - isNeedRepaint = true; } isNeedRepaint = true; break; } - if (isNeedRepaint) { reportPane.repaint(); } diff --git a/designer_base/src/com/fr/common/inputevent/InputEventBaseOnOS.java b/designer_base/src/com/fr/common/inputevent/InputEventBaseOnOS.java index cee80d334a..29b6b9ce36 100644 --- a/designer_base/src/com/fr/common/inputevent/InputEventBaseOnOS.java +++ b/designer_base/src/com/fr/common/inputevent/InputEventBaseOnOS.java @@ -9,13 +9,13 @@ import java.awt.event.MouseEvent; * Created by hzzz on 2017/5/26. */ public class InputEventBaseOnOS { - private static final boolean isMacOS = OperatingSystem.isMacOS(); + private static final boolean IS_MACOS = OperatingSystem.isMacOS(); public static boolean isControlDown(MouseEvent e) { - return isMacOS ? e.isMetaDown() : e.isControlDown(); + return IS_MACOS ? e.isMetaDown() : e.isControlDown(); } public static boolean isControlDown(KeyEvent e) { - return isMacOS ? e.isMetaDown() : e.isControlDown(); + return IS_MACOS ? e.isMetaDown() : e.isControlDown(); } } diff --git a/designer_base/src/com/fr/design/gui/ilist/CheckBoxList.java b/designer_base/src/com/fr/design/gui/ilist/CheckBoxList.java index fa21465cb7..28c9e85e88 100644 --- a/designer_base/src/com/fr/design/gui/ilist/CheckBoxList.java +++ b/designer_base/src/com/fr/design/gui/ilist/CheckBoxList.java @@ -22,7 +22,6 @@ import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.border.EmptyBorder; -import com.fr.common.inputevent.InputEventBaseOnOS; import com.fr.design.gui.icheckbox.UICheckBox; import com.fr.stable.StringUtils; @@ -32,7 +31,7 @@ import com.fr.stable.StringUtils; public class CheckBoxList extends JComponent { /** * 选择状态----全选和全不选 - * + * * @editor zhou * @since 2012-4-1下午2:39:10 */ @@ -54,7 +53,7 @@ public class CheckBoxList extends JComponent { /** * Class constructor. - * + * * @param items * Items with which to populate the list. * @param default_state @@ -177,7 +176,7 @@ public class CheckBoxList extends JComponent { @Override protected void processMouseEvent(MouseEvent e) { if (e.getX() < 20) { - if (InputEventBaseOnOS.isControlDown(e) || e.isAltDown() || e.isShiftDown() || e.isMetaDown()) { + if (e.isControlDown() || e.isAltDown() || e.isShiftDown() || e.isMetaDown()) { int[] indices = getSelectedIndices(); if (indices.length == 0) { super.processMouseEvent(e); @@ -190,17 +189,17 @@ public class CheckBoxList extends JComponent { } int id = e.getID(); switch (id) { - case MouseEvent.MOUSE_PRESSED: - break; - case MouseEvent.MOUSE_RELEASED: - break; - case MouseEvent.MOUSE_CLICKED: - doCheck(); - break; - case MouseEvent.MOUSE_EXITED: - break; - case MouseEvent.MOUSE_ENTERED: - break; + case MouseEvent.MOUSE_PRESSED: + break; + case MouseEvent.MOUSE_RELEASED: + break; + case MouseEvent.MOUSE_CLICKED: + doCheck(); + break; + case MouseEvent.MOUSE_EXITED: + break; + case MouseEvent.MOUSE_ENTERED: + break; } } diff --git a/designer_base/src/com/fr/design/gui/itable/TableSorter.java b/designer_base/src/com/fr/design/gui/itable/TableSorter.java index 93b2c51542..4b2f2995c7 100644 --- a/designer_base/src/com/fr/design/gui/itable/TableSorter.java +++ b/designer_base/src/com/fr/design/gui/itable/TableSorter.java @@ -81,7 +81,7 @@ import javax.swing.table.TableModel; public class TableSorter extends AbstractTableModel { protected TableModel tableModel; - + private static final int ADD = 4; public static final int DESCENDING = -1; public static final int NOT_SORTED = 0; public static final int ASCENDING = 1; @@ -343,17 +343,14 @@ public class TableSorter extends AbstractTableModel { fireTableChanged(e); return; } - - // If the table structure has changed, cancel the sorting; the - // sorting columns may have been either moved or deleted from - // the model. + // If the table structure has changed, cancel the sorting; the + // sorting columns may have been either moved or deleted from the model. if (e.getFirstRow() == TableModelEvent.HEADER_ROW) { cancelSorting(); fireTableChanged(e); return; } - - // We can map a cell event through to the view without widening + // We can map a cell event through to the view without widening // when the following conditions apply: // // a) all the changes are on one row (e.getFirstRow() == e.getLastRow()) and, @@ -382,8 +379,7 @@ public class TableSorter extends AbstractTableModel { column, e.getType())); return; } - - // Something has happened to the data that may have invalidated the row order. + // Something has happened to the data that may have invalidated the row order. clearSortingState(); fireTableDataChanged(); return; @@ -404,7 +400,7 @@ public class TableSorter extends AbstractTableModel { // Cycle the sorting states through {NOT_SORTED, ASCENDING, DESCENDING} or // {NOT_SORTED, DESCENDING, ASCENDING} depending on whether shift is pressed. status = status + (e.isShiftDown() ? -1 : 1); - status = (status + 4) % 3 - 1; // signed mod, returning {-1, 0, 1} + status = (status + ADD) % 3 - 1; // signed mod, returning {-1, 0, 1} setSortingStatus(column, status); } } From 53bd97161031350f1a1cd2e941b08ea752ffb0d2 Mon Sep 17 00:00:00 2001 From: hzzz Date: Fri, 26 May 2017 10:15:10 +0800 Subject: [PATCH 30/41] PMD --- .../common/inputevent/InputEventBaseOnOS.java | 312 +++++++++++++++++- 1 file changed, 301 insertions(+), 11 deletions(-) diff --git a/designer_base/src/com/fr/common/inputevent/InputEventBaseOnOS.java b/designer_base/src/com/fr/common/inputevent/InputEventBaseOnOS.java index 29b6b9ce36..1ea424c67d 100644 --- a/designer_base/src/com/fr/common/inputevent/InputEventBaseOnOS.java +++ b/designer_base/src/com/fr/common/inputevent/InputEventBaseOnOS.java @@ -1,21 +1,311 @@ -package com.fr.common.inputevent; - -import com.fr.stable.OperatingSystem; +package com.fr.design.gui.ilist; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EventListener; +import java.util.List; + +import javax.swing.JComponent; +import javax.swing.JList; +import javax.swing.ListCellRenderer; +import javax.swing.ListModel; +import javax.swing.ListSelectionModel; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.border.EmptyBorder; + +import com.fr.design.gui.icheckbox.UICheckBox; +import com.fr.stable.StringUtils; /** - * Created by hzzz on 2017/5/26. + * CheckBoxs + JList. */ -public class InputEventBaseOnOS { - private static final boolean IS_MACOS = OperatingSystem.isMacOS(); +public class CheckBoxList extends JComponent { + /** + * 选择状态----全选和全不选 + * + * @editor zhou + * @since 2012-4-1下午2:39:10 + */ + public static enum SelectedState { + ALL, NONE + } + + private boolean[] selects; + private JList jlist; + private UICheckBox chooseAll; + + public CheckBoxList(Object[] items) { + this(items, SelectedState.NONE, StringUtils.EMPTY); + } + + public CheckBoxList(Object[] items, String name) { + this(items, SelectedState.NONE, name); + } + + /** + * Class constructor. + * + * @param items + * Items with which to populate the list. + * @param default_state + * default state, true or false + */ + public CheckBoxList(Object[] items, SelectedState state, String name) { + jlist = new BOXLIST(items); + jlist.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + this.selects = new boolean[items.length]; + boolean default_state = (state == SelectedState.ALL); + Arrays.fill(this.selects, default_state); + + jlist.setCellRenderer(new CheckListCellRenderer()); + jlist.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent e) { + doCheck(); + } + + public void mouseReleased(MouseEvent e) { + doCheck(); + } + }); + jlist.addKeyListener(new KeyAdapter() { + + @Override + public void keyTyped(KeyEvent e) { + if (e.getKeyChar() == ' ') { + doCheck(); + } + } + + }); + this.setLayout(new BorderLayout()); + chooseAll = new UICheckBox(name, default_state); + chooseAll.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if (chooseAll.isSelected()) { + setSelected(true); + } else { + setSelected(false); + } + } + }); + this.add(chooseAll, BorderLayout.NORTH); + this.add(jlist, BorderLayout.CENTER); + } + + /* + * 用于CellRenderer显示value为text + */ + protected String value2Text(Object value) { + return value != null ? value.toString() : StringUtils.EMPTY; + } + + public void setItems(Object[] os) { + if (os == null) { + this.setSelected(false); + } else { + for (int i = 0, len = os.length; i < len; i++) { + Object o = os[i]; + for (int j = 0, jen = jlist.getModel().getSize(); j < jen; j++) { + if (o.equals(jlist.getModel().getElementAt(j))) { + this.setSelected(j, true); + } + } + } + } + this.repaint(); + } + + /** + * Is selected + */ + public boolean isSelected(int index) { + if (selects == null || index >= selects.length) { + return false; + } + + return selects[index]; + } + + public void setSelected(int index, boolean isSelected) { + if (selects == null || index >= selects.length) { + return; + } + + selects[index] = isSelected; + this.repaint(this.getBounds()); + + this.fireCheckBoxListSelectionChangeListener(); + } + + private void setSelected(boolean isSelected) { + if (selects == null) { + return; + } + for (int i = 0; i < selects.length; i++) { + selects[i] = isSelected; + } + this.repaint(this.getBounds()); + + this.fireCheckBoxListSelectionChangeListener(); + } - public static boolean isControlDown(MouseEvent e) { - return IS_MACOS ? e.isMetaDown() : e.isControlDown(); + /** + * Returns an array of the objects that have been selected. Overrides the + * JList method. + */ + public Object[] getSelectedValues() { + return this.jlist.getSelectedValues(); } - public static boolean isControlDown(KeyEvent e) { - return IS_MACOS ? e.isMetaDown() : e.isControlDown(); + private class BOXLIST extends JList { + public BOXLIST(Object[] items) { + super(items); + } + + @Override + protected void processMouseEvent(MouseEvent e) { + if (e.getX() < 20) { + if (e.isControlDown() || e.isAltDown() || e.isShiftDown() || e.isMetaDown()) { + int[] indices = getSelectedIndices(); + if (indices.length == 0) { + super.processMouseEvent(e); + } + } else { + super.processMouseEvent(e); + } + } else { + super.processMouseEvent(e); + } + int id = e.getID(); + switch (id) { + case MouseEvent.MOUSE_PRESSED: + break; + case MouseEvent.MOUSE_RELEASED: + break; + case MouseEvent.MOUSE_CLICKED: + doCheck(); + break; + case MouseEvent.MOUSE_EXITED: + break; + case MouseEvent.MOUSE_ENTERED: + break; + } + } + + @Override + protected void processMouseMotionEvent(MouseEvent e) { + if (e.getX() < 20) { + return; + } + + super.processMouseEvent(e); + } + + @Override + public Object[] getSelectedValues() { + List list = new ArrayList(selects.length); + for (int i = 0; i < selects.length; i++) { + if (selects[i]) { + list.add(this.getModel().getElementAt(i)); + } + } + + return list.toArray(); + } + + } + + private void doCheck() { + // p:这里必须改变所有选择checkbox. + int index = jlist.getSelectedIndex(); + boolean sValue = !selects[index]; + + // p:开始设置所有选择的checkbox. + int[] indices = jlist.getSelectedIndices(); + for (int i = 0; i < indices.length; i++) { + setSelected(indices[i], sValue); + } + for (boolean selected : selects) { + if (!selected) { + chooseAll.setSelected(false); + return; + } + } + chooseAll.setSelected(true); + repaint(); + } + + private static final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1); + + private class CheckListCellRenderer extends UICheckBox implements ListCellRenderer { + + public CheckListCellRenderer() { + this.setOpaque(true); + this.setBorder(noFocusBorder); + } + + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + this.setText(value2Text(value)); + this.setSelected(selects[index]); + this.setFont(list.getFont()); + + if (isSelected) { + this.setBackground(list.getSelectionBackground()); + this.setForeground(list.getSelectionForeground()); + } else { + this.setBackground(list.getBackground()); + this.setForeground(list.getForeground()); + } + + if (cellHasFocus) { + this.setBorder(UIManager.getBorder("List.focusCellHighlightBorder")); + } else { + this.setBorder(noFocusBorder); + } + + return this; + } + } + + public void addCheckBoxListSelectionChangeListener(CheckBoxListSelectionChangeListener l) { + this.listenerList.add(CheckBoxListSelectionChangeListener.class, l); } -} + + public void removeCheckBoxListSelectionChangeListener(CheckBoxListSelectionChangeListener l) { + this.listenerList.remove(CheckBoxListSelectionChangeListener.class, l); + } + + public void fireCheckBoxListSelectionChangeListener() { + // Guaranteed to return a non-null array + Object[] listeners = listenerList.getListenerList(); + + // Process the listeners last to first, notifying + // those that are interested in this event + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == CheckBoxListSelectionChangeListener.class) { + ((CheckBoxListSelectionChangeListener)listeners[i + 1]).selectionChanged(this); + } + } + + } + + public static interface CheckBoxListSelectionChangeListener extends EventListener { + public void selectionChanged(CheckBoxList target); + } + + public ListModel getModel() { + return jlist.getModel(); + } + +} \ No newline at end of file From 35aa59377d871190b64b4f8a89fca01324346744 Mon Sep 17 00:00:00 2001 From: hzzz Date: Fri, 26 May 2017 10:16:13 +0800 Subject: [PATCH 31/41] PMD --- .../common/inputevent/InputEventBaseOnOS.java | 312 +----------------- 1 file changed, 11 insertions(+), 301 deletions(-) diff --git a/designer_base/src/com/fr/common/inputevent/InputEventBaseOnOS.java b/designer_base/src/com/fr/common/inputevent/InputEventBaseOnOS.java index 1ea424c67d..29b6b9ce36 100644 --- a/designer_base/src/com/fr/common/inputevent/InputEventBaseOnOS.java +++ b/designer_base/src/com/fr/common/inputevent/InputEventBaseOnOS.java @@ -1,311 +1,21 @@ -package com.fr.design.gui.ilist; +package com.fr.common.inputevent; + +import com.fr.stable.OperatingSystem; -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; -import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.EventListener; -import java.util.List; - -import javax.swing.JComponent; -import javax.swing.JList; -import javax.swing.ListCellRenderer; -import javax.swing.ListModel; -import javax.swing.ListSelectionModel; -import javax.swing.UIManager; -import javax.swing.border.Border; -import javax.swing.border.EmptyBorder; - -import com.fr.design.gui.icheckbox.UICheckBox; -import com.fr.stable.StringUtils; /** - * CheckBoxs + JList. + * Created by hzzz on 2017/5/26. */ -public class CheckBoxList extends JComponent { - /** - * 选择状态----全选和全不选 - * - * @editor zhou - * @since 2012-4-1下午2:39:10 - */ - public static enum SelectedState { - ALL, NONE - } - - private boolean[] selects; - private JList jlist; - private UICheckBox chooseAll; - - public CheckBoxList(Object[] items) { - this(items, SelectedState.NONE, StringUtils.EMPTY); - } - - public CheckBoxList(Object[] items, String name) { - this(items, SelectedState.NONE, name); - } - - /** - * Class constructor. - * - * @param items - * Items with which to populate the list. - * @param default_state - * default state, true or false - */ - public CheckBoxList(Object[] items, SelectedState state, String name) { - jlist = new BOXLIST(items); - jlist.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); - this.selects = new boolean[items.length]; - boolean default_state = (state == SelectedState.ALL); - Arrays.fill(this.selects, default_state); - - jlist.setCellRenderer(new CheckListCellRenderer()); - jlist.addMouseListener(new MouseAdapter() { - public void mousePressed(MouseEvent e) { - doCheck(); - } - - public void mouseReleased(MouseEvent e) { - doCheck(); - } - }); - jlist.addKeyListener(new KeyAdapter() { - - @Override - public void keyTyped(KeyEvent e) { - if (e.getKeyChar() == ' ') { - doCheck(); - } - } - - }); - this.setLayout(new BorderLayout()); - chooseAll = new UICheckBox(name, default_state); - chooseAll.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - if (chooseAll.isSelected()) { - setSelected(true); - } else { - setSelected(false); - } - } - }); - this.add(chooseAll, BorderLayout.NORTH); - this.add(jlist, BorderLayout.CENTER); - } - - /* - * 用于CellRenderer显示value为text - */ - protected String value2Text(Object value) { - return value != null ? value.toString() : StringUtils.EMPTY; - } - - public void setItems(Object[] os) { - if (os == null) { - this.setSelected(false); - } else { - for (int i = 0, len = os.length; i < len; i++) { - Object o = os[i]; - for (int j = 0, jen = jlist.getModel().getSize(); j < jen; j++) { - if (o.equals(jlist.getModel().getElementAt(j))) { - this.setSelected(j, true); - } - } - } - } - this.repaint(); - } - - /** - * Is selected - */ - public boolean isSelected(int index) { - if (selects == null || index >= selects.length) { - return false; - } - - return selects[index]; - } - - public void setSelected(int index, boolean isSelected) { - if (selects == null || index >= selects.length) { - return; - } - - selects[index] = isSelected; - this.repaint(this.getBounds()); - - this.fireCheckBoxListSelectionChangeListener(); - } - - private void setSelected(boolean isSelected) { - if (selects == null) { - return; - } - for (int i = 0; i < selects.length; i++) { - selects[i] = isSelected; - } - this.repaint(this.getBounds()); - - this.fireCheckBoxListSelectionChangeListener(); - } +public class InputEventBaseOnOS { + private static final boolean IS_MACOS = OperatingSystem.isMacOS(); - /** - * Returns an array of the objects that have been selected. Overrides the - * JList method. - */ - public Object[] getSelectedValues() { - return this.jlist.getSelectedValues(); + public static boolean isControlDown(MouseEvent e) { + return IS_MACOS ? e.isMetaDown() : e.isControlDown(); } - private class BOXLIST extends JList { - public BOXLIST(Object[] items) { - super(items); - } - - @Override - protected void processMouseEvent(MouseEvent e) { - if (e.getX() < 20) { - if (e.isControlDown() || e.isAltDown() || e.isShiftDown() || e.isMetaDown()) { - int[] indices = getSelectedIndices(); - if (indices.length == 0) { - super.processMouseEvent(e); - } - } else { - super.processMouseEvent(e); - } - } else { - super.processMouseEvent(e); - } - int id = e.getID(); - switch (id) { - case MouseEvent.MOUSE_PRESSED: - break; - case MouseEvent.MOUSE_RELEASED: - break; - case MouseEvent.MOUSE_CLICKED: - doCheck(); - break; - case MouseEvent.MOUSE_EXITED: - break; - case MouseEvent.MOUSE_ENTERED: - break; - } - } - - @Override - protected void processMouseMotionEvent(MouseEvent e) { - if (e.getX() < 20) { - return; - } - - super.processMouseEvent(e); - } - - @Override - public Object[] getSelectedValues() { - List list = new ArrayList(selects.length); - for (int i = 0; i < selects.length; i++) { - if (selects[i]) { - list.add(this.getModel().getElementAt(i)); - } - } - - return list.toArray(); - } - - } - - private void doCheck() { - // p:这里必须改变所有选择checkbox. - int index = jlist.getSelectedIndex(); - boolean sValue = !selects[index]; - - // p:开始设置所有选择的checkbox. - int[] indices = jlist.getSelectedIndices(); - for (int i = 0; i < indices.length; i++) { - setSelected(indices[i], sValue); - } - for (boolean selected : selects) { - if (!selected) { - chooseAll.setSelected(false); - return; - } - } - chooseAll.setSelected(true); - repaint(); - } - - private static final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1); - - private class CheckListCellRenderer extends UICheckBox implements ListCellRenderer { - - public CheckListCellRenderer() { - this.setOpaque(true); - this.setBorder(noFocusBorder); - } - - public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { - this.setText(value2Text(value)); - this.setSelected(selects[index]); - this.setFont(list.getFont()); - - if (isSelected) { - this.setBackground(list.getSelectionBackground()); - this.setForeground(list.getSelectionForeground()); - } else { - this.setBackground(list.getBackground()); - this.setForeground(list.getForeground()); - } - - if (cellHasFocus) { - this.setBorder(UIManager.getBorder("List.focusCellHighlightBorder")); - } else { - this.setBorder(noFocusBorder); - } - - return this; - } - } - - public void addCheckBoxListSelectionChangeListener(CheckBoxListSelectionChangeListener l) { - this.listenerList.add(CheckBoxListSelectionChangeListener.class, l); + public static boolean isControlDown(KeyEvent e) { + return IS_MACOS ? e.isMetaDown() : e.isControlDown(); } - - public void removeCheckBoxListSelectionChangeListener(CheckBoxListSelectionChangeListener l) { - this.listenerList.remove(CheckBoxListSelectionChangeListener.class, l); - } - - public void fireCheckBoxListSelectionChangeListener() { - // Guaranteed to return a non-null array - Object[] listeners = listenerList.getListenerList(); - - // Process the listeners last to first, notifying - // those that are interested in this event - for (int i = listeners.length - 2; i >= 0; i -= 2) { - if (listeners[i] == CheckBoxListSelectionChangeListener.class) { - ((CheckBoxListSelectionChangeListener)listeners[i + 1]).selectionChanged(this); - } - } - - } - - public static interface CheckBoxListSelectionChangeListener extends EventListener { - public void selectionChanged(CheckBoxList target); - } - - public ListModel getModel() { - return jlist.getModel(); - } - -} \ No newline at end of file +} From 85b2ed5e0424c000f47ef1e8f772a37223ed20e8 Mon Sep 17 00:00:00 2001 From: hzzz Date: Fri, 26 May 2017 10:20:05 +0800 Subject: [PATCH 32/41] PMD --- .../com/fr/design/gui/ilist/CheckBoxList.java | 585 +++++++++--------- 1 file changed, 287 insertions(+), 298 deletions(-) diff --git a/designer_base/src/com/fr/design/gui/ilist/CheckBoxList.java b/designer_base/src/com/fr/design/gui/ilist/CheckBoxList.java index 28c9e85e88..880e94d557 100644 --- a/designer_base/src/com/fr/design/gui/ilist/CheckBoxList.java +++ b/designer_base/src/com/fr/design/gui/ilist/CheckBoxList.java @@ -1,311 +1,300 @@ package com.fr.design.gui.ilist; -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; +import com.fr.design.gui.icheckbox.UICheckBox; +import com.fr.stable.StringUtils; + +import javax.swing.*; +import javax.swing.border.Border; +import javax.swing.border.EmptyBorder; +import java.awt.*; +import java.awt.event.*; import java.util.ArrayList; import java.util.Arrays; import java.util.EventListener; import java.util.List; -import javax.swing.JComponent; -import javax.swing.JList; -import javax.swing.ListCellRenderer; -import javax.swing.ListModel; -import javax.swing.ListSelectionModel; -import javax.swing.UIManager; -import javax.swing.border.Border; -import javax.swing.border.EmptyBorder; - -import com.fr.design.gui.icheckbox.UICheckBox; -import com.fr.stable.StringUtils; - /** * CheckBoxs + JList. */ public class CheckBoxList extends JComponent { - /** - * 选择状态----全选和全不选 - * - * @editor zhou - * @since 2012-4-1下午2:39:10 - */ - public static enum SelectedState { - ALL, NONE - } - - private boolean[] selects; - private JList jlist; - private UICheckBox chooseAll; - - public CheckBoxList(Object[] items) { - this(items, SelectedState.NONE, StringUtils.EMPTY); - } - - public CheckBoxList(Object[] items, String name) { - this(items, SelectedState.NONE, name); - } - - /** - * Class constructor. - * - * @param items - * Items with which to populate the list. - * @param default_state - * default state, true or false - */ - public CheckBoxList(Object[] items, SelectedState state, String name) { - jlist = new BOXLIST(items); - jlist.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); - this.selects = new boolean[items.length]; - boolean default_state = (state == SelectedState.ALL); - Arrays.fill(this.selects, default_state); - - jlist.setCellRenderer(new CheckListCellRenderer()); - jlist.addMouseListener(new MouseAdapter() { - public void mousePressed(MouseEvent e) { - doCheck(); - } - - public void mouseReleased(MouseEvent e) { - doCheck(); - } - }); - jlist.addKeyListener(new KeyAdapter() { - - @Override - public void keyTyped(KeyEvent e) { - if (e.getKeyChar() == ' ') { - doCheck(); - } - } - - }); - this.setLayout(new BorderLayout()); - chooseAll = new UICheckBox(name, default_state); - chooseAll.addActionListener(new ActionListener() { - - @Override - public void actionPerformed(ActionEvent e) { - if (chooseAll.isSelected()) { - setSelected(true); - } else { - setSelected(false); - } - } - }); - this.add(chooseAll, BorderLayout.NORTH); - this.add(jlist, BorderLayout.CENTER); - } - - /* - * 用于CellRenderer显示value为text - */ - protected String value2Text(Object value) { - return value != null ? value.toString() : StringUtils.EMPTY; - } - - public void setItems(Object[] os) { - if (os == null) { - this.setSelected(false); - } else { - for (int i = 0, len = os.length; i < len; i++) { - Object o = os[i]; - for (int j = 0, jen = jlist.getModel().getSize(); j < jen; j++) { - if (o.equals(jlist.getModel().getElementAt(j))) { - this.setSelected(j, true); - } - } - } - } - this.repaint(); - } - - /** - * Is selected - */ - public boolean isSelected(int index) { - if (selects == null || index >= selects.length) { - return false; - } - - return selects[index]; - } - - public void setSelected(int index, boolean isSelected) { - if (selects == null || index >= selects.length) { - return; - } - - selects[index] = isSelected; - this.repaint(this.getBounds()); - - this.fireCheckBoxListSelectionChangeListener(); - } - - private void setSelected(boolean isSelected) { - if (selects == null) { - return; - } - for (int i = 0; i < selects.length; i++) { - selects[i] = isSelected; - } - this.repaint(this.getBounds()); - - this.fireCheckBoxListSelectionChangeListener(); - } - - /** - * Returns an array of the objects that have been selected. Overrides the - * JList method. - */ - public Object[] getSelectedValues() { - return this.jlist.getSelectedValues(); - } - - private class BOXLIST extends JList { - public BOXLIST(Object[] items) { - super(items); - } - - @Override - protected void processMouseEvent(MouseEvent e) { - if (e.getX() < 20) { - if (e.isControlDown() || e.isAltDown() || e.isShiftDown() || e.isMetaDown()) { - int[] indices = getSelectedIndices(); - if (indices.length == 0) { - super.processMouseEvent(e); - } - } else { - super.processMouseEvent(e); - } - } else { - super.processMouseEvent(e); - } - int id = e.getID(); - switch (id) { - case MouseEvent.MOUSE_PRESSED: - break; - case MouseEvent.MOUSE_RELEASED: - break; - case MouseEvent.MOUSE_CLICKED: - doCheck(); - break; - case MouseEvent.MOUSE_EXITED: - break; - case MouseEvent.MOUSE_ENTERED: - break; - } - } - - @Override - protected void processMouseMotionEvent(MouseEvent e) { - if (e.getX() < 20) { - return; - } - - super.processMouseEvent(e); - } - - @Override - public Object[] getSelectedValues() { - List list = new ArrayList(selects.length); - for (int i = 0; i < selects.length; i++) { - if (selects[i]) { - list.add(this.getModel().getElementAt(i)); - } - } - - return list.toArray(); - } - - } - - private void doCheck() { - // p:这里必须改变所有选择checkbox. - int index = jlist.getSelectedIndex(); - boolean sValue = !selects[index]; - - // p:开始设置所有选择的checkbox. - int[] indices = jlist.getSelectedIndices(); - for (int i = 0; i < indices.length; i++) { - setSelected(indices[i], sValue); - } - for (boolean selected : selects) { - if (!selected) { - chooseAll.setSelected(false); - return; - } - } - chooseAll.setSelected(true); - repaint(); - } - - private static final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1); - - private class CheckListCellRenderer extends UICheckBox implements ListCellRenderer { - - public CheckListCellRenderer() { - this.setOpaque(true); - this.setBorder(noFocusBorder); - } - - public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { - this.setText(value2Text(value)); - this.setSelected(selects[index]); - this.setFont(list.getFont()); - - if (isSelected) { - this.setBackground(list.getSelectionBackground()); - this.setForeground(list.getSelectionForeground()); - } else { - this.setBackground(list.getBackground()); - this.setForeground(list.getForeground()); - } - - if (cellHasFocus) { - this.setBorder(UIManager.getBorder("List.focusCellHighlightBorder")); - } else { - this.setBorder(noFocusBorder); - } - - return this; - } - } - - public void addCheckBoxListSelectionChangeListener(CheckBoxListSelectionChangeListener l) { - this.listenerList.add(CheckBoxListSelectionChangeListener.class, l); - } - - public void removeCheckBoxListSelectionChangeListener(CheckBoxListSelectionChangeListener l) { - this.listenerList.remove(CheckBoxListSelectionChangeListener.class, l); - } - - public void fireCheckBoxListSelectionChangeListener() { - // Guaranteed to return a non-null array - Object[] listeners = listenerList.getListenerList(); - - // Process the listeners last to first, notifying - // those that are interested in this event - for (int i = listeners.length - 2; i >= 0; i -= 2) { - if (listeners[i] == CheckBoxListSelectionChangeListener.class) { - ((CheckBoxListSelectionChangeListener)listeners[i + 1]).selectionChanged(this); - } - } - - } - - public static interface CheckBoxListSelectionChangeListener extends EventListener { - public void selectionChanged(CheckBoxList target); - } - - public ListModel getModel() { - return jlist.getModel(); - } + private final static int X_COORDINATE = 20; + + /** + * 选择状态----全选和全不选 + * + * @editor zhou + * @since 2012-4-1下午2:39:10 + */ + public static enum SelectedState { + ALL, NONE + } + + private boolean[] selects; + private JList jlist; + private UICheckBox chooseAll; + + public CheckBoxList(Object[] items) { + this(items, SelectedState.NONE, StringUtils.EMPTY); + } + + public CheckBoxList(Object[] items, String name) { + this(items, SelectedState.NONE, name); + } + + /** + * Class constructor. + * + * @param items Items with which to populate the list. + * @param state default state, true or false + */ + public CheckBoxList(Object[] items, SelectedState state, String name) { + jlist = new BOXLIST(items); + jlist.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + this.selects = new boolean[items.length]; + boolean default_state = (state == SelectedState.ALL); + Arrays.fill(this.selects, default_state); + + jlist.setCellRenderer(new CheckListCellRenderer()); + jlist.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent e) { + doCheck(); + } + + public void mouseReleased(MouseEvent e) { + doCheck(); + } + }); + jlist.addKeyListener(new KeyAdapter() { + + @Override + public void keyTyped(KeyEvent e) { + if (e.getKeyChar() == ' ') { + doCheck(); + } + } + + }); + this.setLayout(new BorderLayout()); + chooseAll = new UICheckBox(name, default_state); + chooseAll.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if (chooseAll.isSelected()) { + setSelected(true); + } else { + setSelected(false); + } + } + }); + this.add(chooseAll, BorderLayout.NORTH); + this.add(jlist, BorderLayout.CENTER); + } + + /* + * 用于CellRenderer显示value为text + */ + protected String value2Text(Object value) { + return value != null ? value.toString() : StringUtils.EMPTY; + } + + public void setItems(Object[] os) { + if (os == null) { + this.setSelected(false); + } else { + for (int i = 0, len = os.length; i < len; i++) { + Object o = os[i]; + for (int j = 0, jen = jlist.getModel().getSize(); j < jen; j++) { + if (o.equals(jlist.getModel().getElementAt(j))) { + this.setSelected(j, true); + } + } + } + } + this.repaint(); + } + + /** + * Is selected + */ + public boolean isSelected(int index) { + if (selects == null || index >= selects.length) { + return false; + } + + return selects[index]; + } + + public void setSelected(int index, boolean isSelected) { + if (selects == null || index >= selects.length) { + return; + } + + selects[index] = isSelected; + this.repaint(this.getBounds()); + + this.fireCheckBoxListSelectionChangeListener(); + } + + private void setSelected(boolean isSelected) { + if (selects == null) { + return; + } + for (int i = 0; i < selects.length; i++) { + selects[i] = isSelected; + } + this.repaint(this.getBounds()); + + this.fireCheckBoxListSelectionChangeListener(); + } + + /** + * Returns an array of the objects that have been selected. Overrides the + * JList method. + */ + public Object[] getSelectedValues() { + return this.jlist.getSelectedValues(); + } + + private class BOXLIST extends JList { + public BOXLIST(Object[] items) { + super(items); + } + + @Override + protected void processMouseEvent(MouseEvent e) { + if (e.getX() < X_COORDINATE) { + boolean anyMaskDown = e.isControlDown() || e.isAltDown() || e.isShiftDown() || e.isMetaDown(); + if (anyMaskDown) { + int[] indices = getSelectedIndices(); + if (indices.length == 0) { + super.processMouseEvent(e); + } + } else { + super.processMouseEvent(e); + } + } else { + super.processMouseEvent(e); + } + int id = e.getID(); + switch (id) { + case MouseEvent.MOUSE_PRESSED: + break; + case MouseEvent.MOUSE_RELEASED: + break; + case MouseEvent.MOUSE_CLICKED: + doCheck(); + break; + case MouseEvent.MOUSE_EXITED: + break; + case MouseEvent.MOUSE_ENTERED: + break; + } + } + + @Override + protected void processMouseMotionEvent(MouseEvent e) { + if (e.getX() < X_COORDINATE) { + return; + } + + super.processMouseEvent(e); + } + + @Override + public Object[] getSelectedValues() { + List list = new ArrayList(selects.length); + for (int i = 0; i < selects.length; i++) { + if (selects[i]) { + list.add(this.getModel().getElementAt(i)); + } + } + + return list.toArray(); + } + + } + + private void doCheck() { + // p:这里必须改变所有选择checkbox. + int index = jlist.getSelectedIndex(); + boolean sValue = !selects[index]; + + // p:开始设置所有选择的checkbox. + int[] indices = jlist.getSelectedIndices(); + for (int i = 0; i < indices.length; i++) { + setSelected(indices[i], sValue); + } + for (boolean selected : selects) { + if (!selected) { + chooseAll.setSelected(false); + return; + } + } + chooseAll.setSelected(true); + repaint(); + } + + private static final Border NO_FOCUS_BORDER = new EmptyBorder(1, 1, 1, 1); + + private class CheckListCellRenderer extends UICheckBox implements ListCellRenderer { + + public CheckListCellRenderer() { + this.setOpaque(true); + this.setBorder(NO_FOCUS_BORDER); + } + + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + this.setText(value2Text(value)); + this.setSelected(selects[index]); + this.setFont(list.getFont()); + + if (isSelected) { + this.setBackground(list.getSelectionBackground()); + this.setForeground(list.getSelectionForeground()); + } else { + this.setBackground(list.getBackground()); + this.setForeground(list.getForeground()); + } + + if (cellHasFocus) { + this.setBorder(UIManager.getBorder("List.focusCellHighlightBorder")); + } else { + this.setBorder(NO_FOCUS_BORDER); + } + + return this; + } + } + + public void addCheckBoxListSelectionChangeListener(CheckBoxListSelectionChangeListener l) { + this.listenerList.add(CheckBoxListSelectionChangeListener.class, l); + } + + public void removeCheckBoxListSelectionChangeListener(CheckBoxListSelectionChangeListener l) { + this.listenerList.remove(CheckBoxListSelectionChangeListener.class, l); + } + + public void fireCheckBoxListSelectionChangeListener() { + // Guaranteed to return a non-null array + Object[] listeners = listenerList.getListenerList(); + + // Process the listeners last to first, notifying + // those that are interested in this event + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == CheckBoxListSelectionChangeListener.class) { + ((CheckBoxListSelectionChangeListener) listeners[i + 1]).selectionChanged(this); + } + } + + } + + public static interface CheckBoxListSelectionChangeListener extends EventListener { + public void selectionChanged(CheckBoxList target); + } + + public ListModel getModel() { + return jlist.getModel(); + } } \ No newline at end of file From b1187cbd05d47eea16d670cfa39bf8a5ce5a448a Mon Sep 17 00:00:00 2001 From: XiaXiang Date: Sat, 27 May 2017 14:58:02 +0800 Subject: [PATCH 33/41] =?UTF-8?q?alphafine=20=E5=B9=BF=E5=91=8A=E5=BC=B9?= =?UTF-8?q?=E7=AA=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mainframe/alphafine/images/check.png | Bin 0 -> 14790 bytes .../mainframe/alphafine/images/open.png | Bin 0 -> 17575 bytes .../mainframe/alphafine/images/remind.png | Bin 0 -> 189129 bytes .../alphafine/images/remind_close.png | Bin 0 -> 15340 bytes .../mainframe/alphafine/images/uncheck.png | Bin 0 -> 14691 bytes .../search/manager/AlphaSearchManager.java | 4 +- .../aspectj/designerbase/AlphaFineReminder.aj | 32 ++++- .../designerbase/TemplateProcessTracker.aj | 24 ++-- .../AlphaFine/AlphafineConfigManager.java | 33 ++++- .../actions/help/AlphaFine/RemindDialog.java | 52 +++++++ .../actions/help/AlphaFine/RemindPane.java | 129 ++++++++++++++++++ .../designerform/TemplateProcessTracker.aj | 118 ++++++++-------- 12 files changed, 315 insertions(+), 77 deletions(-) create mode 100644 designer/src/com/fr/design/mainframe/alphafine/images/check.png create mode 100644 designer/src/com/fr/design/mainframe/alphafine/images/open.png create mode 100644 designer/src/com/fr/design/mainframe/alphafine/images/remind.png create mode 100644 designer/src/com/fr/design/mainframe/alphafine/images/remind_close.png create mode 100644 designer/src/com/fr/design/mainframe/alphafine/images/uncheck.png create mode 100644 designer_base/src/com/fr/design/actions/help/AlphaFine/RemindDialog.java create mode 100644 designer_base/src/com/fr/design/actions/help/AlphaFine/RemindPane.java diff --git a/designer/src/com/fr/design/mainframe/alphafine/images/check.png b/designer/src/com/fr/design/mainframe/alphafine/images/check.png new file mode 100644 index 0000000000000000000000000000000000000000..1b0e017b57351a4d01708e0c3bd1a5b55cf67086 GIT binary patch literal 14790 zcmeI3du&rx9LF!3fNU%R0~z?B=>)4=dmnAr_R9?87aU*pa2FhLyXf+-V^B{V+cGiUSiFgBWLvneal zhkWK%qo64q>Nd40Dlj>1Emo1WyG<^Sjdgn5oTJ&qF>DLXcxcvPWmul^@C<9pzs&v` z7k0E93*rN`q+xTC^3I- zm32=bG_|!EtIB1vgalDe7+fFr(&eV&j2H8PfS?1v;k7ajE9dTGS)TLoY)cd4<{1V_ zl2exD2q}^r8AftAtz1hVXXhD?XBjjHqAbq=caS9L!cApCwMZUGxyqvVu}if1^jj|U8xyyW!DoL;yUXJqV6BYP zEm<9s!(kn8I7O>F;&O`|C%7ah%s$CJDRn>*Q^tPDr{UIIMy*ZmL0Dp_qX?J?*^5$|! zx10g7a6pDTSToio+miQ`cT_a4u4Y6!^2Xd$A%E%Fnas7q8wPlf7- zyrSEj7)?itpfs>C!G%SH3J5Ng1~w+Ru!v9r!G+Sm#sn7@5h@_KP#V~n;KCw81q2sL z0~-@uSVX9R;6iC&V}c8d2o(@qC=F~(aA6Ul0)h*rfsF|+EFx4uaG^A?F~NmJgbD~Q zlm<2?xUh&&0l|gRz{Ug@77;2SxKJ9{nBc-9LIngDN&_1cTv$Y?fZ#%DU}J&{iwG4E zTqq4}OmJZlp#p*nrGbqJE-WHcKyaZnura}fMT80nE|dl~Cb+POPyxY((!j<97ZwpJ zAh=K(*!YIHYKo8lfdqW!FAX2=yR-9^ID9bBBnEpz6g9GlqBd-zsB7c!`$vjOF%X&MNMhw47B!TF1-EK%BJU5%{lc;w6%GUr5;2+tKGKwrP&8#lKAGT z)4S5&Tf@WCPG7$8I1;QHpBpa1cD!{S3-m!4Ykop$!$H#EC6{@&R= z3+s0Md{5{D_1ly6uWfuse7}Bd4jo=Lf9}__U;jiJy=ED`f1T~}{$HOTJ@es=%#!uX zo4C}bD~+>aKR5^5&(EJ)JC<5AbToK;>&z=PQOlyPd#67=dU4;tLCt+?!2_dRFZSD> z-N)W{eeT8nht?mXI@T^+w&eVoEl<=&4h4_TKl0bdFKavWx@{-CN2dMLpq=a8Fk|bi zvE93y4xE#(9%|juabWBj&m()s9jCvs9KO44`!V;)w=RA8>8m5xR)j8YUfH<4`R}Xg c>kZUAd(RyoEuPnGJZah4-W7OvdH=@$0NuqSuK)l5 literal 0 HcmV?d00001 diff --git a/designer/src/com/fr/design/mainframe/alphafine/images/open.png b/designer/src/com/fr/design/mainframe/alphafine/images/open.png new file mode 100644 index 0000000000000000000000000000000000000000..b37113b4f962e77387927c86beae033c67f49c1b GIT binary patch literal 17575 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 Pl?cYp#rA@=|IYsdm204; literal 0 HcmV?d00001 diff --git a/designer/src/com/fr/design/mainframe/alphafine/images/remind.png b/designer/src/com/fr/design/mainframe/alphafine/images/remind.png new file mode 100644 index 0000000000000000000000000000000000000000..d7de53f9691742684ad65c805c2a1f7c3378d7af GIT binary patch literal 189129 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 NV`*k*T5pUc{vS3^RNepp literal 0 HcmV?d00001 diff --git a/designer/src/com/fr/design/mainframe/alphafine/images/remind_close.png b/designer/src/com/fr/design/mainframe/alphafine/images/remind_close.png new file mode 100644 index 0000000000000000000000000000000000000000..c418eb8e80af74160cf444ee632511d91bef73e3 GIT binary patch literal 15340 zcmeI3eNYo;9>*77DJoj9SkIS>v1(AmZeAfvh((ZsH1Z-UQWTbCfyE>nvWo;-B(0nZ z!|1^XWjuRheYpIf3{gH zqKpyZ4JtjRw?>hOpRh1RHl?-G91(3 zm`pVA66^dxq_r8d@#N^3fpXwiggBRFtvHGn78ZsSDne*m4l2`VG$UhoOQA;!I zs;vOQ0Mb#NOiGcJM3YH|F0dKMRa?QOEFA6XSt@&Qa)xB$dd3_(X{W}paXlWJdntHk zNDHnNkFt>jOWRUt+NATWvcwk%MNv`QstOfJ^n`)3a9o46=y22Ej1T4`qY0MOab78= zlFHR7G8L{;;&SCOEDXmmD2YcoEQg*pQrSf#a;R}Ra4X;(kaBnqu!D>QOZ=oPuolW= zG~n5^%}lU5%1q>tsMV6AMF$%prFUK7QM8G+fnkw4g%%yH8FIPT8Xjk1Si)i;pUbHJMTX}jH%cc^iA0WHe?1DL3xQ{ibHIz#S_57z9+8P#$J z8xB?j7#ZQ71(_Bd(KcAwqfg~#)l}foE0q{{p)&4szzg>e_ip6z!u`X&gVuExiq**n z$_;CVT-^EVIU3f2TLn_5R;d&!Ejqk;xFeCWlcv;Y3hZHqTbT-QVQ$axj!}&p$1*}4 z14hqeL4WG*x%9MxTLy5qf_iUPhEB70GyKBA;1&JCiQ#lY5ts&VEa2ir1PcUQFb&>V zz{QIQ76`at8oaT9ix&|r5OBdXcw+$1=HY-1zfy{V1a-O zrokHvxOfr40s$9HgEtm%@gjl+0xp;aZ!F;AMFa~3TrdsZSir@L2o?yqU>dx!fQuIq zED&(PG^QMJqO=+5u^Y^knb}Q1g}GoS#)*A#TWz` zuZ@e2OtF7`p|;HuxMAj{((~6QBt&0-ZAxBw+}xm~xOE%a8v@rgl`RS?ajf4Z4c}bW znVGS`?hqf3+@}wkUq59@?UN-{3y-|=LE?Kk0pSYQ)!E9re8mLo9yV0b^UeM6((?@M z-#Z_3IBurSf3?l$;q&nrqZRCiKI>49-RWzTEyBVTs8T&_E_f`Tml=Sx#R{_37)w`;Q6n2@pM9C7P$ zpi9{v(RS;t^zGUi>r8;22oeMu)iY;x3` zjHwIgBaWx0-@JYM>D3dT$eo#3ui@>t`=51pcfWK@M@r6poNp@KcKG)ziX0a@#yvl* zT3G?EY18*x&$dZhm!3U(_WqfB=gE!#w4Clw-?C|SRazc%vB~e9Wl@X%TYa@ArbC@L zc^k5Af9mhP%KOjm&Z6y-3US-RNoig44*1SIbtC+XQqb;yOp|}f|A5Oe#hGwo!QI65 zs~e{6Y^k05j_5$B@xH$`$~pa@q+&-45g&YNaYfPeu!c!FuO}@2+8A70eD2%LAGwM) zHn#sdc4>U|6+{BKH@0_8$3M8%y1DW6A>--LBY@C6#T9k6x5S^;~XmsQSY{T00(=vuA=Gn*6`!%$4^A z+opzui)NNI`u1MT**7mTsKe($=rKuG)_SL`cUgUx?Yp<`#gD(d>F(-==77&8{t4Or zgY-e#!HhG1arItt9zVRf{8Hz;UDrQPy43#!{4R24lz+6AxN@N%>1FOTw;$=N{Y}|| vvhUv4*O9i8KfY47E4cNys>zkl<{|4ArGNHAsoDni91^!`P4v-~neY7%tz|t& literal 0 HcmV?d00001 diff --git a/designer/src/com/fr/design/mainframe/alphafine/images/uncheck.png b/designer/src/com/fr/design/mainframe/alphafine/images/uncheck.png new file mode 100644 index 0000000000000000000000000000000000000000..0e23e1961907b11c77d3e6273b8c7f70bd47f634 GIT binary patch literal 14691 zcmeI3TZ|J`7{><%!moeP4SG{=EH<3o`z?&K%leGtAA) z-S?v0$Q{2kOnkLg7<0z*n`vm2m7fa{<B(NaGdQ=goJ1!E=Ja{A}_=^KEVl*ATLOKLgEFs{tBdf zaFn#vqBN3SUoVG$r2-|#F(r3gJX@8Xs z&m&|r8Fy9nvn%tmqUkQzRY|Vh)SU5VK9rRmly<#AJ`xn;1woL+s1%Le$;Tz02T6Qo zTaLV;YQ<@gBN`NA1u-n~q9jCM4xnt$fp?H9JMtxEfm)D9RivU}Rb(fvRpd#;nfhds zYc>L9V_iuZqik4sSSTG%a-Eui%Uf$wPPZLdS5PjS#tk7&QzbDGQTbSSA{dv$@nEE= z$U!;Ihl53)M-vL)ADuuk4`MzK?F&+84Q0yRFZI;wWu^x91*z|`G{WuS3Kf4L<( zq*+jENVD+@odzoxuV3#p8%5h%Tjx8@~+Z*85S`8B(6Mw9NrCgIh9M<#o-ASAg3ZOzKQe$1WK@|3TSM0ot- z1oyM_v)IH7VG8Ont{tbfBmCj6yGYKbSxSTN0VH8bGu_$tD*8( zR>OPPc2}l=cfIFn@91dU(#;4u>PCOEz@NG|mwqe0Wx#hUT;q17b($NS;R*-ME4spo zVLDm_(jdkZ7ZDK@P+X7(F{ZePh@gPtf;5OR#YIE}1r!&gL5wLbA|fcDxF8K;OmPtr zK>@`DX%J(Ii--scC@x5Y7*kwCL{LC+K^nxE;vyn~0*VXLAjT9I5fKznT#yDarnrcR zpn&3nG>9?9MMMMz6c?mHj43W6A}FA^APr(naS;(g0mTJr5MzpqhzJTOE=YqIQ(Qzu zP(X1(8pN35A|iqUiVM;p#uOJ35fo5dkOncPxQK|LfZ~EQh%v=QL<9vC7oI+W(Bgs7@aNy0eDsyRP2zL=-rl>>ob7$8 zbnD#V7vy81{E^`=H-5VBtv4QgZO@V2_x)N~Bb+#U_5Npji}BuVJB?lZN9P|K-?2D0 zd-tl`JG+zvhgKXfJ@MC$hd%u3@412H@9uqZY3bA>+{)ihAKtlc#h=Fa8=gP4^q12& zZdzXYVRmW!rSht|yVhn-Ucdj$2Ys(bkDlY-KiBth=%+nzK6&scnvuR<#7M^;czO2Q S*KfnaXL5s^vj^6V@B9yy>Ha 4) { + showReminderDialog(); + } else { + manager.setOperateCount(manager.getOperateCount() + 1); + } + } + } + + /** + * 弹框提醒使用AlphaFine + */ + private static void showReminderDialog() { + RemindDialog remindDialog = new RemindDialog(DesignerContext.getDesignerFrame()); + remindDialog.setVisible(true); + } + + } diff --git a/designer_base/src/com/fr/aspectj/designerbase/TemplateProcessTracker.aj b/designer_base/src/com/fr/aspectj/designerbase/TemplateProcessTracker.aj index bc8b58615b..1ab23100b1 100644 --- a/designer_base/src/com/fr/aspectj/designerbase/TemplateProcessTracker.aj +++ b/designer_base/src/com/fr/aspectj/designerbase/TemplateProcessTracker.aj @@ -5,29 +5,27 @@ package com.fr.aspectj.designerbase; * Created by plough on 2017/3/3. */ -import com.fr.design.mainframe.templateinfo.TemplateInfoCollector; import org.aspectj.lang.reflect.SourceLocation; import java.awt.event.ActionEvent; import java.awt.event.MouseEvent; -import java.util.Date; public aspect TemplateProcessTracker { //声明一个pointcut,匹配你需要的方法 - pointcut onMouseClicked(MouseEvent e) : + pointcut onMouseClicked(MouseEvent e): execution(* mouseClicked(MouseEvent)) && args(e); - pointcut onMousePressed(MouseEvent e) : + pointcut onMousePressed(MouseEvent e): execution(* mousePressed(MouseEvent)) && args(e); - pointcut onMouseReleased(MouseEvent e) : + pointcut onMouseReleased(MouseEvent e): execution(* mouseReleased(MouseEvent)) && args(e); - pointcut onActionPerformed(ActionEvent e) : + pointcut onActionPerformed(ActionEvent e): execution(* actionPerformed(ActionEvent)) && args(e); - pointcut onSetValueAt(Object v, int r, int c) : + pointcut onSetValueAt(Object v, int r, int c): execution(* setValueAt(java.lang.Object, int, int)) && args(v, r, c); //before表示之前的意思 //这整个表示在MouseAdapter的public void mouseXXX(MouseEvent)方法调用之前,你想要执行的代码 - before(MouseEvent e) : onMouseClicked(e) || onMousePressed(e) || onMouseReleased(e) { + before(MouseEvent e): onMouseClicked(e) || onMousePressed(e) || onMouseReleased(e) { SourceLocation sl = thisJoinPoint.getSourceLocation();//切面对应的代码位置 //String log = String.format("%s:\n%s\n%s\n%s\n\n", new Date(), sl, e, e.getSource()); @@ -35,10 +33,10 @@ public aspect TemplateProcessTracker { //TemplateInfoCollector.appendProcess(log); } //同上 - before(ActionEvent e) : onActionPerformed(e) { + before(ActionEvent e): onActionPerformed(e) { SourceLocation sl = thisJoinPoint.getSourceLocation(); // !within(LogHandlerBar) 没用, 手动过滤 - if (e.getSource().toString().contains("javax.swing.Timer")) { + if (e != null && e.getSource().toString().contains("javax.swing.Timer")) { return; } @@ -48,12 +46,12 @@ public aspect TemplateProcessTracker { } //同上 - before(Object v, int r, int c) : onSetValueAt(v, r, c) { + before(Object v, int r, int c): onSetValueAt(v, r, c) { SourceLocation sl = thisJoinPoint.getSourceLocation(); - //String log = String.format("%s:\n%s\nset value: %s at (%d, %d)\n\n", new Date(), sl, v, r, c); + //String log getSourceLocation= String.format("%s:\n%s\nset value: %s at (%d, %d)\n\n", new Date(), sl, v, r, c); String log = ""; - // TemplateInfoCollector.appendProcess(log); + // TemplateInfoCollector.appendProcess(log); } diff --git a/designer_base/src/com/fr/design/actions/help/AlphaFine/AlphafineConfigManager.java b/designer_base/src/com/fr/design/actions/help/AlphaFine/AlphafineConfigManager.java index aa73d7afe9..3aa6f44bdb 100644 --- a/designer_base/src/com/fr/design/actions/help/AlphaFine/AlphafineConfigManager.java +++ b/designer_base/src/com/fr/design/actions/help/AlphaFine/AlphafineConfigManager.java @@ -67,6 +67,15 @@ public class AlphafineConfigManager implements XMLable { */ private KeyStroke shortCutKeyStore; + /** + * 是否提醒 + */ + private boolean isNeedRemind = true; + + /** + * 直接操作菜单次数 + */ + private int operateCount; @@ -92,7 +101,9 @@ public class AlphafineConfigManager implements XMLable { this.setContainAction(reader.getAttrAsBoolean("isContainAction", true)); this.setContainTemplate(reader.getAttrAsBoolean("isContainTemplate", true)); this.setContainFileContent(reader.getAttrAsBoolean("isContainFileContent", false)); - this.setShortcuts(reader.getAttrAsString("shortcuts", "meta + f")); + this.setShortcuts(reader.getAttrAsString("shortcuts", getDefaultShortCuts())); + this.setNeedRemind(reader.getAttrAsBoolean("isNeedRemind", true)); + this.setOperateCount(reader.getAttrAsInt("operateCount", 0)); } @@ -109,7 +120,9 @@ public class AlphafineConfigManager implements XMLable { .attr("isContainDocument", this.isContainDocument()) .attr("isContainTemplate", this.isContainTemplate()) .attr("isContainPlugin", this.isContainPlugin()) - .attr("isContainFileContent", this.isContainFileContent()); + .attr("isContainFileContent", this.isContainFileContent()) + .attr("isNeedRemind", this.isNeedRemind()) + .attr("operateCount", this.getOperateCount()); writer.end(); } @@ -214,4 +227,20 @@ public class AlphafineConfigManager implements XMLable { public void setContainFileContent(boolean containFileContent) { isContainFileContent = containFileContent; } + + public boolean isNeedRemind() { + return isNeedRemind; + } + + public void setNeedRemind(boolean needRemind) { + isNeedRemind = needRemind; + } + + public int getOperateCount() { + return operateCount; + } + + public void setOperateCount(int operateCount) { + this.operateCount = operateCount; + } } diff --git a/designer_base/src/com/fr/design/actions/help/AlphaFine/RemindDialog.java b/designer_base/src/com/fr/design/actions/help/AlphaFine/RemindDialog.java new file mode 100644 index 0000000000..a2152d5a37 --- /dev/null +++ b/designer_base/src/com/fr/design/actions/help/AlphaFine/RemindDialog.java @@ -0,0 +1,52 @@ +package com.fr.design.actions.help.AlphaFine; + +import com.fr.design.DesignerEnvManager; +import com.fr.design.dialog.BasicDialog; +import com.fr.design.dialog.UIDialog; +import com.fr.design.utils.gui.GUICoreUtils; + +import java.awt.*; +import java.awt.event.*; + +/** + * Created by XiaXiang on 2017/5/26. + */ +public class RemindDialog extends UIDialog { + private RemindPane remindPane; + private static final int WIDTH = 600; + private static final int HEIGHT = 400; + public RemindDialog(Frame parent) { + super(parent); + setUndecorated(true); + setSize(WIDTH, HEIGHT); + initComponent(); + GUICoreUtils.centerWindow(this); + } + + private void initComponent() { + final AlphafineConfigManager manager = DesignerEnvManager.getEnvManager().getAlphafineConfigManager(); + remindPane = new RemindPane(manager); + remindPane.navigateButton.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + dispose(); + manager.setOperateCount(0); + } + }); + this.add(remindPane); + + } + + @Override + public void checkValid() throws Exception { + + } + + public RemindPane getRemindPane() { + return remindPane; + } + + public void setRemindPane(RemindPane remindPane) { + this.remindPane = remindPane; + } +} diff --git a/designer_base/src/com/fr/design/actions/help/AlphaFine/RemindPane.java b/designer_base/src/com/fr/design/actions/help/AlphaFine/RemindPane.java new file mode 100644 index 0000000000..5862b731fe --- /dev/null +++ b/designer_base/src/com/fr/design/actions/help/AlphaFine/RemindPane.java @@ -0,0 +1,129 @@ +package com.fr.design.actions.help.AlphaFine; + +import com.fr.design.gui.ibutton.UIButton; +import com.fr.design.gui.ilable.UILabel; +import com.fr.general.IOUtils; +import com.fr.general.Inter; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/** + * Created by XiaXiang on 2017/5/26. + */ +public class RemindPane extends JPanel { + public static final Font MEDIUM_FONT = new Font("Song_TypeFace", 0, 12); + public static final Font LARGE_FONT = new Font("Song_TypeFace", 0, 18); + private UIButton openButton; + private JPanel backgroundPane; + private UILabel backgroundLabel; + private UILabel checkLabel; + private Icon checkIcon = IOUtils.readIcon("/com/fr/design/mainframe/alphafine/images/check.png"); + private Icon unCheckIcon = IOUtils.readIcon("/com/fr/design/mainframe/alphafine/images/uncheck.png"); + private Icon closeIcon = IOUtils.readIcon("/com/fr/design/mainframe/alphafine/images/remind_close.png"); + private Icon labelIcon = IOUtils.readIcon("/com/fr/design/mainframe/alphafine/images/remind.png"); + private Icon openIcon = IOUtils.readIcon("com/fr/design/mainframe/alphafine/images/open.png"); + public JComponent navigateButton = new JComponent() { + protected void paintComponent(Graphics g) { + closeIcon.paintIcon(this, g, 0, 0); + } + }; + + public RemindPane(AlphafineConfigManager manager) { + this.setPreferredSize(new Dimension(600, 400)); + initUI(manager); + this.setLayout(getAbsoluteLayout()); + } + + private void initUI(final AlphafineConfigManager manager) { + openButton = new UIButton() { + @Override + public void paintComponent(Graphics g) { + g.setColor( Color.white ); + g.fillRect(0, 0, getSize().width, getSize().height); + super.paintComponent(g); + } + }; + openButton.setContentAreaFilled(false); + openButton.setForeground(new Color(0x3394F0)); + openButton.setIcon(openIcon); + openButton.setFont(LARGE_FONT); + openButton.set4ToolbarButton(); + openButton.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + + + } + }); + backgroundLabel = new UILabel(Inter.getLocText("FR-Designer-Alphafine_No_Remind")); + backgroundLabel.setFont(MEDIUM_FONT); + backgroundLabel.setForeground(Color.white); + checkLabel = new UILabel(); + checkLabel.setIcon(unCheckIcon); + checkLabel.addMouseListener(new MouseAdapter() { + private boolean isCheck = false; + + @Override + public void mouseClicked(MouseEvent e) { + if (isCheck) { + checkLabel.setIcon(unCheckIcon); + manager.setNeedRemind(true); + isCheck = false; + } else { + checkLabel.setIcon(checkIcon); + manager.setNeedRemind(false); + isCheck = true; + } + } + }); + backgroundPane = new JPanel(new BorderLayout()); + backgroundPane.add(new UILabel(labelIcon), BorderLayout.CENTER); + add(navigateButton, 0); + add(checkLabel, 1); + add(openButton, 2); + add(backgroundLabel, 3); + add(backgroundPane, 4); + } + + /** + * 控件排列用绝对布局 + * @return + */ + protected LayoutManager getAbsoluteLayout() { + return new LayoutManager() { + + @Override + public void removeLayoutComponent(Component comp) { + } + + @Override + public Dimension preferredLayoutSize(Container parent) { + return parent.getPreferredSize(); + } + + @Override + public Dimension minimumLayoutSize(Container parent) { + return null; + } + + @Override + public void layoutContainer(Container parent) { + int width = parent.getWidth(); + int height = parent.getHeight(); + navigateButton.setBounds((width - 30), 0, 30, 30); + openButton.setBounds(30, 300, 150, 40); + backgroundLabel.setBounds(95, 350, 100, 20); + checkLabel.setBounds(70, 350, 20, 20); + backgroundPane.setBounds(0, 0, width, height); + } + + @Override + public void addLayoutComponent(String name, Component comp) { + } + }; + } + +} diff --git a/designer_form/src/com/fr/aspectj/designerform/TemplateProcessTracker.aj b/designer_form/src/com/fr/aspectj/designerform/TemplateProcessTracker.aj index 1870793713..654e05f242 100644 --- a/designer_form/src/com/fr/aspectj/designerform/TemplateProcessTracker.aj +++ b/designer_form/src/com/fr/aspectj/designerform/TemplateProcessTracker.aj @@ -1,59 +1,59 @@ -package com.fr.aspectj.designerform; - -/** - * Created by plough on 2017/3/3. - */ -import com.fr.design.mainframe.templateinfo.TemplateInfoCollector; -import org.aspectj.lang.reflect.SourceLocation; - -import java.awt.event.ActionEvent; -import java.awt.event.MouseEvent; -import java.util.Date; - -public aspect TemplateProcessTracker { - //声明一个pointcut,匹配你需要的方法 - pointcut onMouseClicked(MouseEvent e) : - execution(* mouseClicked(MouseEvent)) && args(e); - pointcut onMousePressed(MouseEvent e) : - execution(* mousePressed(MouseEvent)) && args(e); - pointcut onMouseReleased(MouseEvent e) : - execution(* mouseReleased(MouseEvent)) && args(e); - pointcut onActionPerformed(ActionEvent e) : - execution(* actionPerformed(ActionEvent)) && args(e); - pointcut onSetValueAt(Object v, int r, int c) : - execution(* setValueAt(java.lang.Object, int, int)) && args(v, r, c); - - //before表示之前的意思 - //这整个表示在MouseAdapter的public void mouseXXX(MouseEvent)方法调用之前,你想要执行的代码 - before(MouseEvent e) : onMouseClicked(e) || onMousePressed(e) || onMouseReleased(e) { - SourceLocation sl = thisJoinPoint.getSourceLocation();//切面对应的代码位置 - - //String log = String.format("%s:\n%s\n%s\n%s\n\n", new Date(), sl, e, e.getSource()); - String log = ""; - //TemplateInfoCollector.appendProcess(log); - } - //同上 - before(ActionEvent e) : onActionPerformed(e) { - SourceLocation sl = thisJoinPoint.getSourceLocation(); - // !within(LogHandlerBar) 没用, 手动过滤 - if (e.getSource().toString().contains("javax.swing.Timer")) { - return; - } - - //String log = String.format("%s:\n%s\n%s\n%s\n\n", new Date(), sl, e, e.getSource()); - String log = ""; - //TemplateInfoCollector.appendProcess(log); - - } - //同上 - before(Object v, int r, int c) : onSetValueAt(v, r, c) { - SourceLocation sl = thisJoinPoint.getSourceLocation(); - - //String log = String.format("%s:\n%s\nset value: %s at (%d, %d)\n\n", new Date(), sl, v, r, c); - String log = ""; - //TemplateInfoCollector.appendProcess(log); - - } - - -} +//package com.fr.aspectj.designerform; +// +///** +// * Created by plough on 2017/3/3. +// */ +//import com.fr.design.mainframe.templateinfo.TemplateInfoCollector; +//import org.aspectj.lang.reflect.SourceLocation; +// +//import java.awt.event.ActionEvent; +//import java.awt.event.MouseEvent; +//import java.util.Date; +// +//public aspect TemplateProcessTracker { +// //声明一个pointcut,匹配你需要的方法 +// pointcut onMouseClicked(MouseEvent e) : +// execution(* mouseClicked(MouseEvent)) && args(e); +// pointcut onMousePressed(MouseEvent e) : +// execution(* mousePressed(MouseEvent)) && args(e); +// pointcut onMouseReleased(MouseEvent e) : +// execution(* mouseReleased(MouseEvent)) && args(e); +// pointcut onActionPerformed(ActionEvent e) : +// execution(* actionPerformed(ActionEvent)) && args(e); +// pointcut onSetValueAt(Object v, int r, int c) : +// execution(* setValueAt(java.lang.Object, int, int)) && args(v, r, c); +// +// //before表示之前的意思 +// //这整个表示在MouseAdapter的public void mouseXXX(MouseEvent)方法调用之前,你想要执行的代码 +// before(MouseEvent e) : onMouseClicked(e) || onMousePressed(e) || onMouseReleased(e) { +// SourceLocation sl = thisJoinPoint.getSourceLocation();//切面对应的代码位置 +// +// //String log = String.format("%s:\n%s\n%s\n%s\n\n", new Date(), sl, e, e.getSource()); +// String log = ""; +// //TemplateInfoCollector.appendProcess(log); +// } +// //同上 +// before(ActionEvent e) : onActionPerformed(e) { +// SourceLocation sl = thisJoinPoint.getSourceLocation(); +// // !within(LogHandlerBar) 没用, 手动过滤 +// if (e.getSource().toString().contains("javax.swing.Timer")) { +// return; +// } +// +// //String log = String.format("%s:\n%s\n%s\n%s\n\n", new Date(), sl, e, e.getSource()); +// String log = ""; +// //TemplateInfoCollector.appendProcess(log); +// +// } +// //同上 +// before(Object v, int r, int c) : onSetValueAt(v, r, c) { +// SourceLocation sl = thisJoinPoint.getSourceLocation(); +// +// //String log = String.format("%s:\n%s\nset value: %s at (%d, %d)\n\n", new Date(), sl, v, r, c); +// String log = ""; +// //TemplateInfoCollector.appendProcess(log); +// +// } +// +// +//} From f7728758c80a7897dfa8e15f88ab94b9d0dcc260 Mon Sep 17 00:00:00 2001 From: XiaXiang Date: Sat, 27 May 2017 15:02:48 +0800 Subject: [PATCH 34/41] bug fix --- .../designer/TemplateProcessTracker.aj | 2 +- .../designerchart/TemplateProcessTracker.aj | 2 +- .../designerform/TemplateProcessTracker.aj | 118 +++++++++--------- 3 files changed, 61 insertions(+), 61 deletions(-) diff --git a/designer/src/com/fr/aspectj/designer/TemplateProcessTracker.aj b/designer/src/com/fr/aspectj/designer/TemplateProcessTracker.aj index d0f3108295..8e4eeb7164 100644 --- a/designer/src/com/fr/aspectj/designer/TemplateProcessTracker.aj +++ b/designer/src/com/fr/aspectj/designer/TemplateProcessTracker.aj @@ -41,7 +41,7 @@ public aspect TemplateProcessTracker { before(ActionEvent e) : onActionPerformed(e) { SourceLocation sl = thisJoinPoint.getSourceLocation(); // !within(LogHandlerBar) 没用, 手动过滤 - if (e.getSource().toString().contains("javax.swing.Timer")) { + if (e != null && e.getSource().toString().contains("javax.swing.Timer")) { return; } diff --git a/designer_chart/src/com/fr/aspectj/designerchart/TemplateProcessTracker.aj b/designer_chart/src/com/fr/aspectj/designerchart/TemplateProcessTracker.aj index 60038d4a39..89ed91033f 100644 --- a/designer_chart/src/com/fr/aspectj/designerchart/TemplateProcessTracker.aj +++ b/designer_chart/src/com/fr/aspectj/designerchart/TemplateProcessTracker.aj @@ -38,7 +38,7 @@ public aspect TemplateProcessTracker { before(ActionEvent e) : onActionPerformed(e) { SourceLocation sl = thisJoinPoint.getSourceLocation(); // !within(LogHandlerBar) 没用, 手动过滤 - if (e.getSource().toString().contains("javax.swing.Timer")) { + if (e != null && e.getSource().toString().contains("javax.swing.Timer")) { return; } diff --git a/designer_form/src/com/fr/aspectj/designerform/TemplateProcessTracker.aj b/designer_form/src/com/fr/aspectj/designerform/TemplateProcessTracker.aj index 654e05f242..3be1a77fa7 100644 --- a/designer_form/src/com/fr/aspectj/designerform/TemplateProcessTracker.aj +++ b/designer_form/src/com/fr/aspectj/designerform/TemplateProcessTracker.aj @@ -1,59 +1,59 @@ -//package com.fr.aspectj.designerform; -// -///** -// * Created by plough on 2017/3/3. -// */ -//import com.fr.design.mainframe.templateinfo.TemplateInfoCollector; -//import org.aspectj.lang.reflect.SourceLocation; -// -//import java.awt.event.ActionEvent; -//import java.awt.event.MouseEvent; -//import java.util.Date; -// -//public aspect TemplateProcessTracker { -// //声明一个pointcut,匹配你需要的方法 -// pointcut onMouseClicked(MouseEvent e) : -// execution(* mouseClicked(MouseEvent)) && args(e); -// pointcut onMousePressed(MouseEvent e) : -// execution(* mousePressed(MouseEvent)) && args(e); -// pointcut onMouseReleased(MouseEvent e) : -// execution(* mouseReleased(MouseEvent)) && args(e); -// pointcut onActionPerformed(ActionEvent e) : -// execution(* actionPerformed(ActionEvent)) && args(e); -// pointcut onSetValueAt(Object v, int r, int c) : -// execution(* setValueAt(java.lang.Object, int, int)) && args(v, r, c); -// -// //before表示之前的意思 -// //这整个表示在MouseAdapter的public void mouseXXX(MouseEvent)方法调用之前,你想要执行的代码 -// before(MouseEvent e) : onMouseClicked(e) || onMousePressed(e) || onMouseReleased(e) { -// SourceLocation sl = thisJoinPoint.getSourceLocation();//切面对应的代码位置 -// -// //String log = String.format("%s:\n%s\n%s\n%s\n\n", new Date(), sl, e, e.getSource()); -// String log = ""; -// //TemplateInfoCollector.appendProcess(log); -// } -// //同上 -// before(ActionEvent e) : onActionPerformed(e) { -// SourceLocation sl = thisJoinPoint.getSourceLocation(); -// // !within(LogHandlerBar) 没用, 手动过滤 -// if (e.getSource().toString().contains("javax.swing.Timer")) { -// return; -// } -// -// //String log = String.format("%s:\n%s\n%s\n%s\n\n", new Date(), sl, e, e.getSource()); -// String log = ""; -// //TemplateInfoCollector.appendProcess(log); -// -// } -// //同上 -// before(Object v, int r, int c) : onSetValueAt(v, r, c) { -// SourceLocation sl = thisJoinPoint.getSourceLocation(); -// -// //String log = String.format("%s:\n%s\nset value: %s at (%d, %d)\n\n", new Date(), sl, v, r, c); -// String log = ""; -// //TemplateInfoCollector.appendProcess(log); -// -// } -// -// -//} +package com.fr.aspectj.designerform; + +/** + * Created by plough on 2017/3/3. + */ +import com.fr.design.mainframe.templateinfo.TemplateInfoCollector; +import org.aspectj.lang.reflect.SourceLocation; + +import java.awt.event.ActionEvent; +import java.awt.event.MouseEvent; +import java.util.Date; + +public aspect TemplateProcessTracker { + //声明一个pointcut,匹配你需要的方法 + pointcut onMouseClicked(MouseEvent e) : + execution(* mouseClicked(MouseEvent)) && args(e); + pointcut onMousePressed(MouseEvent e) : + execution(* mousePressed(MouseEvent)) && args(e); + pointcut onMouseReleased(MouseEvent e) : + execution(* mouseReleased(MouseEvent)) && args(e); + pointcut onActionPerformed(ActionEvent e) : + execution(* actionPerformed(ActionEvent)) && args(e); + pointcut onSetValueAt(Object v, int r, int c) : + execution(* setValueAt(java.lang.Object, int, int)) && args(v, r, c); + + //before表示之前的意思 + //这整个表示在MouseAdapter的public void mouseXXX(MouseEvent)方法调用之前,你想要执行的代码 + before(MouseEvent e) : onMouseClicked(e) || onMousePressed(e) || onMouseReleased(e) { + SourceLocation sl = thisJoinPoint.getSourceLocation();//切面对应的代码位置 + + //String log = String.format("%s:\n%s\n%s\n%s\n\n", new Date(), sl, e, e.getSource()); + String log = ""; + //TemplateInfoCollector.appendProcess(log); + } + //同上 + before(ActionEvent e) : onActionPerformed(e) { + SourceLocation sl = thisJoinPoint.getSourceLocation(); + // !within(LogHandlerBar) 没用, 手动过滤 + if (e != null && e.getSource().toString().contains("javax.swing.Timer")) { + return; + } + + //String log = String.format("%s:\n%s\n%s\n%s\n\n", new Date(), sl, e, e.getSource()); + String log = ""; + //TemplateInfoCollector.appendProcess(log); + + } + //同上 + before(Object v, int r, int c) : onSetValueAt(v, r, c) { + SourceLocation sl = thisJoinPoint.getSourceLocation(); + + //String log = String.format("%s:\n%s\nset value: %s at (%d, %d)\n\n", new Date(), sl, v, r, c); + String log = ""; + //TemplateInfoCollector.appendProcess(log); + + } + + +} From fde3497b2199b3a926164c5c5f271bfa95435e62 Mon Sep 17 00:00:00 2001 From: XiaXiang Date: Sat, 27 May 2017 15:49:17 +0800 Subject: [PATCH 35/41] bug fix --- .../com/fr/design/actions/help/AboutPane.java | 2 +- .../actions/help/AlphaFine/RemindDialog.java | 9 +---- .../actions/help/AlphaFine/RemindPane.java | 38 +++++++++---------- .../com/fr/design/locale/designer.properties | 3 +- .../design/locale/designer_en_US.properties | 3 +- .../design/locale/designer_zh_CN.properties | 3 +- .../design/locale/designer_zh_TW.properties | 3 +- .../loghandler/DesignerLogHandler.java | 2 +- 8 files changed, 30 insertions(+), 33 deletions(-) diff --git a/designer_base/src/com/fr/design/actions/help/AboutPane.java b/designer_base/src/com/fr/design/actions/help/AboutPane.java index 1155f4e921..9c8953597d 100644 --- a/designer_base/src/com/fr/design/actions/help/AboutPane.java +++ b/designer_base/src/com/fr/design/actions/help/AboutPane.java @@ -47,7 +47,7 @@ public class AboutPane extends JPanel { BoxCenterAlignmentCopyablePane buildCopyPane = new BoxCenterAlignmentCopyablePane( getBuildTitle(), - GeneralUtils.readFullBuildNO(), + GeneralUtils.readBuildNO(), new String[]{ Inter.getLocText("FR-Designer-Basic_Copy_Build_NO"), Inter.getLocText("FR-Designer-Basic_Copy_Build_NO_OK") diff --git a/designer_base/src/com/fr/design/actions/help/AlphaFine/RemindDialog.java b/designer_base/src/com/fr/design/actions/help/AlphaFine/RemindDialog.java index a2152d5a37..11486f1138 100644 --- a/designer_base/src/com/fr/design/actions/help/AlphaFine/RemindDialog.java +++ b/designer_base/src/com/fr/design/actions/help/AlphaFine/RemindDialog.java @@ -25,14 +25,7 @@ public class RemindDialog extends UIDialog { private void initComponent() { final AlphafineConfigManager manager = DesignerEnvManager.getEnvManager().getAlphafineConfigManager(); - remindPane = new RemindPane(manager); - remindPane.navigateButton.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - dispose(); - manager.setOperateCount(0); - } - }); + remindPane = new RemindPane(manager, this); this.add(remindPane); } diff --git a/designer_base/src/com/fr/design/actions/help/AlphaFine/RemindPane.java b/designer_base/src/com/fr/design/actions/help/AlphaFine/RemindPane.java index 5862b731fe..ac93bad8e2 100644 --- a/designer_base/src/com/fr/design/actions/help/AlphaFine/RemindPane.java +++ b/designer_base/src/com/fr/design/actions/help/AlphaFine/RemindPane.java @@ -1,5 +1,6 @@ package com.fr.design.actions.help.AlphaFine; +import com.fr.design.dialog.UIDialog; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.gui.ilable.UILabel; import com.fr.general.IOUtils; @@ -25,37 +26,28 @@ public class RemindPane extends JPanel { private Icon closeIcon = IOUtils.readIcon("/com/fr/design/mainframe/alphafine/images/remind_close.png"); private Icon labelIcon = IOUtils.readIcon("/com/fr/design/mainframe/alphafine/images/remind.png"); private Icon openIcon = IOUtils.readIcon("com/fr/design/mainframe/alphafine/images/open.png"); - public JComponent navigateButton = new JComponent() { + public JComponent closeButton = new JComponent() { protected void paintComponent(Graphics g) { closeIcon.paintIcon(this, g, 0, 0); } }; - public RemindPane(AlphafineConfigManager manager) { + public RemindPane(AlphafineConfigManager manager, UIDialog remindDialog) { this.setPreferredSize(new Dimension(600, 400)); - initUI(manager); + initUI(manager, remindDialog); this.setLayout(getAbsoluteLayout()); } - private void initUI(final AlphafineConfigManager manager) { - openButton = new UIButton() { - @Override - public void paintComponent(Graphics g) { - g.setColor( Color.white ); - g.fillRect(0, 0, getSize().width, getSize().height); - super.paintComponent(g); - } - }; - openButton.setContentAreaFilled(false); - openButton.setForeground(new Color(0x3394F0)); + private void initUI(final AlphafineConfigManager manager, final UIDialog dialog) { + + openButton = new UIButton(); openButton.setIcon(openIcon); - openButton.setFont(LARGE_FONT); openButton.set4ToolbarButton(); openButton.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { - - + //manager.setOperateCount(0); + dialog.dispose(); } }); backgroundLabel = new UILabel(Inter.getLocText("FR-Designer-Alphafine_No_Remind")); @@ -81,7 +73,15 @@ public class RemindPane extends JPanel { }); backgroundPane = new JPanel(new BorderLayout()); backgroundPane.add(new UILabel(labelIcon), BorderLayout.CENTER); - add(navigateButton, 0); + closeButton.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + //manager.setOperateCount(0); + dialog.dispose(); + + } + }); + add(closeButton, 0); add(checkLabel, 1); add(openButton, 2); add(backgroundLabel, 3); @@ -113,7 +113,7 @@ public class RemindPane extends JPanel { public void layoutContainer(Container parent) { int width = parent.getWidth(); int height = parent.getHeight(); - navigateButton.setBounds((width - 30), 0, 30, 30); + closeButton.setBounds((width - 30), 0, 30, 30); openButton.setBounds(30, 300, 150, 40); backgroundLabel.setBounds(95, 350, 100, 20); checkLabel.setBounds(70, 350, 20, 20); diff --git a/designer_base/src/com/fr/design/locale/designer.properties b/designer_base/src/com/fr/design/locale/designer.properties index 9d6332e6a8..e632fafd2c 100644 --- a/designer_base/src/com/fr/design/locale/designer.properties +++ b/designer_base/src/com/fr/design/locale/designer.properties @@ -2005,4 +2005,5 @@ FR-Designer_Templates_Content=Templates Contents FR-Designer_AlphaFine_ShowAll=show all FR-Designer_AlphaFine_Latest=Latest FR-Designer_AlphaFine_ShowLess=show less -FR-Designer_Alphafine=AlphaFine \ No newline at end of file +FR-Designer_Alphafine=AlphaFine +FR-Designer-Alphafine_No_Remind= \ No newline at end of file diff --git a/designer_base/src/com/fr/design/locale/designer_en_US.properties b/designer_base/src/com/fr/design/locale/designer_en_US.properties index e8f9e376c5..774beedf58 100644 --- a/designer_base/src/com/fr/design/locale/designer_en_US.properties +++ b/designer_base/src/com/fr/design/locale/designer_en_US.properties @@ -2003,4 +2003,5 @@ FR-Designer_Templates_Content=Template'Contents FR-Designer_AlphaFine_ShowAll=show all FR-Designer_AlphaFine_Latest=Recent FR-Designer_AlphaFine_ShowLess=show less -FR-Designer_Alphafine=AlphaFine \ No newline at end of file +FR-Designer_Alphafine=AlphaFine +FR-Designer-Alphafine_No_Remind=don't remind \ No newline at end of file diff --git a/designer_base/src/com/fr/design/locale/designer_zh_CN.properties b/designer_base/src/com/fr/design/locale/designer_zh_CN.properties index 1fe8ac3c1e..008f2df8d5 100644 --- a/designer_base/src/com/fr/design/locale/designer_zh_CN.properties +++ b/designer_base/src/com/fr/design/locale/designer_zh_CN.properties @@ -2001,4 +2001,5 @@ FR-Designer_AlphaFine_ShowAll=\u663E\u793A\u5168\u90E8 FR-Designer_AlphaFine_Conclude=\u731C\u60A8\u9700\u8981 FR-Designer_AlphaFine_Latest=\u672C\u5730\u5E38\u7528 FR-Designer_AlphaFine_ShowLess=\u6536\u8D77 -FR-Designer_Alphafine=AlphaFine\u667A\u80FD\u641C\u7D22 \ No newline at end of file +FR-Designer_Alphafine=AlphaFine\u667A\u80FD\u641C\u7D22 +FR-Designer-Alphafine_No_Remind=\u4E0D\u518D\u63D0\u793A \ No newline at end of file diff --git a/designer_base/src/com/fr/design/locale/designer_zh_TW.properties b/designer_base/src/com/fr/design/locale/designer_zh_TW.properties index 08a75d41e2..4a8a86d71d 100644 --- a/designer_base/src/com/fr/design/locale/designer_zh_TW.properties +++ b/designer_base/src/com/fr/design/locale/designer_zh_TW.properties @@ -1999,4 +1999,5 @@ FR-Designer_Templates_Content=\u6A21\u677F\u5167\u5BB9 FR-Designer_AlphaFine_Latest=\u6700\u8FD1\u5E38\u7528 FR-Designer_AlphaFine_ShowLess=\u6536\u8D77 FR-Designer_Alphafine=AlphaFine\u667A\u80FD\u641C\u7D22 -FR-Designer_AlphaFine_ShowAll=\u986F\u793A\u5168\u90E8 \ No newline at end of file +FR-Designer_AlphaFine_ShowAll=\u986F\u793A\u5168\u90E8 +FR-Designer-Alphafine_No_Remind=\u4E0D\u518D\u63D0\u793A \ No newline at end of file diff --git a/designer_base/src/com/fr/design/mainframe/loghandler/DesignerLogHandler.java b/designer_base/src/com/fr/design/mainframe/loghandler/DesignerLogHandler.java index 0bf286e51b..e45ade484a 100644 --- a/designer_base/src/com/fr/design/mainframe/loghandler/DesignerLogHandler.java +++ b/designer_base/src/com/fr/design/mainframe/loghandler/DesignerLogHandler.java @@ -187,7 +187,7 @@ public class DesignerLogHandler { } private JTextPane initLogJTextArea() { - JTextPane resultPane = new JTextPane(); + final JTextPane resultPane = new JTextPane(); InputMap inputMap = resultPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, DEFAULT_MODIFIER), DefaultEditorKit.copyAction); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, DEFAULT_MODIFIER), DefaultEditorKit.selectAllAction); From 4964155c0fe691b20fce9e7f0bdc111c4e411011 Mon Sep 17 00:00:00 2001 From: XiaXiang Date: Sat, 27 May 2017 16:47:24 +0800 Subject: [PATCH 36/41] =?UTF-8?q?alphafine=20=E5=B9=BF=E5=91=8A=E5=BC=B9?= =?UTF-8?q?=E6=A1=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../alphafine/component/AlphaFineDialog.java | 1 + .../alphafine/component/AlphaFinePane.java | 8 +++++ .../aspectj/designerbase/AlphaFineReminder.aj | 4 +-- .../src/com/fr/design/DesignerEnvManager.java | 2 +- .../AlphafineAction.java | 3 +- .../AlphafineConfigManager.java | 2 +- .../AlphafineConfigPane.java | 2 +- .../help/alphafine/AlphafineContext.java | 29 +++++++++++++++++++ .../help/alphafine/AlphafineListener.java | 8 +++++ .../RemindDialog.java | 4 +-- .../{AlphaFine => alphafine}/RemindPane.java | 10 ++++--- .../mainframe/toolbar/ToolBarMenuDock.java | 2 +- 12 files changed, 60 insertions(+), 15 deletions(-) rename designer_base/src/com/fr/design/actions/help/{AlphaFine => alphafine}/AlphafineAction.java (96%) rename designer_base/src/com/fr/design/actions/help/{AlphaFine => alphafine}/AlphafineConfigManager.java (99%) rename designer_base/src/com/fr/design/actions/help/{AlphaFine => alphafine}/AlphafineConfigPane.java (99%) create mode 100644 designer_base/src/com/fr/design/actions/help/alphafine/AlphafineContext.java create mode 100644 designer_base/src/com/fr/design/actions/help/alphafine/AlphafineListener.java rename designer_base/src/com/fr/design/actions/help/{AlphaFine => alphafine}/RemindDialog.java (90%) rename designer_base/src/com/fr/design/actions/help/{AlphaFine => alphafine}/RemindPane.java (92%) diff --git a/designer/src/com/fr/design/mainframe/alphafine/component/AlphaFineDialog.java b/designer/src/com/fr/design/mainframe/alphafine/component/AlphaFineDialog.java index 2c7519ac8f..c7ccf0f772 100644 --- a/designer/src/com/fr/design/mainframe/alphafine/component/AlphaFineDialog.java +++ b/designer/src/com/fr/design/mainframe/alphafine/component/AlphaFineDialog.java @@ -487,6 +487,7 @@ public class AlphaFineDialog extends UIDialog { Rectangle paneRectangle = new Rectangle(AlphaFinePane.createAlphaFinePane().getLocationOnScreen(), AlphaFinePane.createAlphaFinePane().getSize()); if (!dialogRectangle.contains(p) && !paneRectangle.contains(p)) { AlphaFineDialog.this.dispose(); + System.out.print(p + "\n"); } } } diff --git a/designer/src/com/fr/design/mainframe/alphafine/component/AlphaFinePane.java b/designer/src/com/fr/design/mainframe/alphafine/component/AlphaFinePane.java index f0d5d7ca65..f818fb587c 100644 --- a/designer/src/com/fr/design/mainframe/alphafine/component/AlphaFinePane.java +++ b/designer/src/com/fr/design/mainframe/alphafine/component/AlphaFinePane.java @@ -2,6 +2,8 @@ package com.fr.design.mainframe.alphafine.component; import com.fr.base.BaseUtils; import com.fr.design.DesignerEnvManager; +import com.fr.design.actions.help.alphafine.AlphafineContext; +import com.fr.design.actions.help.alphafine.AlphafineListener; import com.fr.design.dialog.BasicPane; import com.fr.design.gui.ibutton.UIButton; import com.fr.design.mainframe.alphafine.AlphaFineHelper; @@ -40,6 +42,12 @@ public class AlphaFinePane extends BasicPane { AlphaFineHelper.showAlphaFineDialog(); } }); + AlphafineContext.addAlphafineContextListener(new AlphafineListener() { + @Override + public void showDialog() { + AlphaFineHelper.showAlphaFineDialog(); + } + }); } @Override diff --git a/designer_base/src/com/fr/aspectj/designerbase/AlphaFineReminder.aj b/designer_base/src/com/fr/aspectj/designerbase/AlphaFineReminder.aj index fea7820778..48701f7640 100644 --- a/designer_base/src/com/fr/aspectj/designerbase/AlphaFineReminder.aj +++ b/designer_base/src/com/fr/aspectj/designerbase/AlphaFineReminder.aj @@ -1,8 +1,8 @@ package com.fr.aspectj.designerbase; import com.fr.design.DesignerEnvManager; -import com.fr.design.actions.help.AlphaFine.AlphafineConfigManager; -import com.fr.design.actions.help.AlphaFine.RemindDialog; +import com.fr.design.actions.help.alphafine.AlphafineConfigManager; +import com.fr.design.actions.help.alphafine.RemindDialog; import com.fr.design.mainframe.DesignerContext; import java.awt.event.ActionEvent; diff --git a/designer_base/src/com/fr/design/DesignerEnvManager.java b/designer_base/src/com/fr/design/DesignerEnvManager.java index e7b4f7dfcc..75b4749d83 100644 --- a/designer_base/src/com/fr/design/DesignerEnvManager.java +++ b/designer_base/src/com/fr/design/DesignerEnvManager.java @@ -5,7 +5,7 @@ package com.fr.design; import com.fr.base.*; import com.fr.dav.LocalEnv; -import com.fr.design.actions.help.AlphaFine.AlphafineConfigManager; +import com.fr.design.actions.help.alphafine.AlphafineConfigManager; import com.fr.design.constants.UIConstants; import com.fr.env.RemoteEnv; import com.fr.env.SignIn; diff --git a/designer_base/src/com/fr/design/actions/help/AlphaFine/AlphafineAction.java b/designer_base/src/com/fr/design/actions/help/alphafine/AlphafineAction.java similarity index 96% rename from designer_base/src/com/fr/design/actions/help/AlphaFine/AlphafineAction.java rename to designer_base/src/com/fr/design/actions/help/alphafine/AlphafineAction.java index 7cb1ec2396..fdd6e060e2 100644 --- a/designer_base/src/com/fr/design/actions/help/AlphaFine/AlphafineAction.java +++ b/designer_base/src/com/fr/design/actions/help/alphafine/AlphafineAction.java @@ -1,4 +1,4 @@ -package com.fr.design.actions.help.AlphaFine; +package com.fr.design.actions.help.alphafine; import com.fr.base.BaseUtils; import com.fr.design.DesignerEnvManager; @@ -9,7 +9,6 @@ import com.fr.design.dialog.DialogActionListener; import com.fr.design.mainframe.DesignerContext; import com.fr.design.mainframe.DesignerFrame; import com.fr.design.menu.MenuKeySet; -import com.fr.general.Inter; import javax.swing.*; import java.awt.event.ActionEvent; diff --git a/designer_base/src/com/fr/design/actions/help/AlphaFine/AlphafineConfigManager.java b/designer_base/src/com/fr/design/actions/help/alphafine/AlphafineConfigManager.java similarity index 99% rename from designer_base/src/com/fr/design/actions/help/AlphaFine/AlphafineConfigManager.java rename to designer_base/src/com/fr/design/actions/help/alphafine/AlphafineConfigManager.java index 3aa6f44bdb..eba6de79cd 100644 --- a/designer_base/src/com/fr/design/actions/help/AlphaFine/AlphafineConfigManager.java +++ b/designer_base/src/com/fr/design/actions/help/alphafine/AlphafineConfigManager.java @@ -1,4 +1,4 @@ -package com.fr.design.actions.help.AlphaFine; +package com.fr.design.actions.help.alphafine; import com.fr.stable.OperatingSystem; import com.fr.stable.StringUtils; diff --git a/designer_base/src/com/fr/design/actions/help/AlphaFine/AlphafineConfigPane.java b/designer_base/src/com/fr/design/actions/help/alphafine/AlphafineConfigPane.java similarity index 99% rename from designer_base/src/com/fr/design/actions/help/AlphaFine/AlphafineConfigPane.java rename to designer_base/src/com/fr/design/actions/help/alphafine/AlphafineConfigPane.java index 5d4d75275c..d982cbeece 100644 --- a/designer_base/src/com/fr/design/actions/help/AlphaFine/AlphafineConfigPane.java +++ b/designer_base/src/com/fr/design/actions/help/alphafine/AlphafineConfigPane.java @@ -1,4 +1,4 @@ -package com.fr.design.actions.help.AlphaFine; +package com.fr.design.actions.help.alphafine; import com.fr.design.DesignerEnvManager; import com.fr.design.dialog.BasicPane; diff --git a/designer_base/src/com/fr/design/actions/help/alphafine/AlphafineContext.java b/designer_base/src/com/fr/design/actions/help/alphafine/AlphafineContext.java new file mode 100644 index 0000000000..429f299d6c --- /dev/null +++ b/designer_base/src/com/fr/design/actions/help/alphafine/AlphafineContext.java @@ -0,0 +1,29 @@ +package com.fr.design.actions.help.alphafine; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by XiaXiang on 2017/5/27. + */ +public class AlphafineContext { + private static List fireLoginContextListener = new ArrayList(); + + /** + * 触发AlphaFine弹窗 + */ + public static void fireAlphaFineContextListener() { + for (AlphafineListener l : fireLoginContextListener) { + l.showDialog(); + } + } + + /** + * 添加一个弹出AlphaFine的监听事件 + * + * @param l AlphaFine框弹出监听事件 + */ + public static void addAlphafineContextListener(AlphafineListener l) { + fireLoginContextListener.add(l); + } +} diff --git a/designer_base/src/com/fr/design/actions/help/alphafine/AlphafineListener.java b/designer_base/src/com/fr/design/actions/help/alphafine/AlphafineListener.java new file mode 100644 index 0000000000..01c7905d61 --- /dev/null +++ b/designer_base/src/com/fr/design/actions/help/alphafine/AlphafineListener.java @@ -0,0 +1,8 @@ +package com.fr.design.actions.help.alphafine; + +/** + * Created by XiaXiang on 2017/5/27. + */ +public interface AlphafineListener { + void showDialog(); +} diff --git a/designer_base/src/com/fr/design/actions/help/AlphaFine/RemindDialog.java b/designer_base/src/com/fr/design/actions/help/alphafine/RemindDialog.java similarity index 90% rename from designer_base/src/com/fr/design/actions/help/AlphaFine/RemindDialog.java rename to designer_base/src/com/fr/design/actions/help/alphafine/RemindDialog.java index 11486f1138..9ae6f864a4 100644 --- a/designer_base/src/com/fr/design/actions/help/AlphaFine/RemindDialog.java +++ b/designer_base/src/com/fr/design/actions/help/alphafine/RemindDialog.java @@ -1,12 +1,10 @@ -package com.fr.design.actions.help.AlphaFine; +package com.fr.design.actions.help.alphafine; import com.fr.design.DesignerEnvManager; -import com.fr.design.dialog.BasicDialog; import com.fr.design.dialog.UIDialog; import com.fr.design.utils.gui.GUICoreUtils; import java.awt.*; -import java.awt.event.*; /** * Created by XiaXiang on 2017/5/26. diff --git a/designer_base/src/com/fr/design/actions/help/AlphaFine/RemindPane.java b/designer_base/src/com/fr/design/actions/help/alphafine/RemindPane.java similarity index 92% rename from designer_base/src/com/fr/design/actions/help/AlphaFine/RemindPane.java rename to designer_base/src/com/fr/design/actions/help/alphafine/RemindPane.java index ac93bad8e2..17cb6e456c 100644 --- a/designer_base/src/com/fr/design/actions/help/AlphaFine/RemindPane.java +++ b/designer_base/src/com/fr/design/actions/help/alphafine/RemindPane.java @@ -1,4 +1,4 @@ -package com.fr.design.actions.help.AlphaFine; +package com.fr.design.actions.help.alphafine; import com.fr.design.dialog.UIDialog; import com.fr.design.gui.ibutton.UIButton; @@ -45,9 +45,11 @@ public class RemindPane extends JPanel { openButton.set4ToolbarButton(); openButton.addMouseListener(new MouseAdapter() { @Override - public void mouseClicked(MouseEvent e) { + public void mousePressed(MouseEvent e) { + System.out.print(e.getLocationOnScreen() + "\n"); //manager.setOperateCount(0); dialog.dispose(); + AlphafineContext.fireAlphaFineContextListener(); } }); backgroundLabel = new UILabel(Inter.getLocText("FR-Designer-Alphafine_No_Remind")); @@ -59,7 +61,7 @@ public class RemindPane extends JPanel { private boolean isCheck = false; @Override - public void mouseClicked(MouseEvent e) { + public void mousePressed(MouseEvent e) { if (isCheck) { checkLabel.setIcon(unCheckIcon); manager.setNeedRemind(true); @@ -75,7 +77,7 @@ public class RemindPane extends JPanel { backgroundPane.add(new UILabel(labelIcon), BorderLayout.CENTER); closeButton.addMouseListener(new MouseAdapter() { @Override - public void mouseClicked(MouseEvent e) { + public void mousePressed(MouseEvent e) { //manager.setOperateCount(0); dialog.dispose(); diff --git a/designer_base/src/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java b/designer_base/src/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java index ff49aa7b07..f80e20331c 100644 --- a/designer_base/src/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java +++ b/designer_base/src/com/fr/design/mainframe/toolbar/ToolBarMenuDock.java @@ -11,7 +11,7 @@ import com.fr.design.actions.UpdateAction; import com.fr.design.actions.community.*; import com.fr.design.actions.file.*; import com.fr.design.actions.help.AboutAction; -import com.fr.design.actions.help.AlphaFine.AlphafineAction; +import com.fr.design.actions.help.alphafine.AlphafineAction; import com.fr.design.actions.help.TutorialAction; import com.fr.design.actions.help.WebDemoAction; import com.fr.design.actions.server.*; From d5d7349d1b2a23b22fcab179f1cffd66131660a2 Mon Sep 17 00:00:00 2001 From: XiaXiang Date: Sat, 27 May 2017 18:23:15 +0800 Subject: [PATCH 37/41] =?UTF-8?q?alphafine=20=E5=B9=BF=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mainframe/alphafine/AlphaFineHelper.java | 7 +++++-- .../alphafine/component/AlphaFineDialog.java | 17 +++++++++++++---- .../alphafine/component/AlphaFinePane.java | 4 ++-- .../actions/help/alphafine/RemindPane.java | 3 +-- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/designer/src/com/fr/design/mainframe/alphafine/AlphaFineHelper.java b/designer/src/com/fr/design/mainframe/alphafine/AlphaFineHelper.java index b6c482ff7d..d5901f8f45 100644 --- a/designer/src/com/fr/design/mainframe/alphafine/AlphaFineHelper.java +++ b/designer/src/com/fr/design/mainframe/alphafine/AlphaFineHelper.java @@ -8,12 +8,15 @@ import com.fr.stable.StringUtils; * Created by XiaXiang on 2017/5/8. */ public class AlphaFineHelper { + private static AlphaFineDialog dialog; /** * 弹出alphafine搜索面板 */ - public static void showAlphaFineDialog() { - AlphaFineDialog dialog = new AlphaFineDialog(DesignerContext.getDesignerFrame()); + public static void showAlphaFineDialog(boolean forceOpen) { + if (dialog == null) { + dialog = new AlphaFineDialog(DesignerContext.getDesignerFrame(), forceOpen); + } dialog.setVisible(true); } diff --git a/designer/src/com/fr/design/mainframe/alphafine/component/AlphaFineDialog.java b/designer/src/com/fr/design/mainframe/alphafine/component/AlphaFineDialog.java index c7ccf0f772..7b9974b795 100644 --- a/designer/src/com/fr/design/mainframe/alphafine/component/AlphaFineDialog.java +++ b/designer/src/com/fr/design/mainframe/alphafine/component/AlphaFineDialog.java @@ -67,8 +67,10 @@ public class AlphaFineDialog extends UIDialog { private JList searchResultList; private SearchListModel searchListModel; private SwingWorker searchWorker; + //是否强制打开,因为面板是否dispose绑定了全局鼠标事件,这里需要处理一下 + private boolean foreOpen; - public AlphaFineDialog(Frame parent) { + public AlphaFineDialog(Frame parent, boolean foreOpen) { super(parent); initProperties(); initListener(); @@ -485,9 +487,9 @@ public class AlphaFineDialog extends UIDialog { Point p = k.getLocationOnScreen(); Rectangle dialogRectangle = AlphaFineDialog.this.getBounds(); Rectangle paneRectangle = new Rectangle(AlphaFinePane.createAlphaFinePane().getLocationOnScreen(), AlphaFinePane.createAlphaFinePane().getSize()); - if (!dialogRectangle.contains(p) && !paneRectangle.contains(p)) { + if (!dialogRectangle.contains(p) && !paneRectangle.contains(p) && !foreOpen) { AlphaFineDialog.this.dispose(); - System.out.print(p + "\n"); + foreOpen = false; } } } @@ -518,7 +520,7 @@ public class AlphaFineDialog extends UIDialog { } private static void doClickAction() { - AlphaFineHelper.showAlphaFineDialog(); + AlphaFineHelper.showAlphaFineDialog(false); } @@ -667,4 +669,11 @@ public class AlphaFineDialog extends UIDialog { } + public boolean isForeOpen() { + return foreOpen; + } + + public void setForeOpen(boolean foreOpen) { + this.foreOpen = foreOpen; + } } \ No newline at end of file diff --git a/designer/src/com/fr/design/mainframe/alphafine/component/AlphaFinePane.java b/designer/src/com/fr/design/mainframe/alphafine/component/AlphaFinePane.java index f818fb587c..6c23ab4039 100644 --- a/designer/src/com/fr/design/mainframe/alphafine/component/AlphaFinePane.java +++ b/designer/src/com/fr/design/mainframe/alphafine/component/AlphaFinePane.java @@ -39,13 +39,13 @@ public class AlphaFinePane extends BasicPane { refreshButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - AlphaFineHelper.showAlphaFineDialog(); + AlphaFineHelper.showAlphaFineDialog(false); } }); AlphafineContext.addAlphafineContextListener(new AlphafineListener() { @Override public void showDialog() { - AlphaFineHelper.showAlphaFineDialog(); + AlphaFineHelper.showAlphaFineDialog(true); } }); } diff --git a/designer_base/src/com/fr/design/actions/help/alphafine/RemindPane.java b/designer_base/src/com/fr/design/actions/help/alphafine/RemindPane.java index 17cb6e456c..32431d7451 100644 --- a/designer_base/src/com/fr/design/actions/help/alphafine/RemindPane.java +++ b/designer_base/src/com/fr/design/actions/help/alphafine/RemindPane.java @@ -46,10 +46,9 @@ public class RemindPane extends JPanel { openButton.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { - System.out.print(e.getLocationOnScreen() + "\n"); - //manager.setOperateCount(0); dialog.dispose(); AlphafineContext.fireAlphaFineContextListener(); + } }); backgroundLabel = new UILabel(Inter.getLocText("FR-Designer-Alphafine_No_Remind")); From 869b50a565122137f00c2ca89825c6138815e195 Mon Sep 17 00:00:00 2001 From: XiaXiang Date: Sat, 27 May 2017 18:28:17 +0800 Subject: [PATCH 38/41] rt --- .../design/mainframe/alphafine/component/AlphaFineDialog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/designer/src/com/fr/design/mainframe/alphafine/component/AlphaFineDialog.java b/designer/src/com/fr/design/mainframe/alphafine/component/AlphaFineDialog.java index 7b9974b795..25bcef15fa 100644 --- a/designer/src/com/fr/design/mainframe/alphafine/component/AlphaFineDialog.java +++ b/designer/src/com/fr/design/mainframe/alphafine/component/AlphaFineDialog.java @@ -67,7 +67,7 @@ public class AlphaFineDialog extends UIDialog { private JList searchResultList; private SearchListModel searchListModel; private SwingWorker searchWorker; - //是否强制打开,因为面板是否dispose绑定了全局鼠标事件,这里需要处理一下 + //是否强制打开,因为面板是否关闭绑定了全局鼠标事件,这里需要处理一下 private boolean foreOpen; public AlphaFineDialog(Frame parent, boolean foreOpen) { From 40d6bfbb41f0ef8459843e4abd9da7fe5ebb73bb Mon Sep 17 00:00:00 2001 From: XiaXiang Date: Tue, 30 May 2017 17:14:12 +0800 Subject: [PATCH 39/41] bug fix --- .../alphafine/search/manager/RecentSearchManager.java | 5 ++++- .../src/com/fr/design/actions/help/alphafine/RemindPane.java | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/designer/src/com/fr/design/mainframe/alphafine/search/manager/RecentSearchManager.java b/designer/src/com/fr/design/mainframe/alphafine/search/manager/RecentSearchManager.java index 9f060def66..8742c09ba4 100644 --- a/designer/src/com/fr/design/mainframe/alphafine/search/manager/RecentSearchManager.java +++ b/designer/src/com/fr/design/mainframe/alphafine/search/manager/RecentSearchManager.java @@ -97,7 +97,10 @@ public class RecentSearchManager extends XMLFileManager implements AlphaFineSear private void addModelToList(List list, String name) { try { - list.add(CellModelHelper.getModelFromJson(new JSONObject(name))); + AlphaCellModel model = CellModelHelper.getModelFromJson(new JSONObject(name)); + if (model != null) { + list.add(CellModelHelper.getModelFromJson(new JSONObject(name))); + } } catch (JSONException e) { FRLogger.getLogger().error(e.getMessage()); } diff --git a/designer_base/src/com/fr/design/actions/help/alphafine/RemindPane.java b/designer_base/src/com/fr/design/actions/help/alphafine/RemindPane.java index 32431d7451..db984aecac 100644 --- a/designer_base/src/com/fr/design/actions/help/alphafine/RemindPane.java +++ b/designer_base/src/com/fr/design/actions/help/alphafine/RemindPane.java @@ -46,6 +46,7 @@ public class RemindPane extends JPanel { openButton.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { + manager.setOperateCount(0); dialog.dispose(); AlphafineContext.fireAlphaFineContextListener(); @@ -77,7 +78,7 @@ public class RemindPane extends JPanel { closeButton.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { - //manager.setOperateCount(0); + manager.setOperateCount(0); dialog.dispose(); } From 06af382b35fadc2970e1dd75fbc383ac38c3fb3c Mon Sep 17 00:00:00 2001 From: XiaXiang Date: Wed, 31 May 2017 09:04:17 +0800 Subject: [PATCH 40/41] bug fix --- .../actions/help/alphafine/RemindPane.java | 39 +++++++++++++------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/designer_base/src/com/fr/design/actions/help/alphafine/RemindPane.java b/designer_base/src/com/fr/design/actions/help/alphafine/RemindPane.java index db984aecac..1e8261965c 100644 --- a/designer_base/src/com/fr/design/actions/help/alphafine/RemindPane.java +++ b/designer_base/src/com/fr/design/actions/help/alphafine/RemindPane.java @@ -15,17 +15,27 @@ import java.awt.event.MouseEvent; * Created by XiaXiang on 2017/5/26. */ public class RemindPane extends JPanel { - public static final Font MEDIUM_FONT = new Font("Song_TypeFace", 0, 12); - public static final Font LARGE_FONT = new Font("Song_TypeFace", 0, 18); + private UIButton openButton; private JPanel backgroundPane; - private UILabel backgroundLabel; + private UILabel noRemindLabel; private UILabel checkLabel; private Icon checkIcon = IOUtils.readIcon("/com/fr/design/mainframe/alphafine/images/check.png"); private Icon unCheckIcon = IOUtils.readIcon("/com/fr/design/mainframe/alphafine/images/uncheck.png"); private Icon closeIcon = IOUtils.readIcon("/com/fr/design/mainframe/alphafine/images/remind_close.png"); private Icon labelIcon = IOUtils.readIcon("/com/fr/design/mainframe/alphafine/images/remind.png"); private Icon openIcon = IOUtils.readIcon("com/fr/design/mainframe/alphafine/images/open.png"); + + private static final int WIDTH = 600; + private static final int HEIGHT = 400; + private static final int CLOSE = 30; + + private static final Rectangle OPEN = new Rectangle(30, 300, 150, 40); + private static final Rectangle REMIND = new Rectangle(95, 350, 100, 20); + private static final Rectangle CHECK = new Rectangle(70, 350, 20, 20); + public static final Font MEDIUM_FONT = new Font("Song_TypeFace", 0, 12); + public static final Font LARGE_FONT = new Font("Song_TypeFace", 0, 18); + public JComponent closeButton = new JComponent() { protected void paintComponent(Graphics g) { closeIcon.paintIcon(this, g, 0, 0); @@ -33,11 +43,16 @@ public class RemindPane extends JPanel { }; public RemindPane(AlphafineConfigManager manager, UIDialog remindDialog) { - this.setPreferredSize(new Dimension(600, 400)); + this.setPreferredSize(new Dimension(WIDTH, HEIGHT)); initUI(manager, remindDialog); this.setLayout(getAbsoluteLayout()); } + /** + * 初始化面板 + * @param manager + * @param dialog + */ private void initUI(final AlphafineConfigManager manager, final UIDialog dialog) { openButton = new UIButton(); @@ -52,9 +67,9 @@ public class RemindPane extends JPanel { } }); - backgroundLabel = new UILabel(Inter.getLocText("FR-Designer-Alphafine_No_Remind")); - backgroundLabel.setFont(MEDIUM_FONT); - backgroundLabel.setForeground(Color.white); + noRemindLabel = new UILabel(Inter.getLocText("FR-Designer-Alphafine_No_Remind")); + noRemindLabel.setFont(MEDIUM_FONT); + noRemindLabel.setForeground(Color.white); checkLabel = new UILabel(); checkLabel.setIcon(unCheckIcon); checkLabel.addMouseListener(new MouseAdapter() { @@ -86,7 +101,7 @@ public class RemindPane extends JPanel { add(closeButton, 0); add(checkLabel, 1); add(openButton, 2); - add(backgroundLabel, 3); + add(noRemindLabel, 3); add(backgroundPane, 4); } @@ -115,10 +130,10 @@ public class RemindPane extends JPanel { public void layoutContainer(Container parent) { int width = parent.getWidth(); int height = parent.getHeight(); - closeButton.setBounds((width - 30), 0, 30, 30); - openButton.setBounds(30, 300, 150, 40); - backgroundLabel.setBounds(95, 350, 100, 20); - checkLabel.setBounds(70, 350, 20, 20); + closeButton.setBounds((width - CLOSE), 0, CLOSE, CLOSE); + openButton.setBounds(OPEN); + noRemindLabel.setBounds(REMIND); + checkLabel.setBounds(CHECK); backgroundPane.setBounds(0, 0, width, height); } From f905d03d0e35146c784348f65715e202b8b23355 Mon Sep 17 00:00:00 2001 From: sunmondong Date: Wed, 31 May 2017 14:07:33 +0800 Subject: [PATCH 41/41] =?UTF-8?q?aspectJ=E7=BC=96=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- designer_base/build.9.0.gradle | 24 ++++++++- designer_base/build.9.0.gradle.bak | 69 ++++++++++++++++++++++++ designer_chart/build.9.0.gradle | 24 ++++++++- designer_chart/build.9.0.gradle.bak | 69 ++++++++++++++++++++++++ designer_form/build.9.0.gradle | 23 +++++++- designer_form/build.9.0.gradle.bak | 83 +++++++++++++++++++++++++++++ 6 files changed, 287 insertions(+), 5 deletions(-) create mode 100644 designer_base/build.9.0.gradle.bak create mode 100644 designer_chart/build.9.0.gradle.bak create mode 100644 designer_form/build.9.0.gradle.bak diff --git a/designer_base/build.9.0.gradle b/designer_base/build.9.0.gradle index af0dc75f05..fa144095e9 100644 --- a/designer_base/build.9.0.gradle +++ b/designer_base/build.9.0.gradle @@ -1,8 +1,28 @@ - -apply plugin: 'java' tasks.withType(JavaCompile){ options.encoding = 'UTF-8' } +buildscript { + repositories { + maven { + url "https://maven.eveoh.nl/content/repositories/releases" + } + } + + dependencies { + classpath "nl.eveoh:gradle-aspectj:1.6" + } +} + +repositories { + mavenCentral() +} + +project.ext { + aspectjVersion = '1.8.4' +} + +apply plugin: 'aspectj' + //指定构建的jdk版本 sourceCompatibility=1.7 //指定生成jar包版本 diff --git a/designer_base/build.9.0.gradle.bak b/designer_base/build.9.0.gradle.bak new file mode 100644 index 0000000000..af0dc75f05 --- /dev/null +++ b/designer_base/build.9.0.gradle.bak @@ -0,0 +1,69 @@ + +apply plugin: 'java' +tasks.withType(JavaCompile){ + options.encoding = 'UTF-8' +} +//指定构建的jdk版本 +sourceCompatibility=1.7 +//指定生成jar包版本 +version='8.0' +//生成jar包重命名 +jar{ + baseName='fr-designer-core' +} + + +def srcDir="." +def baseDir=".." + +//指定源码路径 +sourceSets{ + main{ + java{ + srcDirs=["${srcDir}/src"] + } + } +} +//获取什么分支名 +FileTree files =fileTree(dir:'./',include:'build.*.gradle') +def buildDir=files[0].path.substring(0,files[0].path.lastIndexOf ('\\')) +buildDir=buildDir.substring(0,buildDir.lastIndexOf ('\\')) +def branchName=buildDir.substring(buildDir.lastIndexOf ('\\')+1) + +//声明外部依赖 +dependencies{ + compile fileTree(dir:"../${baseDir}/lib",include:'**/*.jar') + compile fileTree(dir:"../${baseDir}",include:"**/build/libs/*.jar",exclude:"bi/**/*.jar") + testCompile 'junit:junit:4.12' +} +//复制非.java文件到classes文件夹下参与打包 +task copyFile(type:Copy,dependsOn:compileJava){ + copy{ + from ("${srcDir}/src"){ + exclude '**/.setting/**','.classpath','.project','**/*.java','**/*.db','**/*.g','**/package.html' + } + into 'build/classes/main' + } + +} + + +//压缩项目中的js文件 +task compressJS{ + ant.taskdef(name:'yuicompress',classname:'com.yahoo.platform.yui.compressor.YUICompressTask'){ + classpath { + fileset(dir:"../${baseDir}/lib4build",includes:'**/*.jar') + } + } + ant.yuicompress(linebreak:"500",warn:"false", munge:"yes",preserveallsemicolons:"false",charset:"utf-8",encoding:"utf-8",outputfolder:'build/classes/main'){ + fileset (dir:"${srcDir}/src"){ + include (name:'**/*.js') + include (name:'**/*.css') + } + + } +} +jar.dependsOn compressJS + + + diff --git a/designer_chart/build.9.0.gradle b/designer_chart/build.9.0.gradle index c8f7e2ac3d..c249659124 100644 --- a/designer_chart/build.9.0.gradle +++ b/designer_chart/build.9.0.gradle @@ -1,8 +1,28 @@ - -apply plugin: 'java' tasks.withType(JavaCompile){ options.encoding = 'UTF-8' } +buildscript { + repositories { + maven { + url "https://maven.eveoh.nl/content/repositories/releases" + } + } + + dependencies { + classpath "nl.eveoh:gradle-aspectj:1.6" + } +} + +repositories { + mavenCentral() +} + +project.ext { + aspectjVersion = '1.8.4' +} + +apply plugin: 'aspectj' + //指定构建的jdk版本 sourceCompatibility=1.7 //指定生成jar包版本 diff --git a/designer_chart/build.9.0.gradle.bak b/designer_chart/build.9.0.gradle.bak new file mode 100644 index 0000000000..c8f7e2ac3d --- /dev/null +++ b/designer_chart/build.9.0.gradle.bak @@ -0,0 +1,69 @@ + +apply plugin: 'java' +tasks.withType(JavaCompile){ + options.encoding = 'UTF-8' +} +//指定构建的jdk版本 +sourceCompatibility=1.7 +//指定生成jar包版本 +version='8.0' +//生成jar包重命名 +jar{ + baseName='fr-designer-chart' +} + + +def srcDir="." +def baseDir=".." + +//指定源码路径 +sourceSets{ + main{ + java{ + srcDirs=["${srcDir}/src"] + } + } +} +//获取什么分支名 +FileTree files =fileTree(dir:'./',include:'build.*.gradle') +def buildDir=files[0].path.substring(0,files[0].path.lastIndexOf ('\\')) +buildDir=buildDir.substring(0,buildDir.lastIndexOf ('\\')) +def branchName=buildDir.substring(buildDir.lastIndexOf ('\\')+1) + +//声明外部依赖 +dependencies{ + compile fileTree(dir:"../${baseDir}/lib",include:'**/*.jar') + compile fileTree(dir:"../${baseDir}",include:"**/build/libs/*.jar",exclude:"bi/**/*.jar") + testCompile 'junit:junit:4.12' +} +//复制非.java文件到classes文件夹下参与打包 +task copyFile(type:Copy,dependsOn:compileJava){ + copy{ + from ("${srcDir}/src"){ + exclude '**/.setting/**','.classpath','.project','**/*.java','**/*.db','**/*.g','**/package.html' + } + into 'build/classes/main' + } + +} + + +//压缩项目中的js文件 +task compressJS{ + ant.taskdef(name:'yuicompress',classname:'com.yahoo.platform.yui.compressor.YUICompressTask'){ + classpath { + fileset(dir:"../${baseDir}/lib4build",includes:'**/*.jar') + } + } + ant.yuicompress(linebreak:"500",warn:"false", munge:"yes",preserveallsemicolons:"false",charset:"utf-8",encoding:"utf-8",outputfolder:'build/classes/main'){ + fileset (dir:"${srcDir}/src"){ + include (name:'**/*.js') + include (name:'**/*.css') + } + + } +} +jar.dependsOn compressJS + + + diff --git a/designer_form/build.9.0.gradle b/designer_form/build.9.0.gradle index 1decff56b9..ebe2c4b795 100644 --- a/designer_form/build.9.0.gradle +++ b/designer_form/build.9.0.gradle @@ -1,8 +1,29 @@ -apply plugin: 'java' tasks.withType(JavaCompile){ options.encoding = 'UTF-8' } +buildscript { + repositories { + maven { + url "https://maven.eveoh.nl/content/repositories/releases" + } + } + + dependencies { + classpath "nl.eveoh:gradle-aspectj:1.6" + } +} + +repositories { + mavenCentral() +} + +project.ext { + aspectjVersion = '1.8.4' +} + +apply plugin: 'aspectj' + //指定构建的jdk版本 sourceCompatibility=1.7 //指定生成jar包版本 diff --git a/designer_form/build.9.0.gradle.bak b/designer_form/build.9.0.gradle.bak new file mode 100644 index 0000000000..1decff56b9 --- /dev/null +++ b/designer_form/build.9.0.gradle.bak @@ -0,0 +1,83 @@ + +apply plugin: 'java' +tasks.withType(JavaCompile){ + options.encoding = 'UTF-8' +} +//指定构建的jdk版本 +sourceCompatibility=1.7 +//指定生成jar包版本 +version='8.0' +//生成jar包重命名 +jar{ + baseName='fr-designer-report' +} + + +def srcDir="." +def baseDir=".." + +//指定源码路径 +sourceSets{ + main{ + java{ + srcDirs=["${srcDir}/src", + "${srcDir}/../designer/src"] + } + } +} +//获取什么分支名 +FileTree files =fileTree(dir:'./',include:'build.*.gradle') +def buildDir=files[0].path.substring(0,files[0].path.lastIndexOf ('\\')) +buildDir=buildDir.substring(0,buildDir.lastIndexOf ('\\')) +def branchName=buildDir.substring(buildDir.lastIndexOf ('\\')+1) + +//声明外部依赖 +dependencies{ + compile fileTree(dir:"../${baseDir}/lib",include:'**/*.jar') + compile fileTree(dir:"../${baseDir}",include:"**/build/libs/*.jar",exclude:"bi/**/*.jar") + testCompile 'junit:junit:4.12' +} +//复制非.java文件到classes文件夹下参与打包 + +//指明无法编译文件所在路径 +def dataContent ={def dir -> + copySpec{ + from ("${dir}"){ + exclude '**/.setting/**','.classpath','.project','**/*.java','**/*.db','**/*.g','**/package.html' + } + } +} + +task copyFile(type:Copy,dependsOn:compileJava){ + copy{ + with dataContent.call("${srcDir}/src") + with dataContent.call("${srcDir}/../designer/src") + into 'build/classes/main' + } + +} + + +//压缩项目中的js文件 +task compressJS{ + ant.taskdef(name:'yuicompress',classname:'com.yahoo.platform.yui.compressor.YUICompressTask'){ + classpath { + fileset(dir:"../${baseDir}/lib4build",includes:'**/*.jar') + } + } + ant.yuicompress(linebreak:"500",warn:"false", munge:"yes",preserveallsemicolons:"false",charset:"utf-8",encoding:"utf-8",outputfolder:'build/classes/main'){ + fileset (dir:"${srcDir}/src"){ + include (name:'**/*.js') + include (name:'**/*.css') + } + fileset (dir:"${srcDir}/../designer/src"){ + include (name:'**/*.js') + include (name:'**/*.css') + } + + } +} +jar.dependsOn compressJS + + +