~~NOTRANS~~ ~~Title: Replace the Login dialog~~ It's possible to customize the standard login dialog a little bit as described in [[vaadin:customize_login|this article]]. If you want full control of the login dialog, it's better to replace the dialog with a custom one. In our example, we'll create a login dialog with additional buttons to do custom authentication steps, e.g. {{:vaadin:login_custom.png?nolink|}} If you use the **standard application layout**, do following: In your web.xml (WebContent/WEB-INF directory), search: main com.sibvisions.apps.projx.ProjX and replace it with: main com.sibvisions.apps.customlogin.MyCustomApplication If you use the **corporation application layout**, do following: In your web.xml (WebContent/WEB-INF directory), search: com.sibvisions.rad.ui.vaadin.server.VaadinServlet and add the following: Application.Login.corporation.classname com.sibvisions.apps.customlogin.MyCustomLogin Finally, let us create the source files (in //src.server// folder): * com.sibvisions.apps.customlogin.**MyCustomApplication** (only for standard layout mode, but also works in corporation mode) * com.sibvisions.apps.customlogin.**MyCustomLogin** The Application simply creates the login, e.g.: package com.sibvisions.apps.customlogin; import javax.rad.application.genui.UILauncher; import com.sibvisions.apps.projx.ILogin; import com.sibvisions.apps.projx.ProjX; public class MyCustomApplication extends ProjX { public MyCustomApplication(UILauncher pLauncher) throws Throwable { super(pLauncher); } @Override protected ILogin createLogin() throws Throwable { if (getLauncher().isWebEnvironment()) { return new MyCustomLogin(); } return super.createLogin(); } } We'll use our custom login, only in web environment. This is all. The login class contains a little bit more code: package com.sibvisions.apps.customlogin; import javax.rad.genui.component.UIButton; import javax.rad.genui.container.UIPanel; import javax.rad.genui.layout.UIFormLayout; import javax.rad.ui.Style; import com.sibvisions.apps.vaadin.web.WebLogin; import com.vaadin.ui.Component; import com.vaadin.ui.CssLayout; public class MyCustomLogin extends WebLogin { private UIPanel panCustomButtons; @Override protected void createLogin() { super.createLogin(); updateUI(); } @Override protected void handleLoginError(Throwable pException) { super.handleLoginError(pException); //important, because the error area will be added dynamically updateUI(); } private void updateUI() { if (!isChangePassword()) { CssLayout cssl = (CssLayout)getInfoLabel().getParent().getParent(); //cleanup if (panCustomButtons != null) { cssl.removeComponent((Component)panCustomButtons.getResource()); } else { UIFormLayout flCustomButtons = new UIFormLayout(); //flCustomButtons.setHorizontalAlignment(IAlignmentConstants.ALIGN_CENTER); flCustomButtons.setMargins(10, 18, 5, 18); flCustomButtons.setHorizontalGap(10); panCustomButtons = new UIPanel(flCustomButtons); UIButton butISA = new UIButton("ISA"); butSAM.eventAction().addListener(this, "doISA"); Style.addStyleNames(butISA, "default", "isa"); UIButton butSAM = new UIButton("SAM"); butSAM.eventAction().addListener(this, "doSAM"); Style.addStyleNames(butSAM, "default", "sam"); panCustomButtons.add(butISA, flCustomButtons.getConstraints(0, 0)); panCustomButtons.add(butSAM, flCustomButtons.getConstraints(1, 0)); } //always above the "error area" cssl.addComponent((Component)panCustomButtons.getResource(), 2); } } public void doISA() throws Throwable { ((RemoteApplication)getApplication()).showInformation(null, "ISA pressed!"); } public void doSAM() throws Throwable { ((RemoteApplication)getApplication()).showInformation(null, "SAM pressed!"); } } Our code adds two new buttons and adds shows an information if one of the two buttons were pressed. The stylesheet definition for the new buttons are: .loginwindow .default.v-button.isa { background: red; border-color: darkred; } .loginwindow .default.v-button.isa.v-pressed, .loginwindow .default.v-button.isa:active { background: red; border-color: darkred; } .loginwindow .default.v-button.isa:focus { border-color: darkred; box-shadow: 0 0 4px darkred; } .v-button.isa:focus:after { border-color: darkred; box-shadow: none; } .loginwindow .default.v-button.sam { background: green; border-color: darkgreen; } .loginwindow .default.v-button.sam.v-pressed, .loginwindow .default.v-button.sam:active { background: green; border-color: dargreen; } .loginwindow .default.v-button.sam:focus { border-color: darkgreen; box-shadow: 0 0 4px darkgreen; } .v-button.sam:focus:after { border-color: darkgren; box-shadow: none; } If you want to create a complete new layout for the login dialog, simply write your own code in **createLogin** method and don't call **super.createLogin()**. The **createLogin** method of WebLogin: protected void createLogin() { sNewPassword = null; sConfirmPassword = null; boolean bChangePwd = isChangePassword(); cslayLoginPanel = new CssLayout(); cslayLoginPanel.addStyleName("login-panel"); cslayLoginPanel.setSizeFull(); layoutMode = getLayoutMode(); boolean bMini = layoutMode == LayoutMode.Mini; if (bMini) { winLogin.addStyleName("small"); cslayLoginPanel.addStyleName("small"); } else { winLogin.removeStyleName("small"); } //---------------------------------------------------------------------------- // Header //---------------------------------------------------------------------------- lblTitle = new Label(); lblTitle.setSizeUndefined(); lblTitle.addStyleName("welcome"); lblInfo = new Label(); lblInfo.setSizeUndefined(); lblInfo.addStyleName("info"); lblError = new Label(); lblError.setSizeUndefined(); lblError.addStyleName("welcomerror"); VerticalLayout vlayLabels = new VerticalLayout(); vlayLabels.setSpacing(false); vlayLabels.setWidth("100%"); vlayLabels.setSizeUndefined(); vlayLabels.setMargin(true); vlayLabels.addStyleName("labels"); vlayLabels.addComponent(lblTitle); vlayLabels.addComponent(lblError); if (!bMini) { vlayLabels.addComponent(lblInfo); } //---------------------------------------------------------------------------- // Username and Password //---------------------------------------------------------------------------- AbstractOrderedLayout aolFields; if (bMini) { aolFields = new VerticalLayout(); } else { aolFields = new HorizontalLayout(); } aolFields.setSpacing(true); aolFields.setMargin(true); aolFields.addStyleName("fields"); tfUserName = new TextField(projx.translate("Username")); tfUserName.setIcon(VaadinIcons.USER); tfUserName.setId("UserName"); tfUserName.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON); if (sUserName != null) { tfUserName.setValue(sUserName); } pfPassword = new PasswordField(); if (bChangePwd) { pfPassword.setIcon(VaadinIcons.UNLOCK); } else { pfPassword.setIcon(VaadinIcons.LOCK); } pfPassword.setId("Password"); pfPassword.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON); if (sPassword != null) { pfPassword.setValue(sPassword); } butLogin = new Button(); butLogin.addStyleName("default"); butLogin.addStyleName("ok"); butLogin.setId("OK"); if (bChangePwd) { butLogin.setCaption(projx.translate("Change")); } else { butLogin.setCaption(projx.translate("Login")); } aolFields.addComponent(tfUserName); aolFields.addComponent(pfPassword); if (sUserName == null) { tfUserName.focus(); } else { pfPassword.focus(); } //---------------------------------------------------------------------------- // New Password and Confirm Password //---------------------------------------------------------------------------- AbstractOrderedLayout aolPasswordFields; if (bChangePwd) { lblTitle.setValue(projx.translate(CHANGE_PASSWORD)); pfPassword.setCaption(projx.translate("Old Password")); if (bMini) { aolPasswordFields = new VerticalLayout(); } else { aolPasswordFields = new HorizontalLayout(); } aolPasswordFields.setSpacing(true); aolPasswordFields.setMargin(true); aolPasswordFields.addStyleName("fields"); aolPasswordFields.addStyleName("passwordfields"); pfNewPassword = new PasswordField(projx.translate("New Password")); pfNewPassword.setId("PasswordNew"); pfNewPassword.setIcon(VaadinIcons.LOCK); pfNewPassword.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON); if (sNewPassword != null) { pfNewPassword.setValue(sNewPassword); } pfPassword.focus(); pfConfirmPassword = new PasswordField(projx.translate("Confirm Password")); pfConfirmPassword.setId("PasswordConfirm"); pfConfirmPassword.setIcon(VaadinIcons.LOCK); pfConfirmPassword.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON); AbstractOrderedLayout aolButtons; if (bMini) { aolButtons = new HorizontalLayout(); aolButtons.addStyleName("nopadding"); aolButtons.setSpacing(true); aolButtons.setMargin(false); aolButtons.setSizeFull(); } else { aolButtons = aolPasswordFields; } butCancel = new Button(projx.translate("Cancel")); butCancel.addStyleName("default"); butCancel.addStyleName("cancel"); butCancel.setId("Cancel"); aolPasswordFields.addComponent(pfNewPassword); aolPasswordFields.addComponent(pfConfirmPassword); aolButtons.addComponent(butLogin); aolButtons.setComponentAlignment(butLogin, Alignment.BOTTOM_LEFT); Label lblOr = new Label(projx.translate("or"), ContentMode.HTML); lblOr.addStyleName("or"); if (!bMini) { aolButtons.addComponent(lblOr); aolButtons.setComponentAlignment(lblOr, Alignment.BOTTOM_LEFT); } aolButtons.addComponent(butCancel); if (bMini) { aolButtons.setComponentAlignment(butCancel, Alignment.BOTTOM_RIGHT); } else { aolButtons.setComponentAlignment(butCancel, Alignment.BOTTOM_LEFT); } if (aolButtons != aolPasswordFields) { aolPasswordFields.addComponent(aolButtons); } if (projx.isConnected()) { lblInfo.setValue(projx.translate("Please enter and confirm the new password.")); tfUserName.setEnabled(false); } else { if (projx.isForceChangePassword()) { lblInfo.setValue(projx.translate("Please enter and confirm the new password.")); tfUserName.setEnabled(false); pfPassword.setEnabled(false); } else { lblInfo.setValue(projx.translate("Please enter your username and passwords.")); } } ShortcutListener sclEsc = new ShortcutListener(projx.translate("Cancel"), KeyCode.ESCAPE, null) { public void handleAction(Object pSender, Object pTarget) { doCancel(); } }; butCancel.addClickListener(new ClickListener() { public void buttonClick(ClickEvent event) { doCancel(); } }); butLogin.addShortcutListener(sclEsc); } else { pfPassword.setCaption(projx.translate("Password")); lblTitle.setValue(projx.translate(WELCOME)); lblInfo.setValue(projx.translate("Please enter your username and password.")); pfNewPassword = null; pfConfirmPassword = null; aolFields.addComponent(butLogin); aolFields.setComponentAlignment(butLogin, Alignment.BOTTOM_LEFT); aolPasswordFields = null; } //---------------------------------------------------------------------------- // ALL together //---------------------------------------------------------------------------- cslayLoginPanel.addComponent(vlayLabels); cslayLoginPanel.addComponent(aolFields); if (aolPasswordFields != null) { cslayLoginPanel.addComponent(aolPasswordFields); } ((CssLayout)winLogin.getContent()).addComponent(cslayLoginPanel); //---------------------------------------------------------------------------- // Event handling //---------------------------------------------------------------------------- ShortcutListener sclEnter = new ShortcutListener(projx.translate("Login"), KeyCode.ENTER, null) { public void handleAction(Object pSender, Object pTarget) { doOk(); } }; butLogin.addClickListener(new ClickListener() { public void buttonClick(ClickEvent event) { doOk(); } }); butLogin.addShortcutListener(sclEnter); updateError(); }