package com.kenai.redminenb.project;
import com.kenai.redminenb.util.ActionListenerPanel;
import com.kenai.redminenb.util.ExceptionHandler;
import com.taskadapter.redmineapi.RedmineException;
import java.awt.event.ActionEvent;
import java.util.regex.Pattern;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import org.openide.util.NbBundle;
import com.taskadapter.redmineapi.RedmineManager;
import com.taskadapter.redmineapi.bean.Project;
import com.taskadapter.redmineapi.bean.ProjectFactory;
import java.awt.Color;
import java.awt.Dimension;
import java.util.logging.Logger;
import javax.swing.GroupLayout;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.LayoutStyle;
/**
*
* @author Mykolas
*/
public class RedmineProjectPanel extends ActionListenerPanel implements DocumentListener {
private static final Logger LOG = Logger.getLogger(RedmineProjectPanel.class.getName());
private static final Pattern IDENTIFIER_PATTERN = Pattern.compile("[a-z0-9_]{1,100}");
//
private final RedmineManager redmineManager;
private String projectName;
private String description;
private String identifier;
private String errorMessage;
/**
* Creates new form RedmineProjectPanel
*/
public RedmineProjectPanel(RedmineManager redmineManager) {
this.redmineManager = redmineManager;
initComponents();
nameTextField.getDocument().addDocumentListener(this);
descriptionTextArea.getDocument().addDocumentListener(this);
identifierTextField.getDocument().addDocumentListener(this);
errorLabel.setVisible(false);
}
public String getProjectName() {
return projectName;
}
public String getDescription() {
return description;
}
public String getIdentifier() {
return identifier;
}
private boolean isProjectError() {
projectName = nameTextField.getText().trim();
if (projectName.isEmpty()) {
errorMessage = "The name is invalid";
return true;
}
description = descriptionTextArea.getText().trim();
identifier = identifierTextField.getText().trim();
if (!IDENTIFIER_PATTERN.matcher(identifier).matches()) {
errorMessage = "<html>Identifier length is between 1 and 100 characters. <br/>"
+ "Only lower case letters (a-z), numbers and dashes are allowed.</html>";
return true;
}
return false;
}
private boolean isProjectValid() {
if (!isProjectError()) {
errorLabel.setText(null);
errorLabel.setVisible(false);
return true;
}
errorLabel.setText(errorMessage);
errorLabel.setVisible(true);
return false;
}
private boolean createNewProject() {
final Project project = ProjectFactory.create();
project.setName(projectName);
project.setDescription(description);
project.setIdentifier(identifier);
try {
redmineManager.getProjectManager().createProject(project);
return true;
} catch (RedmineException | RuntimeException ex) {
ExceptionHandler.handleException(LOG, "Failed to create project", ex);
}
errorLabel.setText(errorMessage);
errorLabel.setVisible(true);
return false;
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == okButton && dialogDescribtor != null) {
if (isProjectValid()) {
if (createNewProject()) {
dialogDescribtor.setClosingOptions(new Object[]{okButton, cancelButton});
}
} else {
dialogDescribtor.setClosingOptions(new Object[]{cancelButton});
}
}
}
@Override
public void insertUpdate(DocumentEvent e) {
isProjectValid();
}
@Override
public void removeUpdate(DocumentEvent e) {
isProjectValid();
}
@Override
public void changedUpdate(DocumentEvent e) {
isProjectValid();
}
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
nameLabel = new JLabel();
identifierLabel = new JLabel();
descriptionLabel = new JLabel();
nameTextField = new JTextField();
identifierTextField = new JTextField();
jScrollPane1 = new JScrollPane();
descriptionTextArea = new JTextArea();
errorLabel = new JLabel();
nameLabel.setText(NbBundle.getMessage(RedmineProjectPanel.class, "RedmineProjectPanel.nameLabel.text")); // NOI18N
identifierLabel.setText(NbBundle.getMessage(RedmineProjectPanel.class, "RedmineProjectPanel.identifierLabel.text")); // NOI18N
descriptionLabel.setText(NbBundle.getMessage(RedmineProjectPanel.class, "RedmineProjectPanel.descriptionLabel.text")); // NOI18N
nameTextField.setText(NbBundle.getMessage(RedmineProjectPanel.class, "RedmineProjectPanel.nameTextField.text")); // NOI18N
identifierTextField.setText(NbBundle.getMessage(RedmineProjectPanel.class, "RedmineProjectPanel.identifierTextField.text")); // NOI18N
descriptionTextArea.setColumns(20);
descriptionTextArea.setRows(5);
jScrollPane1.setViewportView(descriptionTextArea);
errorLabel.setForeground(new Color(153, 0, 0));
errorLabel.setIcon(new ImageIcon(getClass().getResource("/com/kenai/redminenb/resources/error.png"))); // NOI18N
errorLabel.setText(NbBundle.getMessage(RedmineProjectPanel.class, "RedmineProjectPanel.errorLabel.text")); // NOI18N
errorLabel.setMaximumSize(new Dimension(407, 16));
GroupLayout layout = new GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING)
.addComponent(errorLabel, GroupLayout.Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 407, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(nameLabel)
.addComponent(descriptionLabel)
.addComponent(identifierLabel))
.addGap(15, 15, 15)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING)
.addComponent(identifierTextField, GroupLayout.DEFAULT_SIZE, 324, Short.MAX_VALUE)
.addComponent(jScrollPane1, GroupLayout.DEFAULT_SIZE, 324, Short.MAX_VALUE)
.addComponent(nameTextField, GroupLayout.Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 324, Short.MAX_VALUE))))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(nameLabel)
.addComponent(nameTextField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(descriptionLabel)
.addComponent(jScrollPane1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(identifierTextField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addComponent(identifierLabel))
.addGap(18, 18, 18)
.addComponent(errorLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addContainerGap(33, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private JLabel descriptionLabel;
private JTextArea descriptionTextArea;
private JLabel errorLabel;
private JLabel identifierLabel;
private JTextField identifierTextField;
private JScrollPane jScrollPane1;
private JLabel nameLabel;
private JTextField nameTextField;
// End of variables declaration//GEN-END:variables
}