/* * AppearancePreferencesPane.java * * Copyright (C) 2009-12 by RStudio, Inc. * * Unless you have received this program directly from RStudio pursuant * to the terms of a commercial license agreement with RStudio, then * this program is licensed to you under the terms of version 3 of the * GNU Affero General Public License. This program is distributed WITHOUT * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT, * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details. * */ package org.rstudio.studio.client.workbench.prefs.views; import com.google.gwt.dom.client.SelectElement; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.regexp.shared.MatchResult; import com.google.gwt.regexp.shared.RegExp; import com.google.gwt.resources.client.ImageResource; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.inject.Inject; import org.rstudio.core.client.BrowseCap; import org.rstudio.core.client.StringUtil; import org.rstudio.core.client.resources.ImageResource2x; import org.rstudio.core.client.theme.ThemeFonts; import org.rstudio.core.client.widget.SelectWidget; import org.rstudio.studio.client.application.Desktop; import org.rstudio.studio.client.application.events.EventBus; import org.rstudio.studio.client.application.events.ThemeChangedEvent; import org.rstudio.studio.client.workbench.prefs.model.RPrefs; import org.rstudio.studio.client.workbench.prefs.model.UIPrefs; import org.rstudio.studio.client.workbench.views.source.editors.text.themes.AceThemes; public class AppearancePreferencesPane extends PreferencesPane { @Inject public AppearancePreferencesPane(PreferencesDialogResources res, UIPrefs uiPrefs, final AceThemes themes, EventBus eventBus) { res_ = res; uiPrefs_ = uiPrefs; eventBus_ = eventBus; VerticalPanel leftPanel = new VerticalPanel(); flatTheme_ = new SelectWidget("RStudio theme:", new String[]{"Classic", "Modern", "Sky"}, new String[]{"classic", "modern", "alternate"}, false); flatTheme_.addStyleName(res.styles().themeChooser()); flatTheme_.getListBox().setWidth("95%"); flatTheme_.getListBox().addChangeHandler(new ChangeHandler() { public void onChange(ChangeEvent event) { } }); String themeAlias = uiPrefs_.getFlatTheme().getGlobalValue(); if (themeAlias == "default" || themeAlias == "dark-grey") themeAlias = "modern"; flatTheme_.setValue(themeAlias); leftPanel.add(flatTheme_); if (Desktop.isDesktop()) { // no zoom level on cocoa desktop if (!BrowseCap.isCocoaDesktop()) { int initialIndex = -1; int normalIndex = -1; String[] zoomValues = Desktop.getFrame().getZoomLevels().split("\\n"); String[] zoomLabels = new String[zoomValues.length]; for (int i=0; i<zoomValues.length; i++) { double zoomValue = Double.parseDouble(zoomValues[i]); if (zoomValue == 1.0) normalIndex = i; if (zoomValue == Desktop.getFrame().getZoomLevel()) initialIndex = i; zoomLabels[i] = StringUtil.formatPercent(zoomValue); } if (initialIndex == -1) initialIndex = normalIndex; zoomLevel_ = new SelectWidget("Zoom:", zoomLabels, zoomValues, false); zoomLevel_.getListBox().setSelectedIndex(initialIndex); initialZoomLevel_ = zoomValues[initialIndex]; leftPanel.add(zoomLevel_); zoomLevel_.getListBox().addChangeHandler(new ChangeHandler() { @Override public void onChange(ChangeEvent event) { updatePreviewZoomLevel(); } }); } String[] fonts = Desktop.getFrame().getFixedWidthFontList().split("\\n"); fontFace_ = new SelectWidget("Editor font:", fonts, fonts, false, false, false); fontFace_.getListBox().setWidth("95%"); String value = Desktop.getFrame().getFixedWidthFont(); String label = Desktop.getFrame().getFixedWidthFont().replaceAll("\\\"", ""); if (!fontFace_.setValue(label)) { fontFace_.insertValue(0, label, value); fontFace_.setValue(value); } initialFontFace_ = StringUtil.notNull(fontFace_.getValue()); leftPanel.add(fontFace_); fontFace_.addChangeHandler(new ChangeHandler() { @Override public void onChange(ChangeEvent event) { String font = fontFace_.getValue(); if (font != null) preview_.setFont(font); else preview_.setFont(ThemeFonts.getFixedWidthFont()); } }); } String[] labels = {"7", "8", "9", "10", "11", "12", "13", "14", "16", "18", "24", "36"}; String[] values = new String[labels.length]; for (int i = 0; i < labels.length; i++) values[i] = Double.parseDouble(labels[i]) + ""; fontSize_ = new SelectWidget("Editor Font size:", labels, values, false); fontSize_.getListBox().setWidth("95%"); if (!fontSize_.setValue(uiPrefs.fontSize().getGlobalValue() + "")) fontSize_.getListBox().setSelectedIndex(3); fontSize_.getListBox().addChangeHandler(new ChangeHandler() { public void onChange(ChangeEvent event) { preview_.setFontSize(Double.parseDouble(fontSize_.getValue())); } }); theme_ = new SelectWidget("Editor theme:", themes.getThemeNames(), themes.getThemeNames(), false); theme_.getListBox().addChangeHandler(new ChangeHandler() { public void onChange(ChangeEvent event) { preview_.setTheme(themes.getThemeUrl(theme_.getValue())); } }); theme_.getListBox().getElement().<SelectElement>cast().setSize(7); theme_.getListBox().getElement().getStyle().setHeight(250, Unit.PX); theme_.addStyleName(res.styles().themeChooser()); theme_.setValue(themes.getEffectiveThemeName(uiPrefs_.theme().getGlobalValue())); leftPanel.add(fontSize_); leftPanel.add(theme_); FlowPanel previewPanel = new FlowPanel(); previewPanel.setSize("100%", "100%"); preview_ = new AceEditorPreview(CODE_SAMPLE); preview_.setHeight("498px"); preview_.setWidth("278px"); preview_.setTheme(themes.getThemeUrl(uiPrefs_.theme().getGlobalValue())); preview_.setFontSize(Double.parseDouble(fontSize_.getValue())); updatePreviewZoomLevel(); previewPanel.add(preview_); HorizontalPanel hpanel = new HorizontalPanel(); hpanel.setWidth("100%"); hpanel.add(leftPanel); hpanel.setCellWidth(leftPanel, "160px"); hpanel.add(previewPanel); add(hpanel); } private void updatePreviewZoomLevel() { // no zoom preview on desktop if (Desktop.isDesktop() && !Desktop.getFrame().isCocoa()) { preview_.setZoomLevel(Double.parseDouble(zoomLevel_.getValue()) / Desktop.getFrame().getZoomLevel()); } } @Override public ImageResource getIcon() { return new ImageResource2x(res_.iconAppearance2x()); } @Override protected void initialize(RPrefs prefs) { } @Override public boolean onApply(RPrefs rPrefs) { boolean restartRequired = super.onApply(rPrefs); double fontSize = Double.parseDouble(fontSize_.getValue()); uiPrefs_.fontSize().setGlobalValue(fontSize); uiPrefs_.theme().setGlobalValue(theme_.getValue()); if (Desktop.isDesktop()) { if (!initialFontFace_.equals(fontFace_.getValue())) { Desktop.getFrame().setFixedWidthFont(fontFace_.getValue()); restartRequired = true; } if (!Desktop.getFrame().isCocoa()) { if (!initialZoomLevel_.equals(zoomLevel_.getValue())) { double zoomLevel = Double.parseDouble(zoomLevel_.getValue()); Desktop.getFrame().setZoomLevel(zoomLevel); restartRequired = true; } } } String themeName = flatTheme_.getValue(); if (themeName == "modern") { RegExp keyReg = RegExp.compile( "ambiance|chaos|clouds midnight|cobalt|idle fingers|kr theme|" + "material|merbivore soft|merbivore|mono industrial|monokai|" + "pastel on dark|solarized dark|tomorrow night bluw|tomorrow night bright|" + "tomorrow night 80s|tomorrow night|twilight|vibrant ink", "i"); MatchResult result = keyReg.exec(theme_.getValue()); themeName = result != null ? "dark-grey" : "default"; } uiPrefs_.getFlatTheme().setGlobalValue(themeName); ThemeChangedEvent themeChangedEvent = new ThemeChangedEvent(flatTheme_.getValue()); eventBus_.fireEvent(themeChangedEvent); eventBus_.fireEventToAllSatellites(themeChangedEvent); return restartRequired; } @Override public String getName() { return "Appearance"; } private final PreferencesDialogResources res_; private final UIPrefs uiPrefs_; private SelectWidget fontSize_; private SelectWidget theme_; private AceEditorPreview preview_; private SelectWidget fontFace_; private String initialFontFace_; private SelectWidget zoomLevel_; private String initialZoomLevel_; private SelectWidget flatTheme_; private static final String CODE_SAMPLE = "# plotting of R objects\n" + "plot <- function (x, y, ...)\n" + "{\n" + " if (is.function(x) && \n" + " is.null(attr(x, \"class\")))\n" + " {\n" + " if (missing(y))\n" + " y <- NULL\n" + " \n" + " # check for ylab argument\n" + " hasylab <- function(...) \n" + " !all(is.na(\n" + " pmatch(names(list(...)),\n" + " \"ylab\")))\n" + " \n" + " if (hasylab(...))\n" + " plot.function(x, y, ...)\n" + " \n" + " else \n" + " plot.function(\n" + " x, y, \n" + " ylab = paste(\n" + " deparse(substitute(x)),\n" + " \"(x)\"), \n" + " ...)\n" + " }\n" + " else \n" + " UseMethod(\"plot\")\n" + "}\n"; EventBus eventBus_; }