1 /* PackratResolveConflictDialog.java 2 * 3 * Copyright (C) 2021 by RStudio, PBC 4 * 5 * Unless you have received this program directly from RStudio pursuant 6 * to the terms of a commercial license agreement with RStudio, then 7 * this program is licensed to you under the terms of version 3 of the 8 * GNU Affero General Public License. This program is distributed WITHOUT 9 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT, 10 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the 11 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details. 12 * 13 */ 14 15 package org.rstudio.studio.client.packrat.ui; 16 17 import java.util.ArrayList; 18 19 import com.google.gwt.aria.client.Roles; 20 import org.rstudio.core.client.StringUtil; 21 import org.rstudio.core.client.widget.MessageDialog; 22 import org.rstudio.core.client.widget.ModalDialog; 23 import org.rstudio.core.client.widget.OperationWithInput; 24 import org.rstudio.core.client.widget.RStudioDataGrid; 25 import org.rstudio.studio.client.RStudioGinjector; 26 import org.rstudio.studio.client.common.StyleUtils; 27 import org.rstudio.studio.client.packrat.model.PackratConflictActions; 28 import org.rstudio.studio.client.packrat.model.PackratConflictResolution; 29 import org.rstudio.studio.client.workbench.views.packages.ui.PackagesDataGridCommon; 30 31 import com.google.gwt.core.shared.GWT; 32 import com.google.gwt.event.logical.shared.ValueChangeEvent; 33 import com.google.gwt.event.logical.shared.ValueChangeHandler; 34 import com.google.gwt.resources.client.ClientBundle; 35 import com.google.gwt.resources.client.CssResource; 36 import com.google.gwt.user.cellview.client.DataGrid; 37 import com.google.gwt.user.cellview.client.TextColumn; 38 import com.google.gwt.user.client.ui.Grid; 39 import com.google.gwt.user.client.ui.Label; 40 import com.google.gwt.user.client.ui.RadioButton; 41 import com.google.gwt.user.client.ui.VerticalPanel; 42 import com.google.gwt.user.client.ui.Widget; 43 44 public class PackratResolveConflictDialog 45 extends ModalDialog<PackratConflictResolution> 46 { PackratResolveConflictDialog( ArrayList<PackratConflictActions> conflictActions, OperationWithInput<PackratConflictResolution> onResolved)47 public PackratResolveConflictDialog( 48 ArrayList<PackratConflictActions> conflictActions, 49 OperationWithInput<PackratConflictResolution> onResolved) 50 { 51 super("Resolve Conflict", Roles.getDialogRole(), onResolved); 52 53 setOkButtonCaption("Resolve"); 54 55 // main widget 56 mainWidget_ = new VerticalPanel(); 57 58 // layout constants 59 final int kTableWidth = 540; 60 final int kPackageColWidth = 120; 61 final int kActionCol1Width = 190; 62 final int kActionCol2Width = 200; 63 64 // create label 65 Label label = new Label( 66 "Packrat's packages are out of sync with the packages currently " + 67 "installed in your library. To resolve the conflict you need to " + 68 "either update Packrat to match your library or update your library " + 69 "to match Packrat."); 70 label.addStyleName(RESOURCES.styles().conflictLabel()); 71 label.setWidth(kTableWidth + "px"); 72 mainWidget_.add(label); 73 74 // table 75 table_ = new RStudioDataGrid<>(conflictActions.size(), 76 (PackagesDataGridCommon)GWT.create(PackagesDataGridCommon.class)); 77 StyleUtils.forceMacScrollbars(table_); 78 table_.addStyleName(RESOURCES.styles().conflictsTable()); 79 table_.setWidth(kTableWidth + "px"); 80 table_.setHeight("225px"); 81 table_.setRowData(conflictActions); 82 table_.addColumn( 83 new TextColumn<PackratConflictActions>() { 84 public String getValue(PackratConflictActions item) 85 { 86 return item.getPackage(); 87 } 88 }, 89 "Package" 90 ); 91 92 table_.addColumn( 93 new TextColumn<PackratConflictActions>() { 94 public String getValue(PackratConflictActions item) 95 { 96 return StringUtil.notNull(item.getSnapshotAction()); 97 } 98 }, 99 "Packrat" 100 ); 101 102 table_.addColumn( 103 new TextColumn<PackratConflictActions>() { 104 public String getValue(PackratConflictActions item) 105 { 106 return StringUtil.notNull(item.getLibraryAction()); 107 } 108 }, 109 "Library" 110 ); 111 112 table_.setColumnWidth(0, kPackageColWidth + "px"); 113 table_.setColumnWidth(1, kActionCol1Width + "px"); 114 table_.setColumnWidth(2, kActionCol2Width + "px"); 115 mainWidget_.add(table_); 116 117 // create radio buttons 118 Grid choiceGrid = new Grid(1, 3); 119 choiceGrid.setWidth(kTableWidth + "px"); 120 choiceGrid.getColumnFormatter().setWidth(0, (kPackageColWidth-3) + "px"); 121 choiceGrid.getColumnFormatter().setWidth(1, (kActionCol1Width+3) + "px"); 122 choiceGrid.getColumnFormatter().setWidth(2, kActionCol2Width + "px"); 123 choiceGrid.addStyleName(RESOURCES.styles().choicesGrid()); 124 Label resolutionLabel =new Label("Resolution:"); 125 resolutionLabel.addStyleName(RESOURCES.styles().resolutionLabel()); 126 choiceGrid.setWidget(0, 0, resolutionLabel); 127 snapshotChoice_ = new RadioButton("snapshot", "Update Packrat (Snapshot)"); 128 snapshotChoice_.addStyleName(RESOURCES.styles().choiceButton()); 129 choiceGrid.setWidget(0, 1, snapshotChoice_); 130 snapshotChoice_.addValueChangeHandler(new ValueChangeHandler<Boolean>() { 131 @Override 132 public void onValueChange(ValueChangeEvent<Boolean> event) 133 { 134 libraryChoice_.setValue(!event.getValue(), false); 135 } 136 }); 137 libraryChoice_ = new RadioButton("library", "Update Library (Restore)"); 138 libraryChoice_.addStyleName(RESOURCES.styles().choiceButton()); 139 choiceGrid.setWidget(0, 2, libraryChoice_); 140 libraryChoice_.addValueChangeHandler(new ValueChangeHandler<Boolean>() { 141 @Override 142 public void onValueChange(ValueChangeEvent<Boolean> event) 143 { 144 snapshotChoice_.setValue(!event.getValue(), false); 145 } 146 }); 147 mainWidget_.add(choiceGrid); 148 149 150 } 151 152 @Override collectInput()153 protected PackratConflictResolution collectInput() 154 { 155 if (!snapshotChoice_.getValue() && !libraryChoice_.getValue()) 156 { 157 return null; 158 } 159 else if (snapshotChoice_.getValue()) 160 { 161 return PackratConflictResolution.Snapshot; 162 } 163 else if (libraryChoice_.getValue()) 164 { 165 return PackratConflictResolution.Library; 166 } 167 else 168 { 169 return null; 170 } 171 } 172 173 @Override validate(PackratConflictResolution input)174 protected boolean validate(PackratConflictResolution input) 175 { 176 if (input == null) 177 { 178 RStudioGinjector.INSTANCE.getGlobalDisplay().showMessage( 179 MessageDialog.ERROR, 180 "No Selection Made", 181 "You must choose to either update Packrat (snapshot) or " + 182 "update the project's private library (restore)."); 183 return false; 184 } 185 else 186 { 187 return true; 188 } 189 } 190 191 @Override createMainWidget()192 protected Widget createMainWidget() 193 { 194 195 return mainWidget_; 196 } 197 198 static interface Styles extends CssResource 199 { conflictLabel()200 String conflictLabel(); choicesGrid()201 String choicesGrid(); choiceButton()202 String choiceButton(); resolutionLabel()203 String resolutionLabel(); conflictsTable()204 String conflictsTable(); 205 } 206 207 static interface Resources extends ClientBundle 208 { 209 @Source("PackratResolveConflictDialog.css") styles()210 Styles styles(); 211 } 212 213 static Resources RESOURCES = (Resources)GWT.create(Resources.class); ensureStylesInjected()214 public static void ensureStylesInjected() 215 { 216 RESOURCES.styles().ensureInjected(); 217 } 218 219 private VerticalPanel mainWidget_; 220 private DataGrid<PackratConflictActions> table_; 221 private RadioButton snapshotChoice_; 222 private RadioButton libraryChoice_; 223 } 224