package eu.doppel_helix.netbeans.mantisintegration.query; import biz.futureware.mantisconnect.AccountData; import biz.futureware.mantisconnect.FilterData; import biz.futureware.mantisconnect.ObjectRef; import biz.futureware.mantisconnect.ProjectData; import eu.doppel_helix.netbeans.mantisintegration.Mantis; import eu.doppel_helix.netbeans.mantisintegration.data.FlattenedProjectData; import eu.doppel_helix.netbeans.mantisintegration.issue.MantisIssue; import eu.doppel_helix.netbeans.mantisintegration.issue.MantisStatusProvider; import eu.doppel_helix.netbeans.mantisintegration.repository.MantisRepository; import eu.doppel_helix.netbeans.mantisintegration.swing.ListBackedComboBoxModel; import eu.doppel_helix.netbeans.mantisintegration.util.SafeAutocloseable; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.math.BigInteger; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.SwingWorker; import javax.xml.rpc.ServiceException; import javax.xml.ws.Holder; import org.netbeans.modules.bugtracking.spi.IssueStatusProvider; import org.netbeans.modules.bugtracking.spi.QueryController; import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; import org.openide.util.Exceptions; import org.openide.util.HelpCtx; import org.openide.util.Mutex; import org.openide.util.NbBundle; import org.openide.util.RequestProcessor; public class MantisQueryController implements ActionListener, PropertyChangeListener, QueryController { public final static String COMMAND_OPEN_ISSUE = "open_issue"; public final static String COMMAND_SELECT_PROJECT1 = "selectProject1"; public final static String COMMAND_SELECT_PROJECT2 = "selectProject2"; public final static String COMMAND_EXECUTE_QUERY = "executeQuery"; public final static String COMMAND_DELETE_QUERY = "deleteQuery"; public final static String COMMAND_SAVE_QUERY = "saveQuery"; private final static Logger logger = Logger.getLogger( MantisQueryController.class.getName()); RequestProcessor rp = new RequestProcessor("MantisQueryController"); private ListBackedComboBoxModel<FlattenedProjectData> projectModel1 = new ListBackedComboBoxModel<>( FlattenedProjectData.class); private ListBackedComboBoxModel<FilterData> filterModel1 = new ListBackedComboBoxModel<>( FilterData.class); private ListBackedComboBoxModel<AccountData> reporterModel = new ListBackedComboBoxModel<>( AccountData.class); private ListBackedComboBoxModel<AccountData> assignedToModel = new ListBackedComboBoxModel<>( AccountData.class); private ListBackedComboBoxModel<String> categoryModel = new ListBackedComboBoxModel<>( String.class); private ListBackedComboBoxModel<ObjectRef> severityModel = new ListBackedComboBoxModel<>( ObjectRef.class); private ListBackedComboBoxModel<ObjectRef> resolutionModel = new ListBackedComboBoxModel<>( ObjectRef.class); private ListBackedComboBoxModel<ObjectRef> statusModel = new ListBackedComboBoxModel<>( ObjectRef.class); private ListBackedComboBoxModel<ObjectRef> priorityModel = new ListBackedComboBoxModel<>( ObjectRef.class); private ListBackedComboBoxModel<ObjectRef> viewstatusModel = new ListBackedComboBoxModel<>( ObjectRef.class); private MantisQueryPanel mqp; private MantisQuery mq; private MantisRepository mr; private final static ProjectData pseudoProject; private class IssueTableIssueOpener implements MouseListener, KeyListener { @Override public void mouseClicked(MouseEvent e) { int mouseRow = mqp.issueTable.rowAtPoint(e.getPoint()); if ((mouseRow != -1) && (!mqp.issueTable.isRowSelected(mouseRow))) { mqp.issueTable.setRowSelectionInterval(mouseRow, mouseRow); } if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) { int viewRow = mqp.issueTable.getSelectedRow(); if (viewRow == -1) { return; } int modelRow = mqp.issueTable.convertRowIndexToModel(viewRow); MantisIssue mi = mqp.getQueryListModel().getIssue(modelRow); Mantis.getInstance().getBugtrackingSupport().openIssue( mi.getMantisRepository(), mi); } else if (e.getButton() == MouseEvent.BUTTON3) { final MantisIssue issue; int viewRow = mqp.issueTable.getSelectedRow(); if (viewRow != -1) { int modelRow = mqp.issueTable.convertRowIndexToModel(viewRow); issue = ((QueryListModel) mqp.issueTable.getModel()).getIssue(modelRow); } else { issue = null; } final MantisStatusProvider statusProvider = Mantis.getInstance().getStatusProvider(); JPopupMenu menu = new JPopupMenu(); JMenuItem openItem = new JMenuItem(NbBundle.getMessage(MantisQueryController.class, "MantisQueryPanel.menuOpenIssue")); openItem.setEnabled(issue != null); openItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Mantis.getInstance().getBugtrackingSupport().openIssue( issue.getMantisRepository(), issue); } }); JMenuItem markAsRead = new JMenuItem(NbBundle.getMessage(MantisQueryController.class, "MantisQueryPanel.menuMarkAsRead")); markAsRead.setEnabled(statusProvider.getStatus(issue) == IssueStatusProvider.Status.INCOMING_MODIFIED || statusProvider.getStatus(issue) == IssueStatusProvider.Status.INCOMING_NEW); markAsRead.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { statusProvider.setSeenIncoming(issue, true); } }); JMenuItem markAsUnRead = new JMenuItem(NbBundle.getMessage(MantisQueryController.class, "MantisQueryPanel.menuMarkAsUnRead")); markAsUnRead.setEnabled(statusProvider.getStatus(issue) == IssueStatusProvider.Status.SEEN); markAsUnRead.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { statusProvider.setSeenIncoming(issue, false); } }); menu.add(openItem); menu.add(markAsRead); menu.add(markAsUnRead); menu.show(e.getComponent(), e.getX(), e.getY()); } } @Override public void mousePressed(MouseEvent e) { } @Override public void mouseReleased(MouseEvent e) { } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } @Override public void keyTyped(KeyEvent e) { } @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER) { e.consume(); } } @Override public void keyReleased(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER) { int viewRow = mqp.issueTable.getSelectedRow(); if (viewRow == -1) { return; } int modelRow = mqp.issueTable.convertRowIndexToModel(viewRow); MantisIssue mi = mqp.getQueryListModel().getIssue(modelRow); Mantis.getInstance().getBugtrackingSupport().openIssue( mi.getMantisRepository(), mi); e.consume(); } } } IssueTableIssueOpener issueTableIssueOpener = new IssueTableIssueOpener(); static { pseudoProject = new ProjectData(); pseudoProject.setAccess_min(new ObjectRef(BigInteger.ZERO, "None")); pseudoProject.setDescription(""); pseudoProject.setId(BigInteger.ZERO); pseudoProject.setName("All"); } public MantisQueryController(final MantisQuery mq) { this.mq = mq; this.mr = mq.getMantisRepository(); Runnable initializer = new Runnable() { @Override public void run() { try (SafeAutocloseable ac = mq.busy()) { final FilterData[] filter = mr.getMasterData().getFilters(mq.getProjectId()); final List<FlattenedProjectData> projects = new ArrayList<>(); projects.add(new FlattenedProjectData(pseudoProject, 0)); for (ProjectData pd : mr.getMasterData().getProjects()) { projects.addAll(FlattenedProjectData.buildList(pd)); } final List<AccountData> users = new ArrayList<>( Arrays.asList(mr.getMasterData().getUsers(BigInteger.ZERO))); users.add(0, null); final List<String> categories = new ArrayList<>( Arrays.asList(mr.getMasterData().getCategories(BigInteger.ZERO))); categories.add(0, null); final List<ObjectRef> severities = new ArrayList<>( Arrays.asList(mr.getMasterData().getSeverities())); severities.add(0, null); final List<ObjectRef> resolutions = new ArrayList<>( Arrays.asList(mr.getMasterData().getResolutions())); resolutions.add(0, null); final List<ObjectRef> states = new ArrayList<>( Arrays.asList(mr.getMasterData().getStates())); states.add(0, null); final List<ObjectRef> priorities = new ArrayList<>( Arrays.asList(mr.getMasterData().getPriorities())); priorities.add(0, null); final List<ObjectRef> viewstates = new ArrayList<>( Arrays.asList(mr.getMasterData().getViewStates())); viewstates.add(0, null); Mutex.EVENT.writeAccess(new Mutex.Action<Void>() { @Override public Void run() { reporterModel.setBackingList(users); assignedToModel.setBackingList(users); categoryModel.setBackingList(categories); severityModel.setBackingList(severities); resolutionModel.setBackingList(resolutions); statusModel.setBackingList(states); priorityModel.setBackingList(priorities); viewstatusModel.setBackingList(viewstates); projectModel1.setBackingList(projects); projectModel1.setSelectedItem(new FlattenedProjectData( pseudoProject, 0)); reporterModel.setSelectedItem(mq.getReporter()); assignedToModel.setSelectedItem(mq.getAssignedTo()); categoryModel.setSelectedItem(mq.getCategory()); severityModel.setSelectedItem(mq.getSeverity()); resolutionModel.setSelectedItem(mq.getResolution()); statusModel.setSelectedItem(mq.getStatus()); priorityModel.setSelectedItem(mq.getPriority()); viewstatusModel.setSelectedItem(mq.getViewStatus()); if (mq.getProjectId() != null) { FlattenedProjectData foundFpd = null; for (FlattenedProjectData fpd : projects) { if (fpd.getProjectData().getId().equals( mq.getProjectId())) { projectModel1.setSelectedItem(fpd); break; } } } if (filter != null) { filterModel1.setBackingList(Arrays.asList(filter)); filterModel1.addElement(0, null); } if (mq.getServersideFilterId() != null) { for (FilterData fd : filterModel1.getBackingList()) { if (mq.getServersideFilterId().equals(fd.getId())) { filterModel1.setSelectedItem(fd); break; } } } if (mqp != null) { mqp.lastUpdateAfterDatePicker.setDate( mq.getLastUpdateAfter()); mqp.lastUpdateBeforeDatePicker.setDate( mq.getLastUpdateBefore()); mqp.summaryTextField.setText(mq.getSummaryFilter()); if (mq.getCombination() == MantisQuery.Combination.ANY) { mqp.matchTypeComboBox.setSelectedIndex(1); } } return null; } }); } catch (Exception ex) { mq.getMantisRepository() .getExceptionHandler() .handleException(logger, "Failed to update", ex); } } }; this.mr.getRequestProcessor().execute(initializer); } private void onSaveState() { if (mq.isSaved()) { mqp.gotoIssuePanel.setVisible(false); mqp.headerButtonsPanel.setVisible(true); } else { mqp.gotoIssuePanel.setVisible(true); mqp.headerButtonsPanel.setVisible(false); } } private final Runnable updateProjectDependendLists = new Runnable() { // @todo: also update the other lists that are project dependend @Override public void run() { try (SafeAutocloseable saf = mq.busy()) { FlattenedProjectData selected = Mutex.EVENT.writeAccess( new Mutex.Action<FlattenedProjectData>() { @Override public FlattenedProjectData run() { return (FlattenedProjectData) projectModel1.getSelectedItem(); } }); final Holder<FilterData[]> filter = new Holder<>(); if (selected != null) { filter.value = mr.getMasterData().getFilters( selected.getProjectData().getId()); } Mutex.EVENT.writeAccess(new Mutex.Action<Void>() { @Override public Void run() { if (filter != null) { filterModel1.setBackingList(Arrays.asList(filter.value)); filterModel1.addElement(0, null); } else { filterModel1.setBackingList(Collections.EMPTY_LIST); } return null; } }); } catch (Exception ex) { mq.getMantisRepository() .getExceptionHandler() .handleException(logger, "Failed to retrieve filterlist", ex); } } }; @Override public HelpCtx getHelpCtx() { return new HelpCtx(getClass().getName()); } @Override public void actionPerformed(ActionEvent e) { if (null != e.getActionCommand()) switch (e.getActionCommand()) { case COMMAND_OPEN_ISSUE: gotoIssue(); break; case COMMAND_SELECT_PROJECT1: mr.getRequestProcessor().execute(updateProjectDependendLists); break; case COMMAND_SAVE_QUERY: if (mq.getName() == null || mq.getName().isEmpty()) { NotifyDescriptor.InputLine nd = new NotifyDescriptor.InputLine( "Name", "Save query"); DialogDisplayer.getDefault().notify(nd); mq.setName((String) nd.getInputText()); } new SwingWorker<Collection<MantisIssue>, Object>() { @Override protected Collection<MantisIssue> doInBackground() throws Exception { try (SafeAutocloseable ac = mq.busy()) { mq.save(); mq.refresh(); return mq.getIssues(); } } @Override protected void done() { try { getComponent(QueryMode.VIEW).getQueryListModel().setIssues(get()); } catch (InterruptedException | ExecutionException ex) { logger.log(Level.WARNING, "Failed to save query", ex); } } }.execute(); break; case COMMAND_DELETE_QUERY: new SwingWorker() { @Override protected Object doInBackground() throws Exception { mq.remove(); return null; } @Override protected void done() { try { get(); } catch (InterruptedException | ExecutionException ex) { logger.log(Level.WARNING, "Failed to delete query", ex); } } }.execute(); break; case COMMAND_EXECUTE_QUERY: if (projectModel1.getSelectedItem() != null) { mq.setProjectId( ((FlattenedProjectData) projectModel1.getSelectedItem()).getProjectData().getId()); } else { mq.setProjectId(null); } if (filterModel1.getSelectedItem() != null) { mq.setServersideFilterId( ((FilterData) filterModel1.getSelectedItem()).getId()); } else { mq.setServersideFilterId(null); } mq.setReporter((AccountData) reporterModel.getSelectedItem()); mq.setAssignedTo((AccountData) assignedToModel.getSelectedItem()); mq.setCategory((String) categoryModel.getSelectedItem()); mq.setSeverity((ObjectRef) severityModel.getSelectedItem()); mq.setResolution((ObjectRef) resolutionModel.getSelectedItem()); mq.setStatus((ObjectRef) statusModel.getSelectedItem()); mq.setPriority((ObjectRef) priorityModel.getSelectedItem()); mq.setViewStatus((ObjectRef) viewstatusModel.getSelectedItem()); mq.setLastUpdateAfter(mqp.lastUpdateAfterDatePicker.getDate()); mq.setLastUpdateBefore(mqp.lastUpdateBeforeDatePicker.getDate()); if (mqp.matchTypeComboBox.getSelectedIndex() == 1) { mq.setCombination(MantisQuery.Combination.ANY); } else { mq.setCombination(MantisQuery.Combination.ALL); } mq.setSummaryFilter(mqp.summaryTextField.getText()); SwingWorker sw = new SwingWorker<Collection<MantisIssue>,Object>() { @Override protected Collection<MantisIssue> doInBackground() throws Exception { try (SafeAutocloseable ac = mq.busy()) { mq.refresh(); return mq.getIssues(); } } @Override protected void done() { try { getComponent(QueryMode.VIEW).getQueryListModel().setIssues(get()); } catch (InterruptedException | ExecutionException ex) { Exceptions.printStackTrace(ex); } } }; sw.execute(); break; default: } } private void gotoIssue() { getComponent(QueryMode.VIEW); // Make sure component exists Runnable r = new Runnable() { @Override public void run() { try { MantisIssue mi = mq.getMantisRepository(). getIssues(false, mqp.gotoIssueTextField.getText()).get(0); Mantis.getInstance().getBugtrackingSupport().openIssue( mq.getMantisRepository(), mi); } catch (ServiceException | RemoteException | RuntimeException ex) { mq.getMantisRepository() .getExceptionHandler() .handleException(logger, "Failed to open issue", ex); } } }; rp.submit(r); } @Override public void propertyChange(PropertyChangeEvent evt) { if ("busy".equals(evt.getPropertyName()) && mqp != null) { mqp.waitPanel.setVisible((Boolean) evt.getNewValue()); } } @Override public boolean providesMode(QueryMode mode) { return mode == QueryMode.EDIT; } @Override public MantisQueryPanel getComponent(QueryMode mode) { if (mqp == null) { mqp = new MantisQueryPanel(); mqp.projectComboBox.setModel(projectModel1); mqp.projectComboBox.addActionListener(this); mqp.projectComboBox.setActionCommand(COMMAND_SELECT_PROJECT1); mqp.reporterComboBox.setModel(reporterModel); mqp.assignedToComboBox.setModel(assignedToModel); mqp.categoryComboBox.setModel(categoryModel); mqp.severityComboBox.setModel(severityModel); mqp.resolutionComboBox.setModel(resolutionModel); mqp.statusComboBox.setModel(statusModel); mqp.priorityComboBox.setModel(priorityModel); mqp.viewStatusComboBox.setModel(viewstatusModel); mqp.gotoIssueButton.setActionCommand(COMMAND_OPEN_ISSUE); mqp.gotoIssueButton.addActionListener(this); mqp.gotoIssueTextField.setActionCommand(COMMAND_OPEN_ISSUE); mqp.gotoIssueTextField.addActionListener(this); mqp.filterComboBox.setModel(filterModel1); mqp.executeQueryButton.addActionListener(this); mqp.saveQueryButton.addActionListener(this); mqp.deleteQueryLinkButton.addActionListener(this); mq.addPropertyChangeListener(this); mqp.waitPanel.setVisible(mq.isBusy()); mqp.lastUpdateAfterDatePicker.setDate(mq.getLastUpdateAfter()); mqp.lastUpdateBeforeDatePicker.setDate(mq.getLastUpdateBefore()); mqp.summaryTextField.setText(mq.getSummaryFilter()); if (mq.getCombination() == MantisQuery.Combination.ANY) { mqp.matchTypeComboBox.setSelectedIndex(1); } mqp.issueTable.addMouseListener(issueTableIssueOpener); mqp.issueTable.addKeyListener(issueTableIssueOpener); onSaveState(); } return mqp; } @Override public void opened() { } @Override public void closed() { } @Override public boolean saveChanges(String name) { mq.save(); return true; } @Override public boolean discardUnsavedChanges() { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } @Override public boolean isChanged() { return !mq.isSaved(); } @Override public void addPropertyChangeListener(PropertyChangeListener l) { mq.addPropertyChangeListener(l); } @Override public void removePropertyChangeListener(PropertyChangeListener l) { mq.removePropertyChangeListener(l); } }