/*
* Copyright (C) 2012-2016 NS Solutions Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.htmlhifive.tools.jslint.view;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.program.Program;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import com.htmlhifive.tools.jslint.JSLintPluginConstant;
import com.htmlhifive.tools.jslint.configure.ConfigBean;
import com.htmlhifive.tools.jslint.dialog.CreateEngineDialog;
import com.htmlhifive.tools.jslint.dialog.CreateOptionFileDialog;
import com.htmlhifive.tools.jslint.dialog.FileSelectionDialog;
import com.htmlhifive.tools.jslint.dialog.OptionSettingDialog;
import com.htmlhifive.tools.jslint.engine.option.CheckOptionFileWrapperFactory;
import com.htmlhifive.tools.jslint.engine.option.Engine;
import com.htmlhifive.tools.jslint.event.FilterBeanListChangeEvent;
import com.htmlhifive.tools.jslint.event.FilterBeanListChangeListener;
import com.htmlhifive.tools.jslint.logger.JSLintPluginLogger;
import com.htmlhifive.tools.jslint.logger.JSLintPluginLoggerFactory;
import com.htmlhifive.tools.jslint.messages.Messages;
/**
* 設定ページ用コンポジット.
*
* @author NS Solutions Corporation
*
*/
public class JslintPropertyComposite extends AbstractJsLintPropertyComposite {
/**
* プロジェクトリストの高さ.
*/
private static final int HEIGHT_PROJECT_LIST = 100;
/**
* 説明フィルタの高さ.
*/
private static final int HEIGHT_DESCRIPTION = 200;
/**
* ボタンの幅.
*/
private static final int BUTTON_WIDTH = 60;
/**
* ロガー.
*/
private static JSLintPluginLogger logger = JSLintPluginLoggerFactory.getLogger(JslintPropertyComposite.class);
/**
* オプション設定ファイルのパス.
*/
private Text textOptionPath;
/**
* JSLint.jsファイルパス.
*/
private Text textJslintPath;
/**
* 他プロジェクトの設定を利用するかチェックボックス.
*/
private Button checkUseOtherProject;
/**
* オプションファイル選択ボタン.
*/
private Button buttonOptionPath;
/**
* JSLint.jsファイル選択ボタン.
*/
private Button buttonJslintPath;
/**
* プロジェクト選択ビューア.
*/
private TableViewer listviewer;
/**
* オプション編集ボタン.
*/
private Button buttonOptionForm;
/**
* JSLintのヘルプページ用のリンク.
*/
private Link linkHelpPage;
/**
* グルーピングコンポジット.
*/
private DescriptionGroupComposite filterComp;
/**
* 新規ボタン.
*/
private Button buttonNewOption;
/**
* JslintDownloadボタン.
*/
private Button buttonNewJslint;
/**
* コンストラクタ.
*
* @param parent 親コンポジット
* @param project 選択プロジェクト
*
*/
public JslintPropertyComposite(Composite parent, IProject project) {
super(parent, project);
}
@Override
protected void createMainArea() {
createOtherProject();
createGroup1();
createGroup2();
}
/**
* 別プロジェクトの設定を選択するエリアの作成.
*/
private void createOtherProject() {
// 全体のベースコンポジット
Composite comp = createBaseComposite(2);
// JSLintの設定トップラベル
Label messageLabel = new Label(comp, SWT.None);
GridData gdMessageLabel = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1);
messageLabel.setText(Messages.DL0009.getText());
messageLabel.setLayoutData(gdMessageLabel);
// ヘルプリンクの作成
linkHelpPage = new Link(comp, SWT.None);
GridData gdLinkHelpPage = new GridData(SWT.RIGHT, SWT.CENTER, true, false, 1, 1);
linkHelpPage.setText(Messages.DL0010.getText());
linkHelpPage.setLayoutData(gdLinkHelpPage);
linkHelpPage.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
Program.launch(Messages.DL0011.getText());
}
});
Group group = createGroup(comp, Messages.WT0005.getText(), 2, 2);
// チェックボックス作成
checkUseOtherProject = new Button(group, SWT.CHECK);
GridData gdUseOtherProjectCheck = new GridData();
gdUseOtherProjectCheck.horizontalSpan = 1;
checkUseOtherProject.setLayoutData(gdUseOtherProjectCheck);
checkUseOtherProject.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
setActive(checkUseOtherProject.getSelection());
updateVariable();
}
});
// チェックボックスのラベル作成.
Label labelUseOtherProject = new Label(group, SWT.None);
GridData gdLabelUseOtherProject = new GridData();
gdLabelUseOtherProject.horizontalSpan = 1;
labelUseOtherProject.setText(Messages.DL0003.getText());
labelUseOtherProject.setLayoutData(gdLabelUseOtherProject);
// プロジェクトリスト.
listviewer = new TableViewer(group, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
listviewer.setContentProvider(new ArrayContentProvider());
listviewer.setLabelProvider(new WorkbenchLabelProvider());
GridData gdListviewer = new GridData(GridData.FILL_HORIZONTAL);
gdListviewer.horizontalSpan = 2;
gdListviewer.heightHint = HEIGHT_PROJECT_LIST;
listviewer.getControl().setLayoutData(gdListviewer);
listviewer.add(getJsLintProjects());
listviewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
updateVariable();
}
});
}
/**
* ベースコンポジットを生成する.
*
* @param numColumn カラム数
* @return ベースコンポジット
*/
private Composite createBaseComposite(int numColumn) {
Composite comp = new Composite(this, SWT.None);
comp.setLayoutData(new GridData(SWT.FILL, 1, true, false));
GridLayout layout = new GridLayout(numColumn, false);
comp.setLayout(layout);
return comp;
}
/**
* JSLint設定ファイルがあるプロジェクトを取得する.
*
* @return JSLint設定ファイルを持っているプロジェクト.
*/
private IProject[] getJsLintProjects() {
IProject[] allProjects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
List<IProject> jslintProjects = new ArrayList<IProject>();
for (IProject iProject : allProjects) {
if (iProject.getFile(".jslint") != null && iProject.getFile(".jslint").exists()) {
jslintProjects.add(iProject);
}
}
return (IProject[]) jslintProjects.toArray(new IProject[jslintProjects.size()]);
}
/**
* 上部のコンポジットを作成する.
*/
private void createGroup1() {
Group group = createGroup(createBaseComposite(1), Messages.DL0001.getText(), 1, 1);
textOptionPath = new Text(group, SWT.BORDER);
GridData gridOptionPath = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
textOptionPath.setLayoutData(gridOptionPath);
textOptionPath.setText(getConfigBean().getOptionFilePath());
textOptionPath.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
updateVariable();
}
});
// ボタン用コンポジット
Composite buttonComp = new Composite(group, SWT.None);
buttonComp.setLayout(GridLayoutFactory.fillDefaults().numColumns(3).create());
buttonComp.setLayoutData(GridDataFactory.fillDefaults().create());
buttonNewOption = locateButton(buttonComp, 1, Messages.B0005.getText());
buttonNewOption.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
CreateOptionFileDialog createOptionFileDialog = new CreateOptionFileDialog(getShell(), Messages.DT0007
.getText());
if (createOptionFileDialog.open() == Window.OK) {
String outputPath = createOptionFileDialog.getOutputFilePath();
logger.debug(createOptionFileDialog.getOutputFilePath());
try {
CheckOptionFileWrapperFactory.createCheckOptionFileWrapper(outputPath);
} catch (CoreException e1) {
e1.printStackTrace();
}
textOptionPath.setText(outputPath);
updateVariable();
}
}
});
buttonOptionPath = locateButton(buttonComp, 1, Messages.B0001.getText());
buttonOptionPath.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
FileSelectionDialog dialog = new FileSelectionDialog(getShell(), Messages.DT0001.getText(),
Messages.DM0001.format(Messages.E0001.getText()), new String[] { "xml" });
dialog.setInitialSelection(ResourcesPlugin.getWorkspace().getRoot()
.findMember(textOptionPath.getText()));
if (Window.OK == dialog.open()) {
IFile jsFile = (IFile) dialog.getFirstResult();
textOptionPath.setText(jsFile.getFullPath().toString());
}
}
});
buttonOptionForm = locateButton(buttonComp, 1, Messages.B0004.getText());
buttonOptionForm.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
OptionSettingDialog dialog = new OptionSettingDialog(getShell(), getProject(), Engine
.getEngine(getConfigBean().getJsLintPath()));
dialog.open();
}
});
}
/**
* 下部のコンポジットを作成する.
*/
private void createGroup2() {
Composite composite = createBaseComposite(1);
Group group = createGroup(composite, Messages.DL0002.getText(), 1, 1);
// JSLint説明ラベル
Label descLabel = new Label(group, SWT.None);
GridData gdDescLabel = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
descLabel.setLayoutData(gdDescLabel);
descLabel.setText(Messages.DL0012.getText());
// リンクコンポジット
Composite linkComp = new Composite(group, SWT.None);
linkComp.setLayout(GridLayoutFactory.swtDefaults().numColumns(2).equalWidth(false).margins(30, 5).create());
GridData gdlinkComp = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1);
linkComp.setLayoutData(gdlinkComp);
// JSLINTのリンク
Link linkJslint = new Link(linkComp, SWT.None);
GridData gdLinkJslint = GridDataFactory.fillDefaults().create();
linkJslint.setLayoutData(gdLinkJslint);
linkJslint.setText(Messages.DL0013.getText());
linkJslint.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
Program.launch(Messages.DL0014.getText());
}
});
// JSHINTのリンク
Link linkJshint = new Link(linkComp, SWT.None);
GridData gdLinkJshint = GridDataFactory.fillDefaults().indent(50, 0).create();
linkJshint.setLayoutData(gdLinkJshint);
linkJshint.setText(Messages.DL0015.getText());
linkJshint.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
Program.launch(Messages.DL0016.getText());
}
});
textJslintPath = new Text(group, SWT.BORDER);
GridData gridOptionPath = new GridData(GridData.FILL_HORIZONTAL);
gridOptionPath.horizontalSpan = 1;
textJslintPath.setLayoutData(gridOptionPath);
textJslintPath.setText(getConfigBean().getJsLintPath());
textJslintPath.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
updateVariable();
}
});
// 新規と選択ボタンコンポジット.
Composite buttonComposite = new Composite(group, SWT.NONE);
buttonComposite.setLayout(GridLayoutFactory.fillDefaults().numColumns(2).create());
// 新規ダウンロードボタン
buttonNewJslint = locateButton(buttonComposite, 1, Messages.B0008.getText());
buttonNewJslint.setLayoutData(GridDataFactory.fillDefaults().create());
buttonNewJslint.setToolTipText(Messages.DTT0001.getText());
buttonNewJslint.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
CreateEngineDialog dialog = new CreateEngineDialog(getShell(), getProject(), Messages.DT0010.getText());
if (dialog.open() == Dialog.OK) {
textJslintPath.setText(dialog.getEngineFilePath());
updateVariable();
}
}
});
buttonJslintPath = locateButton(buttonComposite, 1, Messages.B0001.getText());
buttonJslintPath.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
FileSelectionDialog dialog = new FileSelectionDialog(getShell(), Messages.DT0002.getText(),
Messages.DM0001.format(Messages.E0000.getText()),
new String[] { JSLintPluginConstant.EXTENTION_JS });
dialog.setInitialSelection(ResourcesPlugin.getWorkspace().getRoot()
.findMember(textJslintPath.getText()));
if (Window.OK == dialog.open()) {
IFile jsFile = (IFile) dialog.getFirstResult();
textJslintPath.setText(jsFile.getFullPath().toString());
}
}
});
Group descriptionFilter = createGroup(composite, Messages.DL0006.getText(), 1, 1);
((GridData) descriptionFilter.getLayoutData()).heightHint = HEIGHT_DESCRIPTION;
filterComp = new DescriptionGroupComposite(descriptionFilter, SWT.None);
filterComp.addFilterBeanListChangeListener(new FilterBeanListChangeListener() {
@Override
public void modify(FilterBeanListChangeEvent event) {
updateVariable();
}
});
}
/**
* Gridカラム8のグループを生成する.
*
* @param parent 親コンポジット
* @param groupName グループ名
* @param column カラム数
* @param horizontalSpan horizontalSpan
* @return グループ
*/
private Group createGroup(Composite parent, String groupName, int column, int horizontalSpan) {
Group group = new Group(parent, SWT.NONE);
GridLayout layout = new GridLayout(column, false);
group.setLayout(layout);
GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false, horizontalSpan, 1);
group.setLayoutData(gd);
group.setText(groupName);
return group;
}
/**
* GridLayoutのレイアウトを持つコンポジット(parent)にボタンを配置する.
*
* @param parent 親コンポジット
* @param horizontalSpan カラム数.
* @param text ボタン名
* @return 配置したボタン
*/
private Button locateButton(Composite parent, int horizontalSpan, String text) {
Button button = new Button(parent, SWT.None);
GridData gridbutton = new GridData(SWT.LEFT, SWT.CENTER, false, false, horizontalSpan, 1);
gridbutton.widthHint = BUTTON_WIDTH;
button.setLayoutData(gridbutton);
button.setText(text);
return button;
}
/**
* 他のプロジェクトを利用するかどうかによる、ウィジェットの活性・非活性を設定する.
*
* @param useOtherProject 他プロジェクトを使用するかどうか.
*/
private void setActive(boolean useOtherProject) {
listviewer.getControl().setEnabled(useOtherProject);
buttonJslintPath.setEnabled(!useOtherProject);
textJslintPath.setEnabled(!useOtherProject);
buttonOptionPath.setEnabled(!useOtherProject);
buttonOptionForm.setEnabled(!useOtherProject);
textOptionPath.setEnabled(!useOtherProject);
filterComp.setEnabled(!useOtherProject);
buttonNewOption.setEnabled(!useOtherProject);
}
@Override
protected void doUpdate() {
getConfigBean().setJsLintPath(textJslintPath.getText());
getConfigBean().setOptionFilePath(textOptionPath.getText());
IStructuredSelection selection = (IStructuredSelection) listviewer.getSelection();
if (selection != null && selection.getFirstElement() != null) {
getConfigBean().setOtherProjectPath(((IProject) selection.getFirstElement()).getName());
}
getConfigBean().setUseOtherProject(checkUseOtherProject.getSelection());
getConfigBean().replaceFilterBeans(filterComp.getFilterBeans());
if (existsFile(getConfigBean().getJsLintPath())
&& existsFile(getConfigBean().getOptionFilePath())
&& StringUtils.endsWithAny(getConfigBean().getJsLintPath(), new String[] {
JSLintPluginConstant.JS_HINT_NAME, JSLintPluginConstant.JS_LINT_NAME })) {
buttonOptionForm.setEnabled(true);
} else {
buttonOptionForm.setEnabled(false);
}
}
/**
* ワークスペース内に指定したパスのファイルが存在するかをチェックする.
*
* @param path パス.
* @return 指定したファイルが存在するかどうか.
*/
private boolean existsFile(String path) {
if (StringUtils.isEmpty(path)) {
return false;
}
if (ResourcesPlugin.getWorkspace().getRoot().exists(new Path(path))) {
return true;
}
return false;
}
@Override
protected void doSetup(ConfigBean configBean) {
checkUseOtherProject.setSelection(configBean.isUseOtherProject());
textJslintPath.setText(configBean.getJsLintPath());
textOptionPath.setText(configBean.getOptionFilePath());
filterComp.setUpTableElement(configBean.getFilterBeans());
if (StringUtils.isNotEmpty(configBean.getOtherProjectPath())) {
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(configBean.getOtherProjectPath());
if (project != null) {
listviewer.setSelection(new StructuredSelection(project));
}
}
setActive(configBean.isUseOtherProject());
}
}