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