• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 package com.update.check.action.view;
17 
18 import com.update.check.dto.UpdateCheckReportDto;
19 import com.update.check.action.DataUpdateNotifier;
20 import com.update.check.dto.ApiDiffResultDto;
21 import com.update.check.log.Logger;
22 import com.update.check.utils.FileUtils;
23 import com.intellij.openapi.Disposable;
24 import com.intellij.openapi.editor.Editor;
25 import com.intellij.openapi.editor.CaretModel;
26 import com.intellij.openapi.editor.LogicalPosition;
27 import com.intellij.openapi.editor.ScrollType;
28 import com.intellij.openapi.editor.ScrollingModel;
29 import com.intellij.openapi.fileEditor.FileEditorManager;
30 import com.intellij.openapi.project.Project;
31 import com.intellij.openapi.util.Disposer;
32 import com.intellij.openapi.vfs.LocalFileSystem;
33 import com.intellij.openapi.vfs.VirtualFile;
34 import com.intellij.openapi.wm.ToolWindow;
35 import com.intellij.ui.content.Content;
36 import com.intellij.ui.content.ContentManager;
37 import org.apache.commons.lang.StringUtils;
38 import org.jetbrains.annotations.NotNull;
39 
40 import javax.swing.JPanel;
41 import javax.swing.JButton;
42 import javax.swing.JTable;
43 import javax.swing.JComponent;
44 import javax.swing.JLabel;
45 import javax.swing.table.TableColumn;
46 import javax.swing.table.AbstractTableModel;
47 import java.awt.Desktop;
48 import java.awt.event.ActionListener;
49 import java.awt.event.ActionEvent;
50 import java.awt.event.MouseAdapter;
51 import java.awt.event.MouseEvent;
52 import java.io.File;
53 import java.io.IOException;
54 import java.net.URI;
55 import java.net.URISyntaxException;
56 import java.util.HashMap;
57 import java.util.Map;
58 import java.util.List;
59 import java.util.LinkedHashMap;
60 import java.util.ArrayList;
61 import java.util.concurrent.ConcurrentHashMap;
62 import java.util.function.Function;
63 import java.util.function.Predicate;
64 import java.util.regex.Matcher;
65 import java.util.regex.Pattern;
66 import java.util.stream.Collectors;
67 
68 /**
69  * UpdateReportPanel
70  *
71  * @since 23-04-07
72  */
73 public class UpdateReportPanel implements Disposable {
74     private static final Logger LOGGER = Logger.createLogger();
75 
76     private static final String LOG_TAG = UpdateReportPanel.class.getName();
77 
78     private JPanel rootPanel;
79 
80     private JTable updateReport;
81 
82     private JLabel sumLabel;
83 
84     private JButton chooseTypeButton;
85 
86     private Project project;
87 
88     private Map<String, String> changeLogs = new HashMap<>();
89 
90     private List<UpdateCheckReportDto> reportDtos = new ArrayList<>();
91 
92     private LinkedHashMap<String, Boolean> arrayTypes = new LinkedHashMap<>();
93 
94     /**
95      * UpdateReportPanel
96      *
97      * @param project project
98      */
UpdateReportPanel(Project project)99     public UpdateReportPanel(Project project) {
100         this.project = project;
101         Report report = new Report();
102         this.updateReport.setModel(report);
103         this.setTableStyle();
104     }
105 
106     @Override
dispose()107     public void dispose() {
108 
109     }
110 
111     /**
112      * loadPanel
113      *
114      * @param project    project
115      * @param toolWindow toolWindow
116      */
loadPanel(@otNull Project project, @NotNull ToolWindow toolWindow)117     public static void loadPanel(@NotNull Project project, @NotNull ToolWindow toolWindow) {
118         UpdateReportPanel updateReportPanel = new UpdateReportPanel(project);
119         ContentManager contentManager = toolWindow.getContentManager();
120         Content content = contentManager.getFactory().createContent(
121                 updateReportPanel.getPanel(), "Report", false);
122         contentManager.addContent(content);
123         Disposer.register(project, updateReportPanel);
124     }
125 
126     /**
127      * getPanel
128      *
129      * @return rootPanel
130      */
getPanel()131     public JComponent getPanel() {
132         return this.rootPanel;
133     }
134 
filterType()135     private void filterType() {
136         this.updateChooseType();
137         this.setUpdateReportStyle();
138     }
139 
updateChooseType()140     private void updateChooseType() {
141         List<UpdateCheckReportDto> typeDto = reportDtos.stream().distinct()
142                 .filter(distinctByKey(UpdateCheckReportDto::getChangeType))
143                 .collect(Collectors.toList());
144         arrayTypes.clear();
145         arrayTypes.put(ConstString.get("check.choose.all"), true);
146         if (typeDto.size() == 0) {
147             return;
148         }
149         for (UpdateCheckReportDto dto : typeDto) {
150             if (dto == null) {
151                 break;
152             }
153             arrayTypes.put(dto.getChangeType(), true);
154         }
155     }
156 
setTableStyle()157     private void setTableStyle() {
158         LOGGER.info(LOG_TAG, "Start rendering JTable");
159         this.filterType();
160         this.chooseTypeButton.setText(ConstString.get("check.choose.type"));
161         this.chooseTypeButton.addActionListener(new ActionListener() {
162             @Override
163             public void actionPerformed(ActionEvent e) {
164                 ShowTypeDialog.showDialog(project, arrayTypes);
165             }
166         });
167         LOGGER.info(LOG_TAG, "Rendering JTable end");
168     }
169 
setUpdateReportStyle()170     private void setUpdateReportStyle() {
171 
172         // Set Table Row Height
173         this.updateReport.setRowHeight(30);
174 
175         // add addMouseListener
176         this.updateReport.setRowSelectionAllowed(true);
177         this.updateReport.setColumnSelectionAllowed(true);
178         this.setUpdateStyle();
179         this.setListenerToReportPanel();
180     }
181 
setUpdateStyle()182     private void setUpdateStyle() {
183         TableColumn tc = this.updateReport.getColumnModel().getColumn(0);
184         tc.setCellEditor(this.updateReport.getDefaultEditor(Boolean.class));
185         tc.setCellRenderer(this.updateReport.getDefaultRenderer(Boolean.class));
186         tc.setPreferredWidth(100);
187         tc.setMaxWidth(100);
188         tc.setMinWidth(100);
189         TableColumn tableColumn = this.updateReport.getColumnModel().getColumn(5);
190         tableColumn.setPreferredWidth(200);
191         tableColumn.setMaxWidth(200);
192         tableColumn.setMinWidth(200);
193     }
194 
setListenerToReportPanel()195     private void setListenerToReportPanel() {
196         this.updateReport.addMouseListener(new MouseAdapter() {
197             @Override
198             public void mouseClicked(MouseEvent e) {
199                 int col = updateReport.columnAtPoint(e.getPoint());
200                 int row = updateReport.getSelectedRow();
201 
202                 // api in simple address
203                 if (col == 4 && e.getClickCount() == 2) {
204                     Object valueAt1 = updateReport.getValueAt(row, 4);
205                     String valueAt = null;
206                     if (valueAt1 instanceof String) {
207                         valueAt = (String) valueAt1;
208                     }
209                     if (StringUtils.isBlank(valueAt)) {
210                         return;
211                     }
212                     if (getApiInApplicationPath(valueAt) == null) {
213                         return;
214                     }
215                     try {
216                         VirtualFile fileByIoFile = LocalFileSystem
217                                 .getInstance()
218                                 .findFileByIoFile(new File(project.getBasePath(),
219                                         getApiInApplicationPath(valueAt)));
220                         FileEditorManager.getInstance(project).openFile(fileByIoFile, true);
221                         gotoLine(Integer.parseInt(valueAt.replaceAll(ConstString.get("check.replace"), "$1")));
222                     } catch (IllegalArgumentException exception) {
223                         MessageBox.showDialog(project, "", ConstString.get("can.not.find.file"));
224                     }
225                 } else if (col == 5) {
226                     Object childValue = updateReport.getValueAt(row, 5);
227                     String valueAt = null;
228                     if (childValue instanceof String) {
229                         valueAt = (String) childValue;
230                     }
231                     if (StringUtils.isBlank(valueAt)) {
232                         return;
233                     }
234                     if (valueAt.split(",").length == 1) {
235                         clickUrl(changeLogs.get(valueAt));
236                         return;
237                     }
238                     ShowChangeLogsDialog.showDialog(project, changeLogs, valueAt);
239                 }
240             }
241         });
242     }
243 
getApiInApplicationPath(String apiAddress)244     private String getApiInApplicationPath(String apiAddress) {
245         String pattern = ConstString.get("check.report.pattern");
246         Pattern r = Pattern.compile(pattern);
247         Matcher m = r.matcher(apiAddress);
248         if (m.find()) {
249             return m.group(0);
250         }
251         return null;
252     }
253 
clickUrl(String url)254     private void clickUrl(String url) {
255         try {
256             if (StringUtils.isNotBlank(url)) {
257                 Desktop desktop = Desktop.getDesktop();
258                 URI uri = new URI(url);
259                 desktop.browse(uri);
260             }
261         } catch (URISyntaxException | IOException exception) {
262             exception.printStackTrace();
263             LOGGER.error(LOG_TAG, "Click " + url + " error! " + exception.getMessage());
264         }
265     }
266 
gotoLine(int lineNumber)267     private void gotoLine(int lineNumber) {
268         Editor editor = FileEditorManager.getInstance(this.project).getSelectedTextEditor();
269         if (editor == null) {
270             return;
271         }
272         CaretModel caretModel = editor.getCaretModel();
273         int totalLineCount = editor.getDocument().getLineCount();
274         if (lineNumber > totalLineCount) {
275             return;
276         }
277 
278         // Moving caret to line number
279         caretModel.moveToLogicalPosition(new LogicalPosition(lineNumber - 1, 0));
280 
281         // Scroll to the caret
282         ScrollingModel scrollingModel = editor.getScrollingModel();
283         scrollingModel.scrollToCaret(ScrollType.CENTER);
284     }
285 
286     class Report extends AbstractTableModel implements DataUpdateNotifier.UpdateListener {
287         List<Object[]> dataList = new ArrayList<>();
288         String[] titles = new String[7];
289         int sum = 0;
290 
291         /**
292          * Report
293          */
Report()294         public Report() {
295             LOGGER.info(LOG_TAG, "Start loading report window");
296             DataUpdateNotifier.getInstance().addUpdateListener(this);
297             this.getReportResult();
298             this.initReport(new LinkedHashMap<>());
299             LOGGER.info(LOG_TAG, "Loading report window end");
300         }
301 
getReportResult()302         private void getReportResult() {
303             try {
304                 File resultJsonFile = new File(project.getBasePath(),
305                         ConstString.get("check.report.json"));
306                 List<UpdateCheckReportDto> updateCheckReportDtos =
307                         FileUtils.readJsonFileToJavaList(resultJsonFile.toString(),
308                                 UpdateCheckReportDto.class);
309                 reportDtos = updateCheckReportDtos;
310                 LOGGER.info(LOG_TAG, "Report size:" + updateCheckReportDtos.size());
311             } catch (IOException e) {
312                 LOGGER.error(LOG_TAG, e.getMessage());
313             }
314         }
315 
screenResult(LinkedHashMap<String, Boolean> changeTypes)316         private List<UpdateCheckReportDto> screenResult(LinkedHashMap<String, Boolean> changeTypes) {
317             if (changeTypes.size() == 0) {
318                 return reportDtos;
319             }
320             List<String> chooseTypes = new ArrayList<>();
321             for (Map.Entry<String, Boolean> entry : changeTypes.entrySet()) {
322                 if (entry.getValue()) {
323                     chooseTypes.add(entry.getKey());
324                 }
325             }
326             return this.multipleChoice(chooseTypes);
327         }
328 
multipleChoice(List<String> chooseTypes)329         private List<UpdateCheckReportDto> multipleChoice(List<String> chooseTypes) {
330             List<UpdateCheckReportDto> multipleChoice = new ArrayList<>();
331             for (String changeType : chooseTypes) {
332                 for (UpdateCheckReportDto dto : reportDtos) {
333                     if (dto != null && dto.getChangeType().equals(changeType)) {
334                         multipleChoice.add(dto);
335                     }
336                 }
337             }
338             return multipleChoice;
339         }
340 
update(LinkedHashMap<String, Boolean> chooseType, String type)341         private void update(LinkedHashMap<String, Boolean> chooseType, String type) {
342             LOGGER.info(LOG_TAG, "Start reload report window");
343             dataList.clear();
344             if ("executeAgain".equals(type)) {
345                 this.getReportResult();
346                 updateChooseType();
347             } else {
348                 arrayTypes = chooseType;
349             }
350             this.initReport(chooseType);
351             fireTableDataChanged();
352             LOGGER.info(LOG_TAG, "Reload report window end");
353         }
354 
initReport(LinkedHashMap<String, Boolean> changeTypes)355         private void initReport(LinkedHashMap<String, Boolean> changeTypes) {
356             List<UpdateCheckReportDto> reportResult = this.screenResult(changeTypes);
357             if (reportResult == null) {
358                 return;
359             }
360             sum = reportResult.size();
361             sumLabel.setText(ConstString.get("sum.report") + sum);
362             for (int i = 0; i < reportResult.size(); i++) {
363                 UpdateCheckReportDto report = reportResult.get(i);
364                 String filePath = report
365                         .getSourceFileName()
366                         .replace(project.getBasePath() + "/", "");
367                 dataList.add(new Object[]{false
368                         , ConstString.get("not.involved")
369                         .equals(report.getSourceFileName())
370                         ? report.getSourceFileName()
371                         : getFileName(report.getSourceFileName())
372                         , report.getApiDefinition(), report.getReminderInformation()
373                         , ConstString.get("not.involved").equals(report.getPos())
374                         ? report.getPos() : filePath + "(" + report.getPos() + ")"
375                         , this.setChangeLogUrl(report.getChangelogs())});
376             }
377             titles[0] = ConstString.get("check.report.order.number");
378             titles[1] = ConstString.get("check.report.ets.name");
379             titles[2] = ConstString.get("report.old.method.text");
380             titles[3] = ConstString.get("report.new.method.text");
381             titles[4] = ConstString.get("report.function.position");
382             titles[5] = ConstString.get("report.change.log");
383         }
384 
setChangeLogUrl(List<ApiDiffResultDto.Changelog> changelogs)385         private String setChangeLogUrl(List<ApiDiffResultDto.Changelog> changelogs) {
386             if (changelogs == null) {
387                 return "";
388             }
389             StringBuilder sb = new StringBuilder();
390             for (ApiDiffResultDto.Changelog changelog : changelogs) {
391                 if (changelog == null) {
392                     continue;
393                 }
394                 changeLogs.put(changelog.getVersion(), changelog.getUrl());
395                 sb.append(changelog.getVersion() + ",");
396             }
397             return sb.toString().replaceFirst(",$", "");
398         }
399 
getFileName(String filePath)400         private String getFileName(String filePath) {
401             File file = new File(filePath);
402             if (file.isFile()) {
403                 return file.getName();
404             }
405             return "";
406         }
407 
408         @Override
isCellEditable(int row, int col)409         public boolean isCellEditable(int row, int col) {
410             return col == 0;
411         }
412 
413         @Override
getColumnName(int column)414         public String getColumnName(int column) {
415             return titles[column];
416         }
417 
418         @Override
getRowCount()419         public int getRowCount() {
420             return sum;
421         }
422 
423         @Override
getColumnCount()424         public int getColumnCount() {
425             return 6;
426         }
427 
428         @Override
getValueAt(int rowIndex, int columnIndex)429         public Object getValueAt(int rowIndex, int columnIndex) {
430             return this.dataList.get(rowIndex)[columnIndex];
431         }
432 
433         @Override
setValueAt(Object aValue, int rowIndex, int columnIndex)434         public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
435             this.dataList.get(rowIndex)[columnIndex] = aValue;
436         }
437 
438         @Override
onUpdate(LinkedHashMap<String, Boolean> chooseType, String type)439         public void onUpdate(LinkedHashMap<String, Boolean> chooseType, String type) {
440             update(chooseType, type);
441         }
442     }
443 
distinctByKey(Function<? super T, Object> keyExtractor)444     private <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
445         Map<Object, Boolean> seen = new ConcurrentHashMap<>();
446         return object -> seen.putIfAbsent(keyExtractor.apply(object), Boolean.TRUE) == null;
447     }
448 
449 }
450