1 /* 2 * RMarkdownPreferencesPane.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 package org.rstudio.studio.client.workbench.prefs.views; 16 17 import com.google.gwt.dom.client.Style.Unit; 18 import com.google.gwt.resources.client.ImageResource; 19 import com.google.gwt.user.client.Command; 20 import com.google.gwt.user.client.ui.CheckBox; 21 import com.google.gwt.user.client.ui.Label; 22 import com.google.gwt.user.client.ui.VerticalPanel; 23 import com.google.inject.Inject; 24 25 import elemental2.core.JsObject; 26 import jsinterop.base.Js; 27 28 import org.rstudio.core.client.Debug; 29 import org.rstudio.core.client.ElementIds; 30 import org.rstudio.core.client.MessageDisplay; 31 import org.rstudio.core.client.prefs.RestartRequirement; 32 import org.rstudio.core.client.resources.ImageResource2x; 33 import org.rstudio.core.client.theme.DialogTabLayoutPanel; 34 import org.rstudio.core.client.theme.VerticalTabPanel; 35 import org.rstudio.core.client.widget.DirectoryChooserTextBox; 36 import org.rstudio.core.client.widget.HelpButton; 37 import org.rstudio.core.client.widget.NumericValueWidget; 38 import org.rstudio.core.client.widget.Operation; 39 import org.rstudio.core.client.widget.SelectWidget; 40 import org.rstudio.studio.client.RStudioGinjector; 41 import org.rstudio.studio.client.common.FileDialogs; 42 import org.rstudio.studio.client.common.HelpLink; 43 import org.rstudio.studio.client.panmirror.server.PanmirrorZoteroLocalConfig; 44 import org.rstudio.studio.client.panmirror.server.PanmirrorZoteroServerOperations; 45 import org.rstudio.studio.client.server.ServerError; 46 import org.rstudio.studio.client.server.ServerRequestCallback; 47 import org.rstudio.studio.client.workbench.model.RemoteFileSystemContext; 48 import org.rstudio.studio.client.workbench.model.Session; 49 import org.rstudio.studio.client.workbench.prefs.model.UserPrefs; 50 import org.rstudio.studio.client.workbench.prefs.model.UserPrefsAccessor; 51 import org.rstudio.studio.client.workbench.prefs.model.UserState; 52 import org.rstudio.studio.client.workbench.prefs.model.UserStateAccessor; 53 import org.rstudio.studio.client.workbench.prefs.views.zotero.ZoteroApiKeyWidget; 54 import org.rstudio.studio.client.workbench.prefs.views.zotero.ZoteroConnectionWidget; 55 import org.rstudio.studio.client.workbench.prefs.views.zotero.ZoteroLibrariesWidget; 56 57 public class RMarkdownPreferencesPane extends PreferencesPane 58 { 59 @Inject RMarkdownPreferencesPane(UserPrefs prefs, UserState state, PreferencesDialogResources res, Session session, RemoteFileSystemContext fsContext, FileDialogs fileDialogs, PanmirrorZoteroServerOperations zoteroServer)60 public RMarkdownPreferencesPane(UserPrefs prefs, 61 UserState state, 62 PreferencesDialogResources res, 63 Session session, 64 RemoteFileSystemContext fsContext, 65 FileDialogs fileDialogs, 66 PanmirrorZoteroServerOperations zoteroServer) 67 { 68 prefs_ = prefs; 69 state_ = state; 70 res_ = res; 71 72 VerticalTabPanel basic = new VerticalTabPanel(ElementIds.RMARKDOWN_BASIC_PREFS); 73 74 basic.add(headerLabel("R Markdown")); 75 76 basic.add(checkboxPref("Show document outline by default", prefs_.showDocOutlineRmd())); 77 basic.add(checkboxPref("Soft-wrap R Markdown files", prefs_.softWrapRmdFiles())); 78 79 docOutlineDisplay_ = new SelectWidget( 80 "Show in document outline: ", 81 new String[] { 82 "Sections Only", 83 "Sections and Named Chunks", 84 "Sections and All Chunks" 85 }, 86 new String[] { 87 UserPrefs.DOC_OUTLINE_SHOW_SECTIONS_ONLY, 88 UserPrefs.DOC_OUTLINE_SHOW_SECTIONS_AND_CHUNKS, 89 UserPrefs.DOC_OUTLINE_SHOW_ALL 90 }, 91 false, 92 true, 93 false); 94 basic.add(docOutlineDisplay_); 95 96 rmdViewerMode_ = new SelectWidget( 97 "Show output preview in: ", 98 new String[] { 99 "Window", 100 "Viewer Pane", 101 "(None)" 102 }, 103 new String[] { 104 UserPrefs.RMD_VIEWER_TYPE_WINDOW, 105 UserPrefs.RMD_VIEWER_TYPE_PANE, 106 UserPrefs.RMD_VIEWER_TYPE_NONE 107 }, 108 false, 109 true, 110 false); 111 basic.add(rmdViewerMode_); 112 113 114 // show output inline for all Rmds 115 final CheckBox rmdInlineOutput = checkboxPref( 116 "Show output inline for all R Markdown documents", 117 prefs_.rmdChunkOutputInline()); 118 basic.add(rmdInlineOutput); 119 120 // behavior for latex and image preview popups 121 latexPreviewWidget_ = new SelectWidget( 122 "Show equation and image previews: ", 123 new String[] { 124 "Never", 125 "In a popup", 126 "Inline" 127 }, 128 new String[] { 129 UserPrefs.LATEX_PREVIEW_ON_CURSOR_IDLE_NEVER, 130 UserPrefs.LATEX_PREVIEW_ON_CURSOR_IDLE_INLINE_ONLY, 131 UserPrefs.LATEX_PREVIEW_ON_CURSOR_IDLE_ALWAYS 132 }, 133 false, 134 true, 135 false); 136 basic.add(latexPreviewWidget_); 137 138 if (session.getSessionInfo().getKnitWorkingDirAvailable()) 139 { 140 knitWorkingDir_ = new SelectWidget( 141 "Evaluate chunks in directory: ", 142 new String[] { 143 "Document", 144 "Current", 145 "Project" 146 }, 147 new String[] { 148 UserPrefs.KNIT_WORKING_DIR_DEFAULT, 149 UserPrefs.KNIT_WORKING_DIR_CURRENT, 150 UserPrefs.KNIT_WORKING_DIR_PROJECT 151 }, 152 false, 153 true, 154 false); 155 basic.add(knitWorkingDir_); 156 } 157 else 158 { 159 knitWorkingDir_ = null; 160 } 161 162 basic.add(spacedBefore(headerLabel("R Notebooks"))); 163 164 // auto-execute the setup chunk 165 final CheckBox autoExecuteSetupChunk = checkboxPref( 166 "Execute setup chunk automatically in notebooks", 167 prefs_.autoRunSetupChunk()); 168 basic.add(autoExecuteSetupChunk); 169 170 // hide console when executing notebook chunks 171 final CheckBox notebookHideConsole = checkboxPref( 172 "Hide console automatically when executing " + 173 "notebook chunks", 174 prefs_.hideConsoleOnChunkExecute()); 175 basic.add(notebookHideConsole); 176 177 basic.add(spacedBefore(new HelpLink("Using R Notebooks", "using_notebooks"))); 178 179 VerticalTabPanel advanced = new VerticalTabPanel(ElementIds.RMARKDOWN_ADVANCED_PREFS); 180 advanced.add(headerLabel("Display")); 181 advanced.add(checkboxPref("Enable chunk background highlight", prefs_.highlightCodeChunks())); 182 advanced.add(checkboxPref("Show inline toolbar for R code chunks", prefs_.showInlineToolbarForRCodeChunks())); 183 final CheckBox showRmdRenderCommand = checkboxPref( "Display render command in R Markdown tab", 184 prefs_.showRmdRenderCommand()); 185 advanced.add(showRmdRenderCommand); 186 187 VerticalTabPanel visualMode = new VerticalTabPanel(ElementIds.RMARKDOWN_VISUAL_MODE_PREFS); 188 189 visualMode.add(headerLabel("General")); 190 191 CheckBox visualMarkdownIsDefault = checkboxPref( 192 "Use visual editor by default for new documents", 193 prefs_.visualMarkdownEditingIsDefault()); 194 visualMarkdownIsDefault.getElement().getStyle().setMarginBottom(10, Unit.PX); 195 visualMode.add(visualMarkdownIsDefault); 196 197 HelpLink visualModeHelpLink = new HelpLink( 198 "Learn more about visual editing mode", 199 "visual_markdown_editing", 200 false // no version info 201 ); 202 nudgeRight(visualModeHelpLink); 203 spaced(visualModeHelpLink); 204 visualMode.add(visualModeHelpLink); 205 206 207 visualMode.add(headerLabel("Display")); 208 209 210 VerticalPanel visualModeOptions = new VerticalPanel(); 211 212 213 214 // show outline 215 CheckBox visualEditorShowOutline = checkboxPref( 216 "Show document outline by default", 217 prefs_.visualMarkdownEditingShowDocOutline(), 218 false); 219 lessSpaced(visualEditorShowOutline); 220 visualModeOptions.add(visualEditorShowOutline); 221 222 // show margin 223 CheckBox visualEditorShowMargin = checkboxPref( 224 "Show margin column indicator in code blocks", 225 prefs_.visualMarkdownEditingShowMargin(), 226 false); 227 lessSpaced(visualEditorShowMargin); 228 visualModeOptions.add(visualEditorShowMargin); 229 230 231 // content width 232 visualModeContentWidth_ = numericPref( 233 "Editor content width (px):", 234 100, 235 NumericValueWidget.NoMaximum, 236 prefs_.visualMarkdownEditingMaxContentWidth(), 237 false 238 ); 239 visualModeContentWidth_.setWidth("42px"); 240 visualModeContentWidth_.setLimits(100, NumericValueWidget.NoMaximum); 241 lessSpaced(visualModeContentWidth_); 242 visualModeOptions.add(nudgeRightPlus(visualModeContentWidth_)); 243 244 // font size 245 final String kDefault = "(Default)"; 246 String[] labels = {kDefault, "8", "9", "10", "11", "12",}; 247 String[] values = new String[labels.length]; 248 for (int i = 0; i < labels.length; i++) 249 { 250 if (labels[i].equals(kDefault)) 251 values[i] = "0"; 252 else 253 values[i] = Double.parseDouble(labels[i]) + ""; 254 } 255 visualModeFontSize_ = new SelectWidget("Editor font size:", labels, values, false, true, false); 256 if (!visualModeFontSize_.setValue(prefs_.visualMarkdownEditingFontSizePoints().getGlobalValue() + "")) 257 visualModeFontSize_.getListBox().setSelectedIndex(0); 258 visualModeFontSize_.getElement().getStyle().setMarginTop(3, Unit.PX); 259 visualModeFontSize_.getElement().getStyle().setMarginBottom(15, Unit.PX); 260 visualModeOptions.add(visualModeFontSize_); 261 262 263 visualModeOptions.add(headerLabel("Markdown")); 264 265 266 // list spacing 267 String[] listSpacingValues = { 268 UserPrefsAccessor.VISUAL_MARKDOWN_EDITING_LIST_SPACING_TIGHT, 269 UserPrefsAccessor.VISUAL_MARKDOWN_EDITING_LIST_SPACING_SPACED 270 }; 271 visualModeListSpacing_ = new SelectWidget("Default spacing between list items: ", 272 listSpacingValues, listSpacingValues, 273 false, true, false); 274 visualModeListSpacing_.getElement().getStyle().setMarginBottom(10, Unit.PX); 275 if (!visualModeListSpacing_.setValue(prefs_.visualMarkdownEditingListSpacing().getGlobalValue())) 276 visualModeListSpacing_.getListBox().setSelectedIndex(0); 277 visualModeOptions.add(visualModeListSpacing_); 278 279 // auto wrap 280 String[] wrapValues = { 281 UserPrefsAccessor.VISUAL_MARKDOWN_EDITING_WRAP_NONE, 282 UserPrefsAccessor.VISUAL_MARKDOWN_EDITING_WRAP_COLUMN, 283 UserPrefsAccessor.VISUAL_MARKDOWN_EDITING_WRAP_SENTENCE 284 }; 285 visualModeWrap_ = new SelectWidget("Automatic text wrapping (line breaks): ", wrapValues, wrapValues, false, true, false); 286 if (!visualModeWrap_.setValue(prefs_.visualMarkdownEditingWrap().getGlobalValue())) 287 visualModeWrap_.getListBox().setSelectedIndex(0); 288 HelpButton.addHelpButton(visualModeWrap_, "visual_markdown_editing-line-wrapping", "Learn more about automatic line wrapping", 0); 289 visualModeWrap_.addStyleName(res.styles().visualModeWrapSelectWidget()); 290 visualModeOptions.add(visualModeWrap_); 291 292 visualModeOptions.add(indent(visualModeWrapColumn_ = numericPref( 293 "Wrap at column:", 1, UserPrefs.MAX_WRAP_COLUMN, 294 prefs.visualMarkdownEditingWrapAtColumn() 295 ))); 296 visualModeWrapColumn_.getElement().getStyle().setMarginBottom(8, Unit.PX); 297 visualModeWrapColumn_.setWidth("36px"); 298 Command manageWrapColumn = () -> { 299 boolean wrapAtColumn = visualModeWrap_.getValue().equals(UserPrefsAccessor.VISUAL_MARKDOWN_EDITING_WRAP_COLUMN); 300 visualModeWrapColumn_.setVisible(wrapAtColumn); 301 visualModeWrap_.getElement().getStyle().setMarginBottom(wrapAtColumn ? 2 : 8, Unit.PX); 302 }; 303 manageWrapColumn.execute(); 304 visualModeWrap_.addChangeHandler((arg) -> { 305 manageWrapColumn.execute(); 306 }); 307 lessSpaced(visualModeWrapColumn_); 308 309 // references 310 String[] referencesValues = { 311 UserPrefsAccessor.VISUAL_MARKDOWN_EDITING_REFERENCES_LOCATION_BLOCK, 312 UserPrefsAccessor.VISUAL_MARKDOWN_EDITING_REFERENCES_LOCATION_SECTION, 313 UserPrefsAccessor.VISUAL_MARKDOWN_EDITING_REFERENCES_LOCATION_DOCUMENT 314 }; 315 visualModeReferences_ = new SelectWidget("Write references at end of current: ", referencesValues, referencesValues, false, true, false); 316 if (!visualModeReferences_.setValue(prefs_.visualMarkdownEditingReferencesLocation().getGlobalValue())) 317 visualModeReferences_.getListBox().setSelectedIndex(0); 318 spaced(visualModeReferences_); 319 visualModeOptions.add(visualModeReferences_); 320 321 // canonical mode 322 CheckBox visualModeCanonical = checkboxPref( 323 "Write canonical visual mode markdown in source mode", 324 prefs_.visualMarkdownEditingCanonical(), 325 false); 326 spaced(visualModeCanonical); 327 visualModeOptions.add(visualModeCanonical); 328 visualModeCanonical.addValueChangeHandler(value -> { 329 if (value.getValue()) 330 { 331 RStudioGinjector.INSTANCE.getGlobalDisplay().showYesNoMessage( 332 MessageDisplay.MSG_WARNING, 333 "Visual Mode Preferences", 334 "Are you sure you want to write canonical markdown from source mode for all R Markdown files?\n\n" + 335 "This preference should generally only be used at a project level (to prevent " + 336 "re-writing of markdown source that you or others don't intend to use with visual mode).\n\n" + 337 "Change this preference now?", 338 false, 339 new Operation() { 340 @Override 341 public void execute() 342 { 343 344 } 345 }, 346 () -> { 347 visualModeCanonical.setValue(false); 348 }, 349 false); 350 } 351 }); 352 353 // help on per-file markdown options 354 HelpLink markdownPerFileOptions = new HelpLink( 355 "Learn more about markdown writer options", 356 "visual_markdown_editing-writer-options", 357 false // no version info 358 ); 359 nudgeRight(markdownPerFileOptions); 360 spaced(markdownPerFileOptions); 361 visualModeOptions.add(markdownPerFileOptions); 362 363 visualMode.add(visualModeOptions); 364 365 VerticalTabPanel citations = new VerticalTabPanel(ElementIds.RMARKDOWN_CITATIONS_PREFS); 366 367 Label citationsLabel = new Label("Citation features are available within R Markdown visual mode."); 368 spaced(citationsLabel); 369 citations.add(citationsLabel); 370 371 // help on per-file markdown options 372 HelpLink citationsHelpLink = new HelpLink( 373 "Learn more about using citations with visual editing mode", 374 "visual_markdown_editing-citations", 375 false // no version info 376 ); 377 spaced(citationsHelpLink); 378 citations.add(citationsHelpLink); 379 380 citations.add(headerLabel("Zotero")); 381 382 zoteroConnection_ = new ZoteroConnectionWidget(res, false); 383 spaced(zoteroConnection_); 384 citations.add(zoteroConnection_); 385 386 zoteroApiKey_ = new ZoteroApiKeyWidget(zoteroServer, "240px"); 387 zoteroApiKey_.getElement().getStyle().setMarginLeft(4, Unit.PX); 388 spaced(zoteroApiKey_); 389 zoteroApiKey_.setKey(state_.zoteroApiKey().getValue()); 390 citations.add(zoteroApiKey_); 391 392 zoteroDataDir_ = new DirectoryChooserTextBox( 393 "Zotero Data Directory:", 394 "(None Detected)", 395 ElementIds.TextBoxButtonId.ZOTERO_DATA_DIRECTORY, 396 null, 397 fileDialogs, 398 fsContext 399 ); 400 spaced(zoteroDataDir_); 401 nudgeRight(zoteroDataDir_); 402 textBoxWithChooser(zoteroDataDir_); 403 zoteroDataDir_.getTextBox().addStyleName(res.styles().smallerText()); 404 String dataDir = state_.zoteroDataDir().getValue(); 405 if (!dataDir.isEmpty()) 406 zoteroDataDir_.setText(dataDir); 407 citations.add(zoteroDataDir_); 408 409 410 zoteroLibs_ = new ZoteroLibrariesWidget(zoteroServer); 411 lessSpaced(zoteroLibs_); 412 citations.add(zoteroLibs_); 413 414 zoteroUseBetterBibtex_ = checkboxPref( 415 "Use Better BibTeX for citation keys and BibTeX export", 416 state_.zoteroUseBetterBibtex(), 417 false); 418 spaced(zoteroUseBetterBibtex_); 419 citations.add(zoteroUseBetterBibtex_); 420 421 // kickoff query for detected zotero data directory 422 zoteroServer.zoteroDetectLocalConfig(new ServerRequestCallback<JsObject>() { 423 424 @Override 425 public void onResponseReceived(JsObject response) 426 { 427 zoteroLocalConfig_ = Js.uncheckedCast(response); 428 429 if (zoteroDataDir_.getText().isEmpty()) 430 zoteroDataDir_.setText(zoteroLocalConfig_.dataDirectory); 431 432 // resolve 'auto' 433 String connectionType = state_.zoteroConnectionType().getValue(); 434 zoteroIsAuto_ = connectionType.equals(UserStateAccessor.ZOTERO_CONNECTION_TYPE_AUTO); 435 if (zoteroIsAuto_) 436 { 437 if (!zoteroDataDir_.getText().isEmpty()) 438 connectionType = UserStateAccessor.ZOTERO_CONNECTION_TYPE_LOCAL; 439 else 440 connectionType = UserStateAccessor.ZOTERO_CONNECTION_TYPE_NONE; 441 } 442 zoteroConnection_.setType(connectionType); 443 444 // manage ui. if the user ever interact with the control then 'auto' is gone 445 manageZoteroUI(true); 446 zoteroConnection_.addChangeHandler((event) -> { 447 zoteroIsAuto_ = false; 448 // connection type change invalidates libraries (as they were 449 // retrived from the previous connection). default back to 450 // 'My Library' 451 zoteroLibs_.setMyLibrary(); 452 manageZoteroUI(false); 453 }); 454 } 455 456 @Override 457 public void onError(ServerError error) 458 { 459 Debug.logError(error); 460 } 461 462 }); 463 464 465 DialogTabLayoutPanel tabPanel = new DialogTabLayoutPanel("R Markdown"); 466 tabPanel.setSize("435px", "533px"); 467 tabPanel.add(basic, "Basic", basic.getBasePanelId()); 468 tabPanel.add(advanced, "Advanced", advanced.getBasePanelId()); 469 tabPanel.add(visualMode, "Visual", visualMode.getBasePanelId()); 470 tabPanel.add(citations, "Citations", citations.getBasePanelId()); 471 tabPanel.selectTab(0); 472 add(tabPanel); 473 } 474 475 @Override getIcon()476 public ImageResource getIcon() 477 { 478 return new ImageResource2x(res_.iconRMarkdown2x()); 479 } 480 481 @Override validate()482 public boolean validate() 483 { 484 return visualModeWrapColumn_.validate() && 485 visualModeContentWidth_.validate() && 486 zoteroLibs_.validate(); 487 } 488 489 @Override getName()490 public String getName() 491 { 492 return "R Markdown"; 493 } 494 495 @Override initialize(UserPrefs prefs)496 protected void initialize(UserPrefs prefs) 497 { 498 docOutlineDisplay_.setValue(prefs_.docOutlineShow().getValue()); 499 rmdViewerMode_.setValue(prefs_.rmdViewerType().getValue().toString()); 500 latexPreviewWidget_.setValue(prefs_.latexPreviewOnCursorIdle().getValue()); 501 if (knitWorkingDir_ != null) 502 knitWorkingDir_.setValue(prefs_.knitWorkingDir().getValue()); 503 504 visualModeWrap_.setValue(prefs.visualMarkdownEditingWrap().getGlobalValue()); 505 visualModeReferences_.setValue(prefs.visualMarkdownEditingReferencesLocation().getGlobalValue()); 506 507 zoteroApiKey_.setProgressIndicator(getProgressIndicator()); 508 509 zoteroLibs_.setLibraries(prefs_.zoteroLibraries().getValue()); 510 zoteroLibs_.addAvailableLibraries(); 511 512 } 513 manageZoteroUI(boolean showLibs)514 private void manageZoteroUI(boolean showLibs) 515 { 516 zoteroApiKey_.setVisible(zoteroConnection_.getType().equals(UserStateAccessor.ZOTERO_CONNECTION_TYPE_WEB)); 517 zoteroDataDir_.setVisible(zoteroConnection_.getType().equals(UserStateAccessor.ZOTERO_CONNECTION_TYPE_LOCAL)); 518 zoteroLibs_.setVisible(showLibs && !zoteroConnection_.getType().equals(UserStateAccessor.ZOTERO_CONNECTION_TYPE_NONE)); 519 zoteroUseBetterBibtex_.setVisible(zoteroDataDir_.isVisible() && zoteroLocalConfig_.betterBibtex); 520 } 521 522 @Override onApply(UserPrefs rPrefs)523 public RestartRequirement onApply(UserPrefs rPrefs) 524 { 525 RestartRequirement restartRequirement = super.onApply(rPrefs); 526 527 prefs_.docOutlineShow().setGlobalValue( 528 docOutlineDisplay_.getValue()); 529 530 prefs_.rmdViewerType().setGlobalValue( 531 rmdViewerMode_.getValue()); 532 533 prefs_.latexPreviewOnCursorIdle().setGlobalValue( 534 latexPreviewWidget_.getValue()); 535 536 prefs_.visualMarkdownEditingFontSizePoints().setGlobalValue( 537 Integer.parseInt(visualModeFontSize_.getValue())); 538 539 prefs_.visualMarkdownEditingListSpacing().setGlobalValue( 540 visualModeListSpacing_.getValue()); 541 542 prefs_.visualMarkdownEditingWrap().setGlobalValue( 543 visualModeWrap_.getValue()); 544 545 prefs_.visualMarkdownEditingReferencesLocation().setGlobalValue( 546 visualModeReferences_.getValue()); 547 548 if (knitWorkingDir_ != null) 549 { 550 prefs_.knitWorkingDir().setGlobalValue( 551 knitWorkingDir_.getValue()); 552 } 553 554 if (zoteroIsAuto_) 555 { 556 state_.zoteroConnectionType().setGlobalValue(UserStateAccessor.ZOTERO_CONNECTION_TYPE_AUTO); 557 } 558 else if (zoteroConnection_.getType().equals(UserStateAccessor.ZOTERO_CONNECTION_TYPE_LOCAL) && 559 zoteroDataDir_.getText().isEmpty()) 560 { 561 // not a valid set 562 } 563 else if (zoteroConnection_.getType().equals(UserStateAccessor.ZOTERO_CONNECTION_TYPE_WEB) && 564 zoteroApiKey_.getKey().isEmpty()) 565 { 566 // not a valid set 567 } 568 else 569 { 570 state_.zoteroConnectionType().setGlobalValue(zoteroConnection_.getType()); 571 } 572 573 prefs_.zoteroLibraries().setGlobalValue(zoteroLibs_.getLibraries()); 574 575 // if the zotero data dir is same as the detected data dir then 576 // set it to empty (allowing the server to always get the right default) 577 if (zoteroDataDir_.getText().equals(zoteroLocalConfig_.dataDirectory)) 578 state_.zoteroDataDir().setGlobalValue(""); 579 else 580 state_.zoteroDataDir().setGlobalValue(zoteroDataDir_.getText()); 581 582 state_.zoteroApiKey().setGlobalValue(zoteroApiKey_.getKey()); 583 584 return restartRequirement; 585 } 586 587 private final UserPrefs prefs_; 588 private final UserState state_; 589 590 private final PreferencesDialogResources res_; 591 592 private final SelectWidget rmdViewerMode_; 593 private final SelectWidget docOutlineDisplay_; 594 private final SelectWidget latexPreviewWidget_; 595 private final SelectWidget knitWorkingDir_; 596 597 private final SelectWidget visualModeFontSize_; 598 private final NumericValueWidget visualModeContentWidth_; 599 private final NumericValueWidget visualModeWrapColumn_; 600 private final SelectWidget visualModeListSpacing_; 601 private final SelectWidget visualModeWrap_; 602 private final SelectWidget visualModeReferences_; 603 604 private final ZoteroConnectionWidget zoteroConnection_; 605 private final DirectoryChooserTextBox zoteroDataDir_; 606 private final ZoteroApiKeyWidget zoteroApiKey_; 607 private final ZoteroLibrariesWidget zoteroLibs_; 608 private final CheckBox zoteroUseBetterBibtex_; 609 private PanmirrorZoteroLocalConfig zoteroLocalConfig_ = new PanmirrorZoteroLocalConfig(); 610 private boolean zoteroIsAuto_ = false; 611 } 612