| /* |
| * Copyright 2000-2012 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.jetbrains.idea.maven.indices; |
| |
| import com.intellij.icons.AllIcons; |
| import com.intellij.openapi.options.BaseConfigurable; |
| import com.intellij.openapi.options.Configurable; |
| import com.intellij.openapi.options.ConfigurationException; |
| import com.intellij.openapi.options.SearchableConfigurable; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.ui.InputValidator; |
| import com.intellij.openapi.ui.Messages; |
| import com.intellij.openapi.util.Disposer; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.ui.CollectionListModel; |
| import com.intellij.ui.JBColor; |
| import com.intellij.ui.ListUtil; |
| import com.intellij.ui.components.JBList; |
| import com.intellij.ui.table.JBTable; |
| import com.intellij.util.Processor; |
| import com.intellij.util.text.DateFormatUtil; |
| import com.intellij.util.ui.AnimatedIcon; |
| import com.intellij.util.ui.AsyncProcessIcon; |
| import com.intellij.util.ui.UIUtil; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.idea.maven.model.MavenRepositoryInfo; |
| import org.jetbrains.idea.maven.services.MavenRepositoryServicesManager; |
| import org.jetbrains.idea.maven.utils.library.RepositoryAttachHandler; |
| |
| import javax.swing.*; |
| import javax.swing.event.ListSelectionEvent; |
| import javax.swing.event.ListSelectionListener; |
| import javax.swing.table.AbstractTableModel; |
| import javax.swing.table.DefaultTableCellRenderer; |
| import java.awt.*; |
| import java.awt.event.ActionEvent; |
| import java.awt.event.ActionListener; |
| import java.awt.event.MouseEvent; |
| import java.awt.event.MouseMotionListener; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.List; |
| |
| public class MavenRepositoriesConfigurable extends BaseConfigurable implements SearchableConfigurable, Configurable.NoScroll { |
| private final MavenProjectIndicesManager myManager; |
| |
| private JPanel myMainPanel; |
| private JBTable myIndicesTable; |
| private JButton myUpdateButton; |
| private JButton myRemoveButton; |
| private JButton myAddButton; |
| private JBList myServiceList; |
| private JButton myTestButton; |
| private JButton myEditButton; |
| |
| private AnimatedIcon myUpdatingIcon; |
| private Timer myRepaintTimer; |
| private ActionListener myTimerListener; |
| private final Project myProject; |
| private final CollectionListModel<String> myModel = new CollectionListModel<String>(); |
| |
| public MavenRepositoriesConfigurable(Project project) { |
| myProject = project; |
| myManager = MavenProjectIndicesManager.getInstance(project); |
| configControls(); |
| } |
| |
| @Override |
| public boolean isModified() { |
| return !myModel.getItems().equals(MavenRepositoryServicesManager.getInstance().getUrls()); |
| } |
| |
| private void configControls() { |
| myServiceList.setModel(myModel); |
| myServiceList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); |
| myAddButton.addActionListener(new ActionListener() { |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| final String value = (String)myServiceList.getSelectedValue(); |
| final String text = Messages.showInputDialog("Artifactory or Nexus Service URL", "Add Service URL", Messages.getQuestionIcon(), |
| value == null ? "http://" : value, new URLInputVaslidator()); |
| if (StringUtil.isNotEmpty(text)) { |
| myModel.add(text); |
| myServiceList.setSelectedValue(text, true); |
| } |
| } |
| }); |
| myEditButton.addActionListener(new ActionListener() { |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| final int index = myServiceList.getSelectedIndex(); |
| final String text = Messages.showInputDialog("Artifactory or Nexus Service URL", "Edit Service URL", Messages.getQuestionIcon(), |
| myModel.getElementAt(index), new URLInputVaslidator()); |
| if (StringUtil.isNotEmpty(text)) { |
| myModel.setElementAt(text, index); |
| } |
| } |
| }); |
| ListUtil.addRemoveListener(myRemoveButton, myServiceList); |
| ListUtil.disableWhenNoSelection(myTestButton, myServiceList); |
| ListUtil.disableWhenNoSelection(myEditButton, myServiceList); |
| myTestButton.addActionListener(new ActionListener() { |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| final String value = (String)myServiceList.getSelectedValue(); |
| if (value != null) { |
| testServiceConnection(value); |
| } |
| } |
| }); |
| |
| myUpdateButton.addActionListener(new ActionListener() { |
| public void actionPerformed(ActionEvent e) { |
| doUpdateIndex(); |
| } |
| }); |
| |
| myIndicesTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { |
| public void valueChanged(ListSelectionEvent e) { |
| updateButtonsState(); |
| } |
| }); |
| |
| myIndicesTable.addMouseMotionListener(new MouseMotionListener() { |
| public void mouseDragged(MouseEvent e) { |
| } |
| |
| public void mouseMoved(MouseEvent e) { |
| int row = myIndicesTable.rowAtPoint(e.getPoint()); |
| if (row == -1) return; |
| updateIndexHint(row); |
| } |
| }); |
| |
| myIndicesTable.setDefaultRenderer(Object.class, new MyCellRenderer()); |
| myIndicesTable.setDefaultRenderer(MavenIndicesManager.IndexUpdatingState.class, |
| new MyIconCellRenderer()); |
| |
| myServiceList.getEmptyText().setText("No services"); |
| myIndicesTable.getEmptyText().setText("No remote repositories"); |
| |
| updateButtonsState(); |
| } |
| |
| private void testServiceConnection(String url) { |
| myTestButton.setEnabled(false); |
| RepositoryAttachHandler.searchRepositories(myProject, Collections.singletonList(url), new Processor<Collection<MavenRepositoryInfo>>() { |
| @Override |
| public boolean process(Collection<MavenRepositoryInfo> infos) { |
| myTestButton.setEnabled(true); |
| if (infos.isEmpty()) { |
| Messages.showMessageDialog("No repositories found", "Service Connection Failed", Messages.getWarningIcon()); |
| } |
| else { |
| final StringBuilder sb = new StringBuilder(); |
| sb.append(infos.size()).append(infos.size() == 1 ? "repository" : " repositories").append(" found"); |
| //for (MavenRepositoryInfo info : infos) { |
| // sb.append("\n "); |
| // sb.append(info.getId()).append(" (").append(info.getName()).append(")").append(": ").append(info.getUrl()); |
| //} |
| Messages.showMessageDialog(sb.toString(), "Service Connection Successful", Messages.getInformationIcon()); |
| } |
| return true; |
| } |
| }); |
| } |
| |
| private void updateButtonsState() { |
| boolean hasSelection = !myIndicesTable.getSelectionModel().isSelectionEmpty(); |
| myUpdateButton.setEnabled(hasSelection); |
| } |
| |
| public void updateIndexHint(int row) { |
| MavenIndex index = getIndexAt(row); |
| String message = index.getFailureMessage(); |
| if (message == null) { |
| myIndicesTable.setToolTipText(null); |
| } |
| else { |
| myIndicesTable.setToolTipText(message); |
| } |
| } |
| |
| private void doUpdateIndex() { |
| myManager.scheduleUpdate(getSelectedIndices()); |
| } |
| |
| private List<MavenIndex> getSelectedIndices() { |
| List<MavenIndex> result = new ArrayList<MavenIndex>(); |
| for (int i : myIndicesTable.getSelectedRows()) { |
| result.add(getIndexAt(i)); |
| } |
| return result; |
| } |
| |
| private MavenIndex getIndexAt(int i) { |
| MyTableModel model = (MyTableModel)myIndicesTable.getModel(); |
| return model.getIndex(i); |
| } |
| |
| public String getDisplayName() { |
| return IndicesBundle.message("maven.repositories.title"); |
| } |
| |
| public String getHelpTopic() { |
| return "reference.settings.project.maven.repository.indices"; |
| } |
| |
| @NotNull |
| public String getId() { |
| return getHelpTopic(); |
| } |
| |
| public Runnable enableSearch(String option) { |
| return null; |
| } |
| |
| public JComponent createComponent() { |
| return myMainPanel; |
| } |
| |
| public void apply() throws ConfigurationException { |
| MavenRepositoryServicesManager.getInstance().setUrls(myModel.getItems()); |
| } |
| |
| public void reset() { |
| myModel.removeAll(); |
| myModel.add(MavenRepositoryServicesManager.getInstance().getUrls()); |
| |
| myIndicesTable.setModel(new MyTableModel(myManager.getIndices())); |
| myIndicesTable.getColumnModel().getColumn(0).setPreferredWidth(400); |
| myIndicesTable.getColumnModel().getColumn(1).setPreferredWidth(50); |
| myIndicesTable.getColumnModel().getColumn(2).setPreferredWidth(50); |
| myIndicesTable.getColumnModel().getColumn(3).setPreferredWidth(20); |
| |
| myUpdatingIcon = new AsyncProcessIcon(IndicesBundle.message("maven.indices.updating")); |
| myUpdatingIcon.resume(); |
| |
| myTimerListener = new ActionListener() { |
| public void actionPerformed(ActionEvent e) { |
| myIndicesTable.repaint(); |
| } |
| }; |
| myRepaintTimer = UIUtil.createNamedTimer("Maven repaint",AsyncProcessIcon.CYCLE_LENGTH / AsyncProcessIcon.COUNT, myTimerListener); |
| myRepaintTimer.start(); |
| } |
| |
| public void disposeUIResources() { |
| if (myRepaintTimer == null) return; // has not yet been initialized and reset |
| |
| myRepaintTimer.removeActionListener(myTimerListener); |
| myRepaintTimer.stop(); |
| Disposer.dispose(myUpdatingIcon); |
| } |
| |
| private class MyTableModel extends AbstractTableModel { |
| private final String[] COLUMNS = |
| new String[]{ |
| IndicesBundle.message("maven.index.url"), |
| IndicesBundle.message("maven.index.type"), |
| IndicesBundle.message("maven.index.updated"), |
| ""}; |
| |
| private final List<MavenIndex> myIndices; |
| |
| public MyTableModel(List<MavenIndex> indices) { |
| myIndices = indices; |
| } |
| |
| public int getColumnCount() { |
| return COLUMNS.length; |
| } |
| |
| @Override |
| public String getColumnName(int index) { |
| return COLUMNS[index]; |
| } |
| |
| public int getRowCount() { |
| return myIndices.size(); |
| } |
| |
| @Override |
| public Class<?> getColumnClass(int columnIndex) { |
| if (columnIndex == 3) return MavenIndicesManager.IndexUpdatingState.class; |
| return super.getColumnClass(columnIndex); |
| } |
| |
| public Object getValueAt(int rowIndex, int columnIndex) { |
| MavenIndex i = getIndex(rowIndex); |
| switch (columnIndex) { |
| case 0: |
| return i.getRepositoryPathOrUrl(); |
| case 1: |
| if (i.getKind() == MavenIndex.Kind.LOCAL) return "Local"; |
| return "Remote"; |
| case 2: |
| if (i.getFailureMessage() != null) { |
| return IndicesBundle.message("maven.index.updated.error"); |
| } |
| long timestamp = i.getUpdateTimestamp(); |
| if (timestamp == -1) return IndicesBundle.message("maven.index.updated.never"); |
| return DateFormatUtil.formatDate(timestamp); |
| case 3: |
| return myManager.getUpdatingState(i); |
| } |
| throw new RuntimeException(); |
| } |
| |
| public MavenIndex getIndex(int rowIndex) { |
| return myIndices.get(rowIndex); |
| } |
| } |
| |
| private class MyCellRenderer extends DefaultTableCellRenderer { |
| @Override |
| public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { |
| // reset custom colors and let DefaultTableCellRenderer to set ones |
| setForeground(null); |
| setBackground(null); |
| |
| Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); |
| |
| MavenIndex index = getIndexAt(row); |
| if (index.getFailureMessage() != null) { |
| if (isSelected) { |
| setForeground(JBColor.PINK); |
| } |
| else { |
| setBackground(JBColor.PINK); |
| } |
| } |
| |
| return c; |
| } |
| } |
| |
| private class MyIconCellRenderer extends MyCellRenderer { |
| MavenIndicesManager.IndexUpdatingState myState; |
| |
| @Override |
| public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { |
| myState = (MavenIndicesManager.IndexUpdatingState)value; |
| return super.getTableCellRendererComponent(table, "", isSelected, hasFocus, row, column); |
| } |
| |
| @Override |
| protected void paintComponent(Graphics g) { |
| super.paintComponent(g); |
| Dimension size = getSize(); |
| switch (myState) { |
| case UPDATING: |
| myUpdatingIcon.setBackground(getBackground()); |
| myUpdatingIcon.setSize(size.width, size.height); |
| myUpdatingIcon.paint(g); |
| break; |
| case WAITING: |
| int x = (size.width - AllIcons.Process.Step_passive.getIconWidth()) / 2; |
| int y = (size.height - AllIcons.Process.Step_passive.getIconHeight()) / 2; |
| AllIcons.Process.Step_passive.paintIcon(this, g, x, y); |
| break; |
| } |
| } |
| } |
| |
| private static class URLInputVaslidator implements InputValidator { |
| @Override |
| public boolean checkInput(String inputString) { |
| try { |
| final URL url = new URL(inputString); |
| return StringUtil.isNotEmpty(url.getHost()); |
| } |
| catch (MalformedURLException e) { |
| return false; |
| } |
| } |
| |
| @Override |
| public boolean canClose(String inputString) { |
| return checkInput(inputString); |
| } |
| } |
| } |