I'm trying to make generic a form design. One of the components is a class that is a Panel for the details...
package net.draconia.test.ui;
import java.awt.BorderLayout;
import java.awt.LayoutManager;
import java.util.Observable;
import javax.annotation.PostConstruct;
import javax.swing.Action;
import javax.swing.JPanel;
import net.draconia.test.ui.model.DetailsPanelModel;
import org.springframework.beans.factory.annotation.Autowired;
public abstract class DetailsPanel<ModelType extends Observable> extends EnablablePanel
{
private static final long serialVersionUID = -9083062930871602527L;
private Action[] mArrButtonActions;
private ButtonsPanel mPnlButtons;
@Autowired
private DetailsPanelModel<ModelType> mObjModel;
public DetailsPanel(final LayoutManager objLayoutManager)
{
this(objLayoutManager, null, null);
}
public DetailsPanel(final LayoutManager objLayoutManager, final Action[] arrButtonActions)
{
this(objLayoutManager, arrButtonActions, null);
}
public DetailsPanel(final LayoutManager objLayoutManager, final Action[] arrButtonActions, final ModelType objModel)
{
super(objLayoutManager);
setButtonActions(arrButtonActions);
getModel().setModel(objModel);
}
protected Action[] getButtonActions()
{
return(mArrButtonActions);
}
protected ButtonsPanel getButtonsPanel()
{
return(mPnlButtons);
}
protected abstract JPanel getFieldsPanel();
public DetailsPanelModel<ModelType> getModel()
{
return(mObjModel);
}
@PostConstruct
protected void initPanel()
{
add(getFieldsPanel(), BorderLayout.NORTH);
add(getButtonsPanel(), BorderLayout.SOUTH);
}
protected void setButtonActions(final Action[] arrButtonActions)
{
mArrButtonActions = arrButtonActions;
if(getButtonsPanel() != null)
getButtonsPanel().setButtons(mArrButtonActions);
}
protected void setButtonsPanel(final ButtonsPanel pnlButtons)
{
mPnlButtons = pnlButtons;
mPnlButtons.setButtons(getButtonActions());
}
protected void setModel(final DetailsPanelModel<ModelType> objModel)
{
mObjModel = objModel;
}
}
More specific though there's a class ScheduleDetailsPanel which is just DetailsPanel. It is not abstract and defines a method definition for getFieldPanel().
package net.draconia.test.ui;
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.KeyEvent;
import javax.annotation.PostConstruct;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import net.draconia.ApplicationContextProvider;
import net.draconia.test.model.Schedule;
import net.draconia.test.ui.actions.Apply;
import net.draconia.test.ui.actions.Cancel;
import net.draconia.test.ui.actions.Save;
import net.draconia.test.ui.model.DetailsPanelModel;
import net.draconia.test.ui.model.ScheduleDetailsPanelModel;
@Component
public class ScheduleDetailsPanel extends DetailsPanel<Schedule>
{
private static final long serialVersionUID = -3654518916162120544L;
@Autowired
private Apply<Schedule> mActApply;
@Autowired
private Cancel<Schedule> mActCancel;
private JLabel mLblId, mLblName;
private JTextField mTxtId, mTxtName;
@Autowired
private Save<Schedule> mActSave;
public ScheduleDetailsPanel()
{
super(new BorderLayout(5, 5));
setButtonActions(new Action[] {getApplyAction(), getSaveAction(), getCancelAction()});
}
protected Apply<Schedule> getApplyAction()
{
return(mActApply);
}
protected Cancel<Schedule> getCancelAction()
{
return(mActCancel);
}
protected JPanel getFieldsPanel()
{
EnablablePanel pnlFields = new EnablablePanel(new GridBagLayout());
return(pnlFields);
}
protected JTextField getIdField()
{
return(mTxtId);
}
protected JLabel getIdLabel()
{
return(mLblId);
}
protected JTextField getNameField()
{
return(mTxtName);
}
protected JLabel getNameLabel()
{
return(mLblName);
}
protected Save<Schedule> getSaveAction()
{
return(mActSave);
}
@PostConstruct
protected void initPanel()
{
GridBagConstraints objConstraints = new GridBagConstraints();
objConstraints.gridx = objConstraints.gridy = 0;
objConstraints.gridwidth = objConstraints.gridheight = 1;
objConstraints.fill = GridBagConstraints.BOTH;
objConstraints.anchor = GridBagConstraints.NORTHWEST;
objConstraints.insets = new Insets(5, 5, 5, 5);
add(getIdLabel(), objConstraints);
objConstraints.gridx++;
add(getIdField(), objConstraints);
objConstraints.gridx = 0;
objConstraints.gridy++;
add(getNameLabel(), objConstraints);
objConstraints.gridx++;
add(getNameField(), objConstraints);
}
protected void setApplyAction(final Apply<Schedule> actApply)
{
mActApply = actApply;
}
protected void setCancelAction(final Cancel<Schedule> actCancel)
{
mActCancel = actCancel;
}
@Autowired
@Qualifier("selectScheduleDialogDetailsId")
protected void setIdField(final JTextField txtId)
{
mTxtId = txtId;
mTxtId.setBorder(BorderFactory.createLoweredBevelBorder());
mTxtId.setEditable(false);
mTxtId.setFont(getFont());
}
@Autowired
@Qualifier("selectScheduleDialogDetailsIdLabel")
protected void setIdLabel(final JLabel lblId)
{
mLblId = lblId;
mLblId.setDisplayedMnemonic(KeyEvent.VK_I);
mLblId.setFont(getFont().deriveFont(Font.BOLD));
mLblId.setLabelFor(getIdField());
mLblId.setOpaque(false);
}
@Autowired
@Qualifier("selectScheduleDialogDetailsName")
protected void setNameField(final JTextField txtName)
{
mTxtName = txtName;
mTxtName.setBorder(BorderFactory.createLoweredBevelBorder());
mTxtName.setEditable(false);
mTxtName.setFont(getFont());
}
@Autowired
@Qualifier("selectScheduleDialogDetailsNameLabel")
protected void setNameLabel(final JLabel lblName)
{
mLblName = lblName;
mLblName.setDisplayedMnemonic(KeyEvent.VK_N);
mLblName.setFont(getFont().deriveFont(Font.BOLD));
mLblName.setLabelFor(getNameField());
mLblName.setOpaque(false);
}
protected void setSaveAction(final Save<Schedule> actSave)
{
mActSave = actSave;
}
}
The structure of Schedule is somewhat irrelevant but for the cases of this test and everythin gin general right now, it's just an Id which is an integer and a Name which is a String but it's taken from a larger project which I plan to reintegrate when I get this working.
What is happening is - If you see - in the Detailspanel abstract class, mObjModel has @Autowired before it but it ends up being null later. What gives? Is it because DetailsPanelModel is an abstract class? The only reason I suspected that was because I put an ApplicationContextProvider class that was ApplicationContextAware and autowired that and that ALSO was null so I didn't know what was going on. I'm trying to get the common functionality in the base class and the specific functionality in the child class of course as proper OOP is designed. Please assist.