1 /* 2 * SourceControlPreferencesPane.java 3 * 4 * Copyright (C) 2021 by RStudio, PBC 5 * 6 * Unless you have received this program directly from RStudio pursuant 7 * to the terms of a commercial license agreement with RStudio, then 8 * this program is licensed to you under the terms of version 3 of the 9 * GNU Affero General Public License. This program is distributed WITHOUT 10 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT, 11 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the 12 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details. 13 * 14 */ 15 16 package org.rstudio.studio.client.workbench.prefs.views; 17 18 import com.google.gwt.event.logical.shared.ValueChangeEvent; 19 import com.google.gwt.event.logical.shared.ValueChangeHandler; 20 import com.google.gwt.resources.client.ImageResource; 21 import com.google.gwt.user.client.Command; 22 import com.google.gwt.user.client.ui.CheckBox; 23 import com.google.gwt.user.client.ui.HasHorizontalAlignment; 24 import com.google.gwt.user.client.ui.HorizontalPanel; 25 import com.google.gwt.user.client.ui.Label; 26 import com.google.inject.Inject; 27 28 import org.rstudio.core.client.BrowseCap; 29 import org.rstudio.core.client.ElementIds; 30 import org.rstudio.core.client.prefs.PreferencesDialogBaseResources; 31 import org.rstudio.core.client.prefs.RestartRequirement; 32 import org.rstudio.core.client.resources.ImageResource2x; 33 import org.rstudio.core.client.widget.FileChooserTextBox; 34 import org.rstudio.core.client.widget.FormLabel; 35 import org.rstudio.core.client.widget.MessageDialog; 36 import org.rstudio.core.client.widget.TextBoxWithButton; 37 import org.rstudio.studio.client.application.Desktop; 38 import org.rstudio.studio.client.common.FileDialogs; 39 import org.rstudio.studio.client.common.GlobalDisplay; 40 import org.rstudio.studio.client.common.HelpLink; 41 import org.rstudio.studio.client.common.vcs.GitServerOperations; 42 import org.rstudio.studio.client.common.vcs.SshKeyWidget; 43 import org.rstudio.studio.client.common.vcs.VcsHelpLink; 44 import org.rstudio.studio.client.workbench.commands.Commands; 45 import org.rstudio.studio.client.workbench.model.RemoteFileSystemContext; 46 import org.rstudio.studio.client.workbench.model.Session; 47 import org.rstudio.studio.client.workbench.model.SessionInfo; 48 import org.rstudio.studio.client.workbench.prefs.model.UserPrefs; 49 50 public class SourceControlPreferencesPane extends PreferencesPane 51 { 52 @Inject SourceControlPreferencesPane(PreferencesDialogResources res, Session session, GitServerOperations server, final GlobalDisplay globalDisplay, final Commands commands, RemoteFileSystemContext fsContext, FileDialogs fileDialogs)53 public SourceControlPreferencesPane(PreferencesDialogResources res, 54 Session session, 55 GitServerOperations server, 56 final GlobalDisplay globalDisplay, 57 final Commands commands, 58 RemoteFileSystemContext fsContext, 59 FileDialogs fileDialogs) 60 { 61 res_ = res; 62 63 chkVcsEnabled_ = new CheckBox( 64 "Enable version control interface for RStudio projects"); 65 extraSpaced(chkVcsEnabled_); 66 add(chkVcsEnabled_); 67 chkVcsEnabled_.addValueChangeHandler(new ValueChangeHandler<Boolean>() { 68 @Override 69 public void onValueChange(ValueChangeEvent<Boolean> event) 70 { 71 manageControlVisibility(); 72 73 globalDisplay.showMessage( 74 MessageDialog.INFO, 75 (event.getValue() ? "Enable" : "Disable") + " Version Control", 76 "You must restart RStudio for this change to take effect."); 77 } 78 }); 79 80 81 // git exe path chooser 82 Command onGitExePathChosen = new Command() 83 { 84 @Override 85 public void execute() 86 { 87 if (BrowseCap.isWindowsDesktop()) 88 { 89 String gitExePath = gitExePathChooser_.getText(); 90 if (!gitExePath.endsWith("git.exe")) 91 { 92 String message = "The program '" + gitExePath + "'" + 93 " is unlikely to be a valid git executable.\n" + 94 "Please select a git executable called 'git.exe'."; 95 96 globalDisplay.showMessage( 97 GlobalDisplay.MSG_WARNING, 98 "Invalid Git Executable", 99 message); 100 } 101 } 102 } 103 }; 104 105 gitExePathLabel_ = new FormLabel("Git executable:"); 106 gitExePathChooser_ = new FileChooserTextBox(gitExePathLabel_, 107 "(Not Found)", 108 ElementIds.TextBoxButtonId.GIT, 109 false, 110 null, 111 onGitExePathChosen); 112 SessionInfo sessionInfo = session.getSessionInfo(); 113 if (sessionInfo.getAllowVcsExeEdit()) 114 addTextBoxChooser(gitExePathLabel_, gitExePathChooser_); 115 116 // svn exe path chooser 117 svnExePathLabel_ = new FormLabel("SVN executable:"); 118 svnExePathChooser_ = new FileChooserTextBox(svnExePathLabel_, 119 "(Not Found)", 120 ElementIds.TextBoxButtonId.SVN, 121 false, 122 null, 123 null); 124 if (sessionInfo.getAllowVcsExeEdit()) 125 addTextBoxChooser(svnExePathLabel_, svnExePathChooser_); 126 127 // terminal path 128 terminalPathLabel_ = new FormLabel("Terminal executable:"); 129 terminalPathChooser_ = new FileChooserTextBox(terminalPathLabel_, 130 "(Not Found)", 131 ElementIds.TextBoxButtonId.VCS_TERMINAL, 132 false, 133 null, 134 null); 135 if (haveTerminalPathPref()) 136 addTextBoxChooser(terminalPathLabel_, terminalPathChooser_); 137 138 // ssh key widget 139 sshKeyWidget_ = new SshKeyWidget(server, "330px"); 140 sshKeyWidget_.addStyleName(res_.styles().sshKeyWidget()); 141 nudgeRight(sshKeyWidget_); 142 add(sshKeyWidget_); 143 144 HelpLink vcsHelpLink = new VcsHelpLink(); 145 nudgeRight(vcsHelpLink); 146 vcsHelpLink.addStyleName(res_.styles().newSection()); 147 add(vcsHelpLink); 148 149 chkVcsEnabled_.setEnabled(false); 150 gitExePathChooser_.setEnabled(false); 151 svnExePathChooser_.setEnabled(false); 152 terminalPathChooser_.setEnabled(false); 153 } 154 155 @Override initialize(UserPrefs prefs)156 protected void initialize(UserPrefs prefs) 157 { 158 chkVcsEnabled_.setEnabled(true); 159 gitExePathChooser_.setEnabled(true); 160 svnExePathChooser_.setEnabled(true); 161 terminalPathChooser_.setEnabled(true); 162 163 chkVcsEnabled_.setValue(prefs.vcsEnabled().getValue()); 164 gitExePathChooser_.setText(prefs.gitExePath().getValue()); 165 svnExePathChooser_.setText(prefs.svnExePath().getValue()); 166 terminalPathChooser_.setText(prefs.terminalPath().getValue()); 167 168 sshKeyWidget_.setRsaSshKeyPath(prefs.rsaKeyPath().getValue(), 169 prefs.haveRsaKey().getValue()); 170 sshKeyWidget_.setProgressIndicator(getProgressIndicator()); 171 172 manageControlVisibility(); 173 } 174 175 @Override getIcon()176 public ImageResource getIcon() 177 { 178 return new ImageResource2x(PreferencesDialogBaseResources.INSTANCE.iconSourceControl2x()); 179 } 180 181 @Override validate()182 public boolean validate() 183 { 184 return true; 185 } 186 187 @Override getName()188 public String getName() 189 { 190 return "Git/SVN"; 191 } 192 193 @Override onApply(UserPrefs prefs)194 public RestartRequirement onApply(UserPrefs prefs) 195 { 196 RestartRequirement restartRequirement = super.onApply(prefs); 197 198 prefs.vcsEnabled().setGlobalValue(chkVcsEnabled_.getValue()); 199 prefs.gitExePath().setGlobalValue(gitExePathChooser_.getText()); 200 prefs.svnExePath().setGlobalValue(svnExePathChooser_.getText()); 201 prefs.terminalPath().setGlobalValue(terminalPathChooser_.getText()); 202 203 return restartRequirement; 204 } 205 haveTerminalPathPref()206 private boolean haveTerminalPathPref() 207 { 208 return Desktop.isDesktop() && BrowseCap.isLinux(); 209 } 210 addTextBoxChooser(Label captionLabel, TextBoxWithButton chooser)211 private void addTextBoxChooser(Label captionLabel, TextBoxWithButton chooser) 212 { 213 String textWidth = "250px"; 214 215 HorizontalPanel captionPanel = new HorizontalPanel(); 216 captionPanel.setWidth(textWidth); 217 nudgeRight(captionPanel); 218 219 captionPanel.add(captionLabel); 220 captionPanel.setCellHorizontalAlignment(captionLabel, 221 HasHorizontalAlignment.ALIGN_LEFT); 222 223 add(tight(captionPanel)); 224 225 chooser.setTextWidth(textWidth); 226 nudgeRight(chooser); 227 textBoxWithChooser(chooser); 228 spaced(chooser); 229 add(chooser); 230 } 231 manageControlVisibility()232 private void manageControlVisibility() 233 { 234 boolean vcsEnabled = chkVcsEnabled_.getValue(); 235 gitExePathLabel_.setVisible(vcsEnabled); 236 gitExePathChooser_.setVisible(vcsEnabled); 237 svnExePathLabel_.setVisible(vcsEnabled); 238 svnExePathChooser_.setVisible(vcsEnabled); 239 terminalPathLabel_.setVisible(vcsEnabled); 240 terminalPathChooser_.setVisible(vcsEnabled && haveTerminalPathPref()); 241 sshKeyWidget_.setVisible(vcsEnabled); 242 } 243 244 private final PreferencesDialogResources res_; 245 246 private final CheckBox chkVcsEnabled_; 247 248 private FormLabel svnExePathLabel_; 249 private FormLabel gitExePathLabel_; 250 private TextBoxWithButton gitExePathChooser_; 251 private TextBoxWithButton svnExePathChooser_; 252 private FormLabel terminalPathLabel_; 253 private TextBoxWithButton terminalPathChooser_; 254 private SshKeyWidget sshKeyWidget_; 255 } 256