1
0
mirror of https://github.com/1C-Company/v8-code-style.git synced 2024-12-01 02:32:18 +02:00

#824 Автоматическое создание структуры модуля

This commit is contained in:
Dmitriy Marmyshev 2021-10-28 19:18:20 +03:00 committed by GitHub
parent 26a45bd3ef
commit 4eedcf9ff6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
60 changed files with 2392 additions and 6 deletions

View File

@ -11,6 +11,7 @@
- Автосортировка метаданных, сортировка объектов верхнего уровня по умолчанию, для подчиненных настраивается - Автосортировка метаданных, сортировка объектов верхнего уровня по умолчанию, для подчиненных настраивается
- Выбор подходящего тип общего модуля из списка при создании нового - Выбор подходящего тип общего модуля из списка при создании нового
- Панель "Bsl Документирующий комментарий" - Панель "Bsl Документирующий комментарий"
- Автоматическое создание структуры модуля
### Новые проверки ### Новые проверки

View File

@ -21,6 +21,7 @@
- [Авто-сортировка метаданных](docs/tools/autosort.md) - [Авто-сортировка метаданных](docs/tools/autosort.md)
- [Создание общих модулей по типам](docs/tools/common-module-types.md) - [Создание общих модулей по типам](docs/tools/common-module-types.md)
- [Панель "Bsl Документирующий комментарий"](docs/tools/bsl-doc-comment-view.md) - [Панель "Bsl Документирующий комментарий"](docs/tools/bsl-doc-comment-view.md)
- [Автоматическое создание структуры модуля](docs/tools/module-structure.md)

View File

@ -59,6 +59,32 @@
<sonar.moduleKey>${project.groupId}:${project.artifactId}</sonar.moduleKey> <sonar.moduleKey>${project.groupId}:${project.artifactId}</sonar.moduleKey>
<!-- JaCoCo code coverage, pass to SonarQube --> <!-- JaCoCo code coverage, pass to SonarQube -->
<sonar.coverage.jacoco.xmlReportPaths>../../**/target/site/jacoco*/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths> <sonar.coverage.jacoco.xmlReportPaths>../../**/target/site/jacoco*/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>
<sonar.issue.ignore.multicriteria>e1,e2,e3,e4,t1,t2,t3,t4</sonar.issue.ignore.multicriteria>
<!-- Static non-final field names should comply with a naming convention -->
<sonar.issue.ignore.multicriteria.e1.ruleKey>java:S3008</sonar.issue.ignore.multicriteria.e1.ruleKey>
<sonar.issue.ignore.multicriteria.e1.resourceKey>**/Messages.java</sonar.issue.ignore.multicriteria.e1.resourceKey>
<!-- Instance methods should not write to "static" fields -->
<sonar.issue.ignore.multicriteria.e2.ruleKey>java:S2696</sonar.issue.ignore.multicriteria.e2.ruleKey>
<sonar.issue.ignore.multicriteria.e2.resourceKey>**/*Plugin.java</sonar.issue.ignore.multicriteria.e2.resourceKey>
<!-- Generic exceptions should never be thrown -->
<sonar.issue.ignore.multicriteria.e3.ruleKey>java:S112</sonar.issue.ignore.multicriteria.e3.ruleKey>
<sonar.issue.ignore.multicriteria.e3.resourceKey>**/*Plugin.java</sonar.issue.ignore.multicriteria.e3.resourceKey>
<!-- Non-primitive fields should not be "volatile" -->
<sonar.issue.ignore.multicriteria.e4.ruleKey>java:S3077</sonar.issue.ignore.multicriteria.e4.ruleKey>
<sonar.issue.ignore.multicriteria.e4.resourceKey>**/*Plugin.java</sonar.issue.ignore.multicriteria.e4.resourceKey>
<!-- Generic exceptions should never be thrown -->
<sonar.issue.ignore.multicriteria.t1.ruleKey>java:S112</sonar.issue.ignore.multicriteria.t1.ruleKey>
<sonar.issue.ignore.multicriteria.t1.resourceKey>/tests/**/*.java</sonar.issue.ignore.multicriteria.t1.resourceKey>
<!-- Null pointers should not be dereferenced -->
<sonar.issue.ignore.multicriteria.t2.ruleKey>java:S2259</sonar.issue.ignore.multicriteria.t2.ruleKey>
<sonar.issue.ignore.multicriteria.t2.resourceKey>/tests/**/*.java</sonar.issue.ignore.multicriteria.t2.resourceKey>
<!-- "throws" declarations should not be superfluous -->
<sonar.issue.ignore.multicriteria.t3.ruleKey>java:S1130</sonar.issue.ignore.multicriteria.t3.ruleKey>
<sonar.issue.ignore.multicriteria.t3.resourceKey>/tests/**/*.java</sonar.issue.ignore.multicriteria.t3.resourceKey>
<!-- Reflection should not be used to increase accessibility of classes, methods, or fields -->
<sonar.issue.ignore.multicriteria.t4.ruleKey>java:S3011</sonar.issue.ignore.multicriteria.t4.ruleKey>
<sonar.issue.ignore.multicriteria.t4.resourceKey>/tests/**/*.java</sonar.issue.ignore.multicriteria.t4.resourceKey>
</properties> </properties>
<build> <build>

View File

@ -18,14 +18,22 @@ Bundle-RequiredExecutionEnvironment: JavaSE-11
Automatic-Module-Name: com.e1c.v8codestyle.bsl.ui Automatic-Module-Name: com.e1c.v8codestyle.bsl.ui
Bundle-ActivationPolicy: lazy Bundle-ActivationPolicy: lazy
Bundle-Localization: plugin Bundle-Localization: plugin
Import-Package: com._1c.g5.v8.dt.bsl.comment;version="[3.0.0,4.0.0)", Import-Package: com._1c.g5.v8.bm.core;version="[7.5.0,8.0.0)",
com._1c.g5.v8.dt.bsl.comment;version="[3.0.0,4.0.0)",
com._1c.g5.v8.dt.bsl.common;version="[6.0.0,7.0.0)", com._1c.g5.v8.dt.bsl.common;version="[6.0.0,7.0.0)",
com._1c.g5.v8.dt.bsl.documentation.comment;version="[3.0.0,4.0.0)", com._1c.g5.v8.dt.bsl.documentation.comment;version="[3.0.0,4.0.0)",
com._1c.g5.v8.dt.bsl.model;version="[4.0.0,5.0.0)", com._1c.g5.v8.dt.bsl.model;version="[4.0.0,5.0.0)",
com._1c.g5.v8.dt.bsl.ui.editor;version="[8.0.0,9.0.0)", com._1c.g5.v8.dt.bsl.ui.editor;version="[8.0.0,9.0.0)",
com._1c.g5.v8.dt.bsl.util;version="[7.0.0,8.0.0)",
com._1c.g5.v8.dt.common;version="[6.0.0,7.0.0)", com._1c.g5.v8.dt.common;version="[6.0.0,7.0.0)",
com._1c.g5.v8.dt.core.filesystem;version="[5.0.0,6.0.0)",
com._1c.g5.v8.dt.core.platform;version="[10.0.0,11.0.0)", com._1c.g5.v8.dt.core.platform;version="[10.0.0,11.0.0)",
com._1c.g5.v8.dt.mcore;version="[6.0.0,7.0.0)", com._1c.g5.v8.dt.mcore;version="[6.0.0,7.0.0)",
com._1c.g5.v8.dt.metadata.mdclass;version="[8.0.0,9.0.0)",
com._1c.g5.v8.dt.theming.ui.util;version="[1.0.0,2.0.0)", com._1c.g5.v8.dt.theming.ui.util;version="[1.0.0,2.0.0)",
com._1c.g5.v8.dt.ui.util;version="[6.0.0,7.0.0)",
com._1c.g5.v8.dt.ui.wizards;version="[8.0.0,9.0.0)",
com._1c.g5.wiring;version="[2.2.0,3.0.0)", com._1c.g5.wiring;version="[2.2.0,3.0.0)",
com._1c.g5.wiring.binder;version="[1.1.0,2.0.0)" com._1c.g5.wiring.binder;version="[1.1.0,2.0.0)",
com.e1c.v8codestyle.bsl;version="[0.1.0,0.2.0)",
com.e1c.v8codestyle.bsl.strict;version="[0.1.0,0.2.0)"

View File

@ -15,6 +15,10 @@
pluginName = 1C:Code style V8 Bsl UI plugin pluginName = 1C:Code style V8 Bsl UI plugin
preferences.modulestructure.name = Module structure
properties.modulestructure.name = Module structure
providerName = 1C-Soft LLC providerName = 1C-Soft LLC
views.BslDocCommentView.name = Bsl Documentation Comment views.BslDocCommentView.name = Bsl Documentation Comment

View File

@ -44,5 +44,112 @@
</view> </view>
</perspectiveExtension> </perspectiveExtension>
</extension> </extension>
<extension
point="com._1c.g5.v8.dt.ui.dtNewWizardRelatedModelsFactories">
<factory
class="com.e1c.v8codestyle.internal.bsl.ui.ExecutableExtensionFactory:com.e1c.v8codestyle.internal.bsl.ui.wizard.ModuleStructureNewWizardRelatedModelsFactory"
order="120">
<triggers>
<modelClass eClass="Configuration" />
<modelClass eClass="CatalogForm" />
<modelClass eClass="DocumentForm" />
<modelClass eClass="EnumForm" />
<modelClass eClass="ChartOfCharacteristicTypesForm" />
<modelClass eClass="InformationRegisterForm" />
<modelClass eClass="DocumentJournalForm" />
<modelClass eClass="ExchangePlanForm" />
<modelClass eClass="DataProcessorForm" />
<modelClass eClass="AccumulationRegisterForm" />
<modelClass eClass="ReportForm" />
<modelClass eClass="CommonModule" />
<modelClass eClass="Bot" />
<modelClass eClass="IntegrationService" />
<modelClass eClass="ExchangePlan" />
<modelClass eClass="WebService" />
<modelClass eClass="HTTPService" />
<modelClass eClass="Constant" />
<modelClass eClass="Document" />
<modelClass eClass="Catalog" />
<modelClass eClass="Document" />
<modelClass eClass="Sequence" />
<modelClass eClass="DocumentJournal" />
<modelClass eClass="Report" />
<modelClass eClass="ExternalReport" />
<modelClass eClass="DataProcessor" />
<modelClass eClass="ExternalDataProcessor" />
<modelClass eClass="InformationRegister" />
<modelClass eClass="AccumulationRegister" />
<modelClass eClass="SettingsStorage" />
<modelClass eClass="Enum" />
<modelClass eClass="Task" />
<modelClass eClass="BusinessProcess" />
<modelClass eClass="Table" />
<modelClass eClass="Cube" />
<modelClass eClass="DimensionTable" />
<modelClass eClass="AccumulationRegisterCommand" />
<modelClass eClass="BusinessProcessCommand" />
<modelClass eClass="CatalogCommand" />
<modelClass eClass="ChartOfCharacteristicTypesCommand" />
<modelClass eClass="CommonCommand" />
<modelClass eClass="DataProcessorCommand" />
<modelClass eClass="DocumentCommand" />
<modelClass eClass="DocumentJournalCommand" />
<modelClass eClass="EnumCommand" />
<modelClass eClass="ExchangePlanCommand" />
<modelClass eClass="FilterCriterionCommand" />
<modelClass eClass="InformationRegisterCommand" />
<modelClass eClass="ReportCommand" />
<modelClass eClass="TaskCommand" />
<modelClass eClass="TableCommand" />
<modelClass eClass="CubeCommand" />
<modelClass eClass="DimensionTableCommand" />
<modelClass eClass="CommonForm" />
<modelClass eClass="CatalogForm" />
<modelClass eClass="DocumentForm" />
<modelClass eClass="EnumForm" />
<modelClass eClass="ChartOfAccountsForm" />
<modelClass eClass="ChartOfCalculationTypesForm" />
<modelClass eClass="ChartOfCharacteristicTypesForm" />
<modelClass eClass="InformationRegisterForm" />
<modelClass eClass="DocumentJournalForm" />
<modelClass eClass="ExchangePlanForm" />
<modelClass eClass="FilterCriterionForm" />
<modelClass eClass="DataProcessorForm" />
<modelClass eClass="AccountingRegisterForm" />
<modelClass eClass="AccumulationRegisterForm" />
<modelClass eClass="ReportForm" />
<modelClass eClass="BusinessProcessForm" />
<modelClass eClass="TaskForm" />
<modelClass eClass="SettingsStorageForm" />
<modelClass eClass="CalculationRegisterForm" />
<modelClass eClass="TableForm" />
<modelClass eClass="CubeForm" />
<modelClass eClass="DimensionTableForm" />
</triggers>
</factory>
</extension>
<extension
point="org.eclipse.ui.propertyPages">
<page
category="com._1c.g5.v8.dt.bsl.Bsl"
class="com.e1c.v8codestyle.internal.bsl.ui.ExecutableExtensionFactory:com.e1c.v8codestyle.internal.bsl.ui.properties.ModuleStructurePropertyPage"
id="com.e1c.v8codestyle.bsl.ui.properties.moduleStructurePropertyPage"
name="%properties.modulestructure.name">
<enabledWhen>
<instanceof
value="org.eclipse.core.resources.IProject">
</instanceof>
</enabledWhen>
</page>
</extension>
<extension
point="org.eclipse.ui.preferencePages">
<page
category="com._1c.g5.v8.dt.bsl.Bsl"
class="com.e1c.v8codestyle.internal.bsl.ui.preferences.ModuleStructurePreferencePage"
id="com.e1c.v8codestyle.bsl.ui.preferences.ModuleStructurePreferencePage"
name="%preferences.modulestructure.name">
</page>
</extension>
</plugin> </plugin>

View File

@ -1,3 +1,4 @@
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
############################################################################### ###############################################################################
# Copyright (C) 2021, 1C-Soft LLC and others. # Copyright (C) 2021, 1C-Soft LLC and others.
# #
@ -10,10 +11,13 @@
# Contributors: # Contributors:
# 1C-Soft LLC - initial API and implementation # 1C-Soft LLC - initial API and implementation
############################################################################### ###############################################################################
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
pluginName = 1С:Стандарты разработки V8 UI плагин Встроенного языка pluginName = 1С:Стандарты разработки V8 UI плагин Встроенного языка
preferences.modulestructure.name = Структура модуля
properties.modulestructure.name = Структура модуля
providerName = ООО "1С-Софт" providerName = ООО "1С-Софт"
views.BslDocCommentView.name = Bsl Документирующий комментарий views.BslDocCommentView.name = Bsl Документирующий комментарий

View File

@ -15,8 +15,11 @@ package com.e1c.v8codestyle.internal.bsl.ui;
import org.eclipse.core.runtime.Plugin; import org.eclipse.core.runtime.Plugin;
import com._1c.g5.v8.dt.bsl.common.IBslPreferences; import com._1c.g5.v8.dt.bsl.common.IBslPreferences;
import com._1c.g5.v8.dt.core.filesystem.IQualifiedNameFilePathConverter;
import com._1c.g5.v8.dt.core.platform.IResourceLookup; import com._1c.g5.v8.dt.core.platform.IResourceLookup;
import com._1c.g5.v8.dt.core.platform.IV8ProjectManager;
import com._1c.g5.wiring.AbstractServiceAwareModule; import com._1c.g5.wiring.AbstractServiceAwareModule;
import com.e1c.v8codestyle.bsl.IModuleStructureProvider;
/** /**
* The external dependencies for plugin * The external dependencies for plugin
@ -36,8 +39,14 @@ class ExternalDependenciesModule
@Override @Override
protected void doConfigure() protected void doConfigure()
{ {
// V8 services
bind(IResourceLookup.class).toService(); bind(IResourceLookup.class).toService();
bind(IBslPreferences.class).toService(); bind(IBslPreferences.class).toService();
bind(IQualifiedNameFilePathConverter.class).toService();
bind(IV8ProjectManager.class).toService();
// CodeStyle Services
bind(IModuleStructureProvider.class).toService();
} }
} }

View File

@ -0,0 +1,35 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.internal.bsl.ui.preferences;
import org.eclipse.osgi.util.NLS;
/**
* @author Dmitriy Marmyshev
*
*/
final class Messages
extends NLS
{
private static final String BUNDLE_NAME = "com.e1c.v8codestyle.internal.bsl.ui.preferences.messages"; //$NON-NLS-1$
public static String ModuleStructurePreferencePage_Automatically_create_module_structure;
static
{
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
}
private Messages()
{
}
}

View File

@ -0,0 +1,61 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.internal.bsl.ui.preferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jface.preference.BooleanFieldEditor;
import org.eclipse.jface.preference.FieldEditorPreferencePage;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
import org.eclipse.ui.preferences.ScopedPreferenceStore;
import com.e1c.v8codestyle.bsl.IModuleStructureProvider;
/**
* The preference page of module structure settings.
* Allows to disable auto-creating module structure.
*
* @author Dmitriy Marmyshev
*/
public class ModuleStructurePreferencePage
extends FieldEditorPreferencePage
implements IWorkbenchPreferencePage
{
/**
* Instantiates a new module structure preference page.
*/
public ModuleStructurePreferencePage()
{
super(GRID);
IPreferenceStore preferenceStore =
new ScopedPreferenceStore(InstanceScope.INSTANCE, IModuleStructureProvider.PREF_QUALIFIER);
setPreferenceStore(preferenceStore);
}
@Override
public void createFieldEditors()
{
addField(new BooleanFieldEditor(IModuleStructureProvider.PREF_KEY_CREATE_STRUCTURE,
Messages.ModuleStructurePreferencePage_Automatically_create_module_structure, getFieldEditorParent()));
}
@Override
public void init(IWorkbench workbench)
{
// Do nothing
}
}

View File

@ -0,0 +1,14 @@
###############################################################################
# Copyright (C) 2021, 1C-Soft LLC and others.
#
# This program and the accompanying materials are made
# available under the terms of the Eclipse Public License 2.0
# which is available at https://www.eclipse.org/legal/epl-2.0/
#
# SPDX-License-Identifier: EPL-2.0
#
# Contributors:
# 1C-Soft LLC - initial API and implementation
###############################################################################
ModuleStructurePreferencePage_Automatically_create_module_structure = &Automatically create module structure

View File

@ -0,0 +1,15 @@
###############################################################################
# Copyright (C) 2021, 1C-Soft LLC and others.
#
# This program and the accompanying materials are made
# available under the terms of the Eclipse Public License 2.0
# which is available at https://www.eclipse.org/legal/epl-2.0/
#
# SPDX-License-Identifier: EPL-2.0
#
# Contributors:
# 1C-Soft LLC - initial API and implementation
###############################################################################
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
ModuleStructurePreferencePage_Automatically_create_module_structure = &Автоматически создавать структуру модуля

View File

@ -0,0 +1,40 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.internal.bsl.ui.properties;
import org.eclipse.osgi.util.NLS;
/**
* @author Dmitriy Marmyshev
*
*/
final class Messages
extends NLS
{
private static final String BUNDLE_NAME = "com.e1c.v8codestyle.internal.bsl.ui.properties.messages"; //$NON-NLS-1$
public static String ModuleStructurePropertyPage_Automatically_create_module_structure;
public static String ModuleStructurePropertyPage_Open_template;
public static String ModuleStructurePropertyPage_Open_template_tooltip;
public static String ModuleStructurePropertyPage_Save_custom_template_to_project_settings;
public static String ModuleStructurePropertyPage_Save_settings;
public static String ModuleStructurePropertyPage_Select_module_type_to_create_custom_structure_templates;
static
{
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
}
private Messages()
{
}
}

View File

@ -0,0 +1,367 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.internal.bsl.ui.properties;
import static com.e1c.v8codestyle.bsl.strict.StrictTypeUtil.BSL_FILE_EXTENSION;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Supplier;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.PreferenceDialog;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.dialogs.PropertyPage;
import org.osgi.service.prefs.BackingStoreException;
import com._1c.g5.v8.dt.bsl.model.ModuleType;
import com._1c.g5.v8.dt.common.FileUtil;
import com._1c.g5.v8.dt.common.StringUtils;
import com._1c.g5.v8.dt.core.platform.IV8Project;
import com._1c.g5.v8.dt.core.platform.IV8ProjectManager;
import com._1c.g5.v8.dt.metadata.mdclass.ScriptVariant;
import com._1c.g5.v8.dt.ui.util.OpenHelper;
import com.e1c.v8codestyle.bsl.IModuleStructureProvider;
import com.e1c.v8codestyle.internal.bsl.ui.UiPlugin;
import com.google.inject.Inject;
/**
* The property page of module structure settings.
* Allows to disable auto-creating module structure or manage custom project templates.
*
* @author Dmitriy Marmyshev
*/
public class ModuleStructurePropertyPage
extends PropertyPage
{
private static final IPath FOLDER_SETTINGS = new Path(".settings/templates"); //$NON-NLS-1$
private final IModuleStructureProvider moduleStructureProvider;
private final IV8ProjectManager v8ProjectManager;
private Button createStructureButton;
private CheckboxTableViewer checkBoxViewer;
private final Set<ModuleType> existTemplates = new HashSet<>();
private boolean currentCreateStructure;
private final OpenHelper openHelper = new OpenHelper();
/**
* Constructor for module structure Property Page.
*
* @param moduleStructureProvider the module structure provider, cannot be {@code null}.
* @param v8ProjectManager the v8 project manager, cannot be {@code null}.
*/
@Inject
public ModuleStructurePropertyPage(IModuleStructureProvider moduleStructureProvider,
IV8ProjectManager v8ProjectManager)
{
super();
this.moduleStructureProvider = moduleStructureProvider;
this.v8ProjectManager = v8ProjectManager;
}
/**
* @see PreferencePage#createContents(Composite)
*/
@Override
protected Control createContents(Composite parent)
{
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
composite.setLayout(layout);
GridData data = new GridData(GridData.FILL);
data.grabExcessHorizontalSpace = true;
composite.setLayoutData(data);
addFirstSection(composite);
addSeparator(composite);
addSecondSection(composite);
return composite;
}
private Composite createDefaultComposite(Composite parent)
{
Composite composite = new Composite(parent, SWT.NULL);
GridLayout layout = new GridLayout();
layout.numColumns = 2;
composite.setLayout(layout);
GridData data = new GridData();
data.verticalAlignment = GridData.FILL;
data.horizontalAlignment = GridData.FILL;
composite.setLayoutData(data);
return composite;
}
@Override
protected void performDefaults()
{
super.performDefaults();
createStructureButton.setSelection(IModuleStructureProvider.PREF_DEFAULT_CREATE_STRUCTURE);
existTemplates.forEach(type -> checkBoxViewer.setChecked(type, true));
}
@Override
public boolean performOk()
{
ProjectScope scope = new ProjectScope(getProject());
IEclipsePreferences node = scope.getNode(IModuleStructureProvider.PREF_QUALIFIER);
boolean value = createStructureButton.getSelection();
node.putBoolean(IModuleStructureProvider.PREF_KEY_CREATE_STRUCTURE, value);
try
{
node.flush();
}
catch (BackingStoreException e)
{
UiPlugin.logError(e);
return false;
}
currentCreateStructure = value;
for (ModuleType type : ModuleType.VALUES)
{
if (checkBoxViewer.getChecked(type) && !existTemplates.contains(type))
{
saveTemplate(type);
}
else if (existTemplates.contains(type) && !checkBoxViewer.getChecked(type))
{
removeTemplate(type);
}
}
loadExistTemplate();
return true;
}
private void saveTemplate(ModuleType type)
{
IFile file = getFileByType(type);
if (file.isAccessible())
{
return;
}
IV8Project v8Project = v8ProjectManager.getProject(getProject());
if (v8Project == null)
{
return;
}
ScriptVariant script = v8Project.getScriptVariant();
Supplier<InputStream> content = moduleStructureProvider.getModuleStructureTemplate(getProject(), type, script);
if (content == null)
{
return;
}
try
{
FileUtil.createParentFolders(file);
}
catch (CoreException e)
{
UiPlugin.logError(e);
return;
}
try (InputStream in = content.get())
{
file.create(in, true, new NullProgressMonitor());
}
catch (CoreException | IOException e)
{
UiPlugin.logError(e);
}
}
private void removeTemplate(ModuleType type)
{
IFile file = getFileByType(type);
if (!file.isAccessible())
{
return;
}
try
{
file.delete(true, true, new NullProgressMonitor());
}
catch (CoreException e)
{
UiPlugin.logError(e);
}
}
private void addFirstSection(Composite parent)
{
Composite composite = createDefaultComposite(parent);
Label createStructureLabel = new Label(composite, SWT.NONE);
createStructureLabel.setText(Messages.ModuleStructurePropertyPage_Automatically_create_module_structure);
currentCreateStructure = moduleStructureProvider.canCreateStructure(getProject());
createStructureButton = new Button(composite, SWT.CHECK);
createStructureButton.setSelection(currentCreateStructure);
}
private void addSeparator(Composite parent)
{
Label separator = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
GridData gridData = new GridData();
gridData.horizontalAlignment = GridData.FILL;
gridData.grabExcessHorizontalSpace = true;
separator.setLayoutData(gridData);
}
private void addSecondSection(Composite parent)
{
Composite composite = createDefaultComposite(parent);
Label customTemplatesLabel = new Label(composite, SWT.NONE | SWT.WRAP);
customTemplatesLabel
.setText(Messages.ModuleStructurePropertyPage_Select_module_type_to_create_custom_structure_templates);
GridData data = new GridData();
data.horizontalAlignment = GridData.FILL;
data.horizontalSpan = 2;
customTemplatesLabel.setLayoutData(data);
checkBoxViewer = CheckboxTableViewer.newCheckList(composite,
SWT.H_SCROLL | SWT.V_SCROLL | SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER);
checkBoxViewer.setContentProvider(ArrayContentProvider.getInstance());
checkBoxViewer.setLabelProvider(LabelProvider.createTextProvider(type -> {
if (type instanceof ModuleType)
{
String label = StringUtils.nameToText(((ModuleType)type).getName()).toLowerCase();
return StringUtils.capitalize(label);
}
return type == null ? "" : type.toString(); //$NON-NLS-1$
}));
checkBoxViewer.setInput(ModuleType.VALUES);
Composite buttonPanel = createDefaultComposite(composite);
Button openButton = new Button(buttonPanel, SWT.PUSH);
openButton.setText(Messages.ModuleStructurePropertyPage_Open_template);
openButton.setToolTipText(Messages.ModuleStructurePropertyPage_Open_template_tooltip);
openButton.setEnabled(false);
openButton.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> {
IStructuredSelection selection = checkBoxViewer.getStructuredSelection();
if (!selection.isEmpty())
{
ModuleType type = (ModuleType)selection.getFirstElement();
saveSettingsAndOpenTemplateAndClose(type);
}
}));
checkBoxViewer.addPostSelectionChangedListener(e -> {
boolean enable = !e.getStructuredSelection().isEmpty()
&& checkBoxViewer.getChecked(e.getStructuredSelection().getFirstElement());
openButton.setEnabled(enable);
});
loadExistTemplate();
}
private IProject getProject()
{
return (IProject)getElement();
}
private void loadExistTemplate()
{
existTemplates.clear();
for (ModuleType type : ModuleType.VALUES)
{
IFile file = getFileByType(type);
if (file.isAccessible())
{
existTemplates.add(type);
}
}
checkBoxViewer.setCheckedElements(new ModuleType[0]);
existTemplates.forEach(type -> checkBoxViewer.setChecked(type, true));
}
private IFile getFileByType(ModuleType type)
{
return getProject()
.getFile(FOLDER_SETTINGS.append(type.getName().toLowerCase()).addFileExtension(BSL_FILE_EXTENSION));
}
private boolean isDirty()
{
if (createStructureButton.getSelection() != currentCreateStructure)
{
return true;
}
Set<Object> checked = Set.of(checkBoxViewer.getCheckedElements());
return !existTemplates.equals(checked);
}
private void saveSettingsAndOpenTemplateAndClose(ModuleType type)
{
if (isDirty())
{
if (!MessageDialog.openQuestion(getShell(), Messages.ModuleStructurePropertyPage_Save_settings,
Messages.ModuleStructurePropertyPage_Save_custom_template_to_project_settings))
{
return;
}
if (!performOk())
{
return;
}
}
getShell().getDisplay().asyncExec(() -> {
IFile file = getFileByType(type);
if (file.isAccessible())
{
openHelper.openEditor(file, null);
}
});
if (getContainer() instanceof PreferenceDialog)
{
((PreferenceDialog)getContainer()).close();
}
}
}

View File

@ -0,0 +1,24 @@
###############################################################################
# Copyright (C) 2021, 1C-Soft LLC and others.
#
# This program and the accompanying materials are made
# available under the terms of the Eclipse Public License 2.0
# which is available at https://www.eclipse.org/legal/epl-2.0/
#
# SPDX-License-Identifier: EPL-2.0
#
# Contributors:
# 1C-Soft LLC - initial API and implementation
###############################################################################
ModuleStructurePropertyPage_Automatically_create_module_structure = Automatically create module structure
ModuleStructurePropertyPage_Open_template = Open template
ModuleStructurePropertyPage_Open_template_tooltip = Open existing custom project template with saving settings.
ModuleStructurePropertyPage_Save_custom_template_to_project_settings = Save custom templates to the project settings?
ModuleStructurePropertyPage_Save_settings = Save settings?
ModuleStructurePropertyPage_Select_module_type_to_create_custom_structure_templates = Select module type to create custom structure templates.\nOr deselect to remove existing custom template.

View File

@ -0,0 +1,25 @@
###############################################################################
# Copyright (C) 2021, 1C-Soft LLC and others.
#
# This program and the accompanying materials are made
# available under the terms of the Eclipse Public License 2.0
# which is available at https://www.eclipse.org/legal/epl-2.0/
#
# SPDX-License-Identifier: EPL-2.0
#
# Contributors:
# 1C-Soft LLC - initial API and implementation
###############################################################################
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
ModuleStructurePropertyPage_Automatically_create_module_structure = Автоматически создавать структуру модуля
ModuleStructurePropertyPage_Open_template = Открыть шаблон
ModuleStructurePropertyPage_Open_template_tooltip = Открыть существующий шаблон проекта с сохранением настроек.
ModuleStructurePropertyPage_Save_custom_template_to_project_settings = Сохранить шаблоны в настройки проекта?
ModuleStructurePropertyPage_Save_settings = Сохранить настройки?
ModuleStructurePropertyPage_Select_module_type_to_create_custom_structure_templates = Отметьте тип модуля чтобы создать пользовательский шаблон структуры модуля.\nИли снемите флажок чтобы удалить существующий пользовательский шаблон.

View File

@ -0,0 +1,249 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.internal.bsl.ui.wizard;
import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.MODULE;
import static com._1c.g5.v8.dt.metadata.mdclass.MdClassPackage.Literals.ABSTRACT_FORM__MODULE;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.util.Set;
import java.util.function.Supplier;
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.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.xtext.naming.QualifiedName;
import com._1c.g5.v8.bm.core.IBmObject;
import com._1c.g5.v8.dt.bsl.model.Module;
import com._1c.g5.v8.dt.bsl.model.ModuleType;
import com._1c.g5.v8.dt.bsl.util.BslUtil;
import com._1c.g5.v8.dt.common.FileUtil;
import com._1c.g5.v8.dt.common.PreferenceUtils;
import com._1c.g5.v8.dt.common.StringUtils;
import com._1c.g5.v8.dt.core.filesystem.IQualifiedNameFilePathConverter;
import com._1c.g5.v8.dt.metadata.mdclass.AbstractForm;
import com._1c.g5.v8.dt.metadata.mdclass.ScriptVariant;
import com._1c.g5.v8.dt.ui.wizards.IDtNewWizardContext;
import com._1c.g5.v8.dt.ui.wizards.IDtNewWizardRelatedModelsFactory;
import com.e1c.v8codestyle.bsl.IModuleStructureProvider;
import com.e1c.v8codestyle.internal.bsl.ui.UiPlugin;
import com.google.common.io.CharStreams;
import com.google.inject.Inject;
/**
* A factory for creating module structure when creating new object in wizard.
*
* @author Dmitriy Marmyshev
*/
public class ModuleStructureNewWizardRelatedModelsFactory
implements IDtNewWizardRelatedModelsFactory<EObject>
{
private static final String CURRENT_CODE = "%CURRENT_CODE%"; //$NON-NLS-1$
private static final String LINE_SEPARATOR_WIN = "\r\n"; //$NON-NLS-1$
private static final String LINE_SEPARATOR_LINUX = "\n"; //$NON-NLS-1$
private final IQualifiedNameFilePathConverter qualifiedNameFilePathConverter;
private final IModuleStructureProvider moduleStructureProvider;
/**
* Instantiates a new module structure new wizard related models factory.
*
* @param qualifiedNameFilePathConverter the qualified name file path converter service, cannot be {@code null}.
* @param moduleStructureProvider the module structure provider service, cannot be {@code null}.
*/
@Inject
public ModuleStructureNewWizardRelatedModelsFactory(IQualifiedNameFilePathConverter qualifiedNameFilePathConverter,
IModuleStructureProvider moduleStructureProvider)
{
this.qualifiedNameFilePathConverter = qualifiedNameFilePathConverter;
this.moduleStructureProvider = moduleStructureProvider;
}
@Override
public void createModels(IDtNewWizardContext<EObject> context, Set<EObject> createdModels)
{
IProject project = context.getV8project().getProject();
if (!moduleStructureProvider.canCreateStructure(project))
{
return;
}
AbstractForm formToAddModule = null;
for (EObject model : context.getRelatedModels())
{
if (model instanceof AbstractForm)
{
formToAddModule = (AbstractForm)model;
}
else if (model instanceof Module)
{
formToAddModule = null;
Module module = (Module)model;
IFile bslFile = getModuleFile(module);
if (bslFile != null)
{
ModuleType type = BslUtil.computeModuleType(module, qualifiedNameFilePathConverter);
createOrUpdateModule(bslFile, type, context);
}
}
}
if (formToAddModule != null)
{
IFile bslFile = getModuleFile(formToAddModule, project);
if (bslFile != null)
{
createOrUpdateModule(bslFile, ModuleType.FORM_MODULE, context);
EObject module = createBslProxyModule(bslFile);
createdModels.add(module);
}
}
}
private void createOrUpdateModule(IFile bslFile, ModuleType type, IDtNewWizardContext<EObject> context)
{
ScriptVariant script = context.getV8project().getScriptVariant();
Supplier<InputStream> content =
moduleStructureProvider.getModuleStructureTemplate(bslFile.getProject(), type, script);
if (content == null)
{
return;
}
String currentCode = StringUtils.EMPTY;
if (bslFile.exists())
{
try (InputStream in = bslFile.getContents();
Reader reader = new InputStreamReader(in, StandardCharsets.UTF_8);)
{
currentCode = CharStreams.toString(reader);
}
catch (IOException | CoreException e)
{
IStatus status = UiPlugin.createErrorStatus("Can't read bsl file with name: " + bslFile.getName(), e); //$NON-NLS-1$
UiPlugin.log(status);
}
}
IProject project = context.getV8project().getProject();
try (InputStream template = content.get();
Reader reader = new InputStreamReader(template, StandardCharsets.UTF_8);)
{
String text = CharStreams.toString(reader);
// Depends where plug-in is build (Windows or Linux) need to fix line-endings with
// project settings.
String actualLineSeparator = resolveLineSeparator(text);
String preferedLineSeparator = PreferenceUtils.getLineSeparator(project);
if (!actualLineSeparator.equals(preferedLineSeparator))
{
text = text.replace(actualLineSeparator, preferedLineSeparator);
}
if (text.contains(CURRENT_CODE))
{
text = text.replace(CURRENT_CODE, currentCode);
}
else if (!currentCode.isEmpty())
{
text = text.concat(currentCode);
}
InputStream in = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8));
if (bslFile.exists())
{
bslFile.setContents(in, true, true, new NullProgressMonitor());
}
else
{
createParentFolders(bslFile);
bslFile.create(in, true, new NullProgressMonitor());
}
}
catch (CoreException | IOException e)
{
IStatus status = UiPlugin.createErrorStatus("Can't create bsl file with name: " + bslFile.getName(), e); //$NON-NLS-1$
UiPlugin.log(status);
}
}
private String resolveLineSeparator(String text)
{
return text.contains(LINE_SEPARATOR_WIN) ? LINE_SEPARATOR_WIN : LINE_SEPARATOR_LINUX;
}
private EObject createBslProxyModule(IFile bslFile)
{
EObject module = EcoreUtil.create(MODULE);
URI uri = URI.createPlatformResourceURI(bslFile.getFullPath().toString(), true).appendFragment("/0"); //$NON-NLS-1$
((InternalEObject)module).eSetProxyURI(uri);
return module;
}
private IFile getModuleFile(Module model)
{
URI uri = EcoreUtil.getURI(model);
if (uri != null && uri.isPlatform())
{
IPath path = new Path(uri.trimFragment().toPlatformString(true));
return ResourcesPlugin.getWorkspace().getRoot().getFile(path);
}
return null;
}
private IFile getModuleFile(AbstractForm model, IProject project)
{
String fqn = ((IBmObject)model).bmGetFqn();
QualifiedName name = QualifiedName.create(fqn).append(StringUtils.capitalize(ABSTRACT_FORM__MODULE.getName()));
IPath path = qualifiedNameFilePathConverter.getFilePath(name, MODULE);
return project.getFile(path);
}
private void createParentFolders(IFile bslFile)
{
try
{
FileUtil.createParentFolders(bslFile);
}
catch (Exception e)
{
// skip if cannot create parent folders in other threads
}
}
}

View File

@ -39,4 +39,5 @@ Import-Package: com._1c.g5.v8.bm.core;version="[7.0.0,8.0.0)",
com.e1c.g5.v8.dt.check;version="[1.0.0,2.0.0)", com.e1c.g5.v8.dt.check;version="[1.0.0,2.0.0)",
com.e1c.g5.v8.dt.check.components;version="[1.0.0,2.0.0)", com.e1c.g5.v8.dt.check.components;version="[1.0.0,2.0.0)",
com.e1c.g5.v8.dt.check.settings;version="[1.0.0,2.0.0)" com.e1c.g5.v8.dt.check.settings;version="[1.0.0,2.0.0)"
Export-Package: com.e1c.v8codestyle.bsl.strict;version="0.1.0" Export-Package: com.e1c.v8codestyle.bsl;version="0.1.0",
com.e1c.v8codestyle.bsl.strict;version="0.1.0"

View File

@ -17,4 +17,5 @@ bin.includes = META-INF/,\
plugin.xml,\ plugin.xml,\
plugin.properties,\ plugin.properties,\
plugin_ru.properties,\ plugin_ru.properties,\
check.descriptions/ check.descriptions/,\
templates/

View File

@ -114,5 +114,11 @@
</check> </check>
</extension> </extension>
<extension
point="org.eclipse.core.runtime.preferences">
<initializer
class="com.e1c.v8codestyle.internal.bsl.ModuleStructureProviderPreferenceInitializer">
</initializer>
</extension>
</plugin> </plugin>

View File

@ -0,0 +1,64 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.bsl;
import java.io.InputStream;
import java.util.function.Supplier;
import org.eclipse.core.resources.IProject;
import com._1c.g5.v8.dt.bsl.model.ModuleType;
import com._1c.g5.v8.dt.metadata.mdclass.ScriptVariant;
import com.e1c.v8codestyle.internal.bsl.BslPlugin;
/**
* The provider of module structure template by module type.
* This service return either template from project settings or default template from the bundle.
*
*
* @author Dmitriy Marmyshev
*/
public interface IModuleStructureProvider
{
/** The preference root qualifier. */
String PREF_QUALIFIER = BslPlugin.PLUGIN_ID;
/** The key for preferences store the state of the creating module structure. */
String PREF_KEY_CREATE_STRUCTURE = "createModuleStructure"; //$NON-NLS-1$
/** The default value of creating module structure. */
boolean PREF_DEFAULT_CREATE_STRUCTURE = true;
/**
* Can create module structure template for the project. This checks project or default settings.
*
* @param project the project, cannot be {@code null}.
* @return true, if can create module structure for the project
*/
boolean canCreateStructure(IProject project);
/**
* Gets the module structure template supplier of input stream.
*
* @param project the project, cannot be {@code null}.
* @param moduleType the module type, cannot be {@code null}.
* @param script the script, cannot be {@code null}.
* @return the module structure template supplier of input stream, may return {@code null} if there is no template
* for such module type and script variant.
*/
Supplier<InputStream> getModuleStructureTemplate(IProject project, ModuleType moduleType, ScriptVariant script);
}

View File

@ -20,6 +20,7 @@ import org.osgi.framework.BundleContext;
import com._1c.g5.v8.dt.bsl.model.BslPackage; import com._1c.g5.v8.dt.bsl.model.BslPackage;
import com._1c.g5.wiring.InjectorAwareServiceRegistrator; import com._1c.g5.wiring.InjectorAwareServiceRegistrator;
import com._1c.g5.wiring.ServiceInitialization; import com._1c.g5.wiring.ServiceInitialization;
import com.e1c.v8codestyle.bsl.IModuleStructureProvider;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.Injector; import com.google.inject.Injector;
@ -131,6 +132,7 @@ public class BslPlugin
ServiceInitialization.schedule(() -> { ServiceInitialization.schedule(() -> {
// register services from injector // register services from injector
registrator.service(IModuleStructureProvider.class).registerInjected();
}); });
} }
@ -180,7 +182,7 @@ public class BslPlugin
{ {
try try
{ {
return Guice.createInjector(new ExternalDependenciesModule(this)); return Guice.createInjector(new ServiceModule(), new ExternalDependenciesModule(this));
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -0,0 +1,144 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.internal.bsl;
import static com.e1c.v8codestyle.bsl.strict.StrictTypeUtil.BSL_FILE_EXTENSION;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.MessageFormat;
import java.util.Optional;
import java.util.function.Supplier;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.preferences.ConfigurationScope;
import org.eclipse.core.runtime.preferences.DefaultScope;
import org.eclipse.core.runtime.preferences.IScopeContext;
import org.eclipse.core.runtime.preferences.InstanceScope;
import com._1c.g5.v8.dt.bsl.model.ModuleType;
import com._1c.g5.v8.dt.metadata.mdclass.ScriptVariant;
import com.e1c.v8codestyle.bsl.IModuleStructureProvider;
/**
* The default implementation of module structure provider.
*
* @author Dmitriy Marmyshev
*/
public class ModuleStructureProvider
implements IModuleStructureProvider
{
private static final String FOLDER_RU = "/templates/ru/"; //$NON-NLS-1$
private static final String FOLDER_EN = "/templates/en/"; //$NON-NLS-1$
private static final IPath FOLDER_SETTINGS = new org.eclipse.core.runtime.Path(".settings/templates"); //$NON-NLS-1$
@Override
public boolean canCreateStructure(IProject project)
{
ProjectScope scope = new ProjectScope(project);
IScopeContext[] contexts =
new IScopeContext[] { scope, InstanceScope.INSTANCE, ConfigurationScope.INSTANCE, DefaultScope.INSTANCE };
return Platform.getPreferencesService()
.getBoolean(PREF_QUALIFIER, PREF_KEY_CREATE_STRUCTURE, PREF_DEFAULT_CREATE_STRUCTURE, contexts);
}
@Override
public Supplier<InputStream> getModuleStructureTemplate(IProject project, ModuleType moduleType,
ScriptVariant script)
{
if (moduleType == null || script == null)
{
return null;
}
StringBuilder sb = new StringBuilder();
sb.append(moduleType.getName().toLowerCase());
sb.append("."); //$NON-NLS-1$
sb.append(BSL_FILE_EXTENSION);
IFile templateFile = project.getFile(FOLDER_SETTINGS.append(sb.toString()));
if (script == ScriptVariant.ENGLISH)
{
sb.insert(0, FOLDER_EN);
}
else
{
sb.insert(0, FOLDER_RU);
}
String path = sb.toString();
if (templateFile.exists())
{
return () -> {
try
{
return templateFile.getContents();
}
catch (CoreException e)
{
IStatus message =
BslPlugin.createErrorStatus("Cannot read tempate file " + templateFile.toString(), e); //$NON-NLS-1$
BslPlugin.log(message);
}
return getClass().getResourceAsStream(path);
};
}
Optional<Path> template = getBundleEntry(path);
if (template.isPresent())
{
return () -> getClass().getResourceAsStream(path);
}
String message = MessageFormat.format("Cannot find module template for type: {0} and language: {1} in {2}", //$NON-NLS-1$
moduleType.getName(), script, path);
IStatus status = BslPlugin.createWarningStatus(message);
BslPlugin.log(status);
return null;
}
private Optional<Path> getBundleEntry(String path)
{
URL url = getClass().getResource(path);
if (url == null)
{
return Optional.empty();
}
try
{
URL fileUrl = FileLocator.toFileURL(url);
return Optional.of(Paths.get(fileUrl.toURI()));
}
catch (IOException | java.net.URISyntaxException e)
{
BslPlugin.logError(e);
}
return Optional.empty();
}
}

View File

@ -0,0 +1,38 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.internal.bsl;
import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
import org.eclipse.core.runtime.preferences.DefaultScope;
import com.e1c.v8codestyle.bsl.IModuleStructureProvider;
/**
* Initializer of default values for module structure service.
*
* @author Dmitriy Marmyshev
*/
public class ModuleStructureProviderPreferenceInitializer
extends AbstractPreferenceInitializer
{
@Override
public void initializeDefaultPreferences()
{
DefaultScope.INSTANCE.getNode(IModuleStructureProvider.PREF_QUALIFIER)
.putBoolean(IModuleStructureProvider.PREF_KEY_CREATE_STRUCTURE,
IModuleStructureProvider.PREF_DEFAULT_CREATE_STRUCTURE);
}
}

View File

@ -0,0 +1,35 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.internal.bsl;
import com.e1c.v8codestyle.bsl.IModuleStructureProvider;
import com.google.inject.AbstractModule;
import com.google.inject.Singleton;
/**
* Internal services of the bundle.
*
* @author Dmitriy Marmyshev
*/
public class ServiceModule
extends AbstractModule
{
@Override
protected void configure()
{
bind(IModuleStructureProvider.class).to(ModuleStructureProvider.class).in(Singleton.class);
}
}

View File

@ -0,0 +1,12 @@
#Region EventHandlers
// Enter code here.
#EndRegion
#Region Private
// Enter code here.
#EndRegion

View File

@ -0,0 +1,14 @@
#Region EventHandlers
// Enter code here.
%CURRENT_CODE%
#EndRegion
#Region Private
// Enter code here.
#EndRegion

View File

@ -0,0 +1,18 @@
#Region Public
// Enter code here.
#EndRegion
#Region Internal
// Enter code here.
#EndRegion
#Region Private
// Enter code here.
#EndRegion

View File

@ -0,0 +1,12 @@
#Region EventHandlers
// Enter code here.
#EndRegion
#Region Private
// Enter code here.
#EndRegion

View File

@ -0,0 +1,36 @@
#Region Variables
#EndRegion
#Region FormEventHandlers
// Enter code here.
%CURRENT_CODE%
#EndRegion
#Region FormHeaderItemsEventHandlers
// Enter code here.
#EndRegion
#Region FormTableItemsEventHandlers
// Enter code here.
#EndRegion
#Region FormCommandsEventHandlers
// Enter code here.
#EndRegion
#Region Private
// Enter code here.
#EndRegion

View File

@ -0,0 +1,12 @@
#Region EventHandlers
// Enter code here.
#EndRegion
#Region Private
// Enter code here.
#EndRegion

View File

@ -0,0 +1,12 @@
#Region EventHandlers
// Enter code here.
#EndRegion
#Region Private
// Enter code here.
#EndRegion

View File

@ -0,0 +1,20 @@
#Region Variables
#EndRegion
#Region EventHandlers
// Enter code here.
#EndRegion
#Region Private
// Enter code here.
#EndRegion
#Region Initialize
#EndRegion

View File

@ -0,0 +1,28 @@
#If Server Or ThickClientOrdinaryApplication Or ExternalConnection Then
#Region Public
// Enter code here.
#EndRegion
#Region EventHandlers
// Enter code here.
#EndRegion
#Region Internal
// Enter code here.
#EndRegion
#Region Private
// Enter code here.
#EndRegion
#EndIf

View File

@ -0,0 +1,36 @@
#If Server Or ThickClientOrdinaryApplication Or ExternalConnection Then
#Region Variables
#EndRegion
#Region Public
// Enter code here.
#EndRegion
#Region EventHandlers
// Enter code here.
#EndRegion
#Region Internal
// Enter code here.
#EndRegion
#Region Private
// Enter code here.
#EndRegion
#Region Initialize
#EndRegion
#EndIf

View File

@ -0,0 +1,20 @@
#Region Variables
#EndRegion
#Region EventHandlers
// Enter code here.
#EndRegion
#Region Private
// Enter code here.
#EndRegion
#Region Initialize
#EndRegion

View File

@ -0,0 +1,36 @@
#If Server Or ThickClientOrdinaryApplication Or ExternalConnection Then
#Region Variables
#EndRegion
#Region Public
// Enter code here.
#EndRegion
#Region EventHandlers
// Enter code here.
#EndRegion
#Region Internal
// Enter code here.
#EndRegion
#Region Private
// Enter code here.
#EndRegion
#Region Initialize
#EndRegion
#EndIf

View File

@ -0,0 +1,16 @@
#If Server Or ThickClientOrdinaryApplication Or ExternalConnection Then
#Region EventHandlers
// Enter code here.
#EndRegion
#Region Private
// Enter code here.
#EndRegion
#EndIf

View File

@ -0,0 +1,36 @@
#If Server Or ThickClientOrdinaryApplication Or ExternalConnection Then
#Region Variables
#EndRegion
#Region Public
// Enter code here.
#EndRegion
#Region EventHandlers
// Enter code here.
#EndRegion
#Region Internal
// Enter code here.
#EndRegion
#Region Private
// Enter code here.
#EndRegion
#Region Initialize
#EndRegion
#EndIf

View File

@ -0,0 +1,12 @@
#Region EventHandlers
// Enter code here.
#EndRegion
#Region Private
// Enter code here.
#EndRegion

View File

@ -0,0 +1,12 @@
#Область ОбработчикиСобытий
// Код процедур и функций
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
// Код процедур и функций
#КонецОбласти

View File

@ -0,0 +1,14 @@
#Область ОбработчикиСобытий
// Код процедур и функций
%CURRENT_CODE%
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
// Код процедур и функций
#КонецОбласти

View File

@ -0,0 +1,18 @@
#Область ПрограммныйИнтерфейс
// Код процедур и функций
#КонецОбласти
#Область СлужебныйПрограммныйИнтерфейс
// Код процедур и функций
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
// Код процедур и функций
#КонецОбласти

View File

@ -0,0 +1,12 @@
#Область ОбработчикиСобытий
// Код процедур и функций
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
// Код процедур и функций
#КонецОбласти

View File

@ -0,0 +1,36 @@
#Область ОписаниеПеременных
#КонецОбласти
#Область ОбработчикиСобытийФормы
// Код процедур и функций
%CURRENT_CODE%
#КонецОбласти
#Область ОбработчикиСобытийЭлементовШапкиФормы
// Код процедур и функций
#КонецОбласти
#Область ОбработчикиСобытийЭлементовТаблицыФормы<ИмяТаблицыФормы>
// Код процедур и функций
#КонецОбласти
#Область ОбработчикиКомандФормы
// Код процедур и функций
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
// Код процедур и функций
#КонецОбласти

View File

@ -0,0 +1,12 @@
#Область ОбработчикиСобытий
// Код процедур и функций
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
// Код процедур и функций
#КонецОбласти

View File

@ -0,0 +1,12 @@
#Область ОбработчикиСобытий
// Код процедур и функций
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
// Код процедур и функций
#КонецОбласти

View File

@ -0,0 +1,20 @@
#Область ОписаниеПеременных
#КонецОбласти
#Область ОбработчикиСобытий
// Код процедур и функций
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
// Код процедур и функций
#КонецОбласти
#Область Инициализация
#КонецОбласти

View File

@ -0,0 +1,28 @@
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
#Область ПрограммныйИнтерфейс
// Код процедур и функций
#КонецОбласти
#Область ОбработчикиСобытий
// Код процедур и функций
#КонецОбласти
#Область СлужебныйПрограммныйИнтерфейс
// Код процедур и функций
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
// Код процедур и функций
#КонецОбласти
#КонецЕсли

View File

@ -0,0 +1,36 @@
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
#Область ОписаниеПеременных
#КонецОбласти
#Область ПрограммныйИнтерфейс
// Код процедур и функций
#КонецОбласти
#Область ОбработчикиСобытий
// Код процедур и функций
#КонецОбласти
#Область СлужебныйПрограммныйИнтерфейс
// Код процедур и функций
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
// Код процедур и функций
#КонецОбласти
#Область Инициализация
#КонецОбласти
#КонецЕсли

View File

@ -0,0 +1,20 @@
#Область ОписаниеПеременных
#КонецОбласти
#Область ОбработчикиСобытий
// Код процедур и функций
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
// Код процедур и функций
#КонецОбласти
#Область Инициализация
#КонецОбласти

View File

@ -0,0 +1,36 @@
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
#Область ОписаниеПеременных
#КонецОбласти
#Область ПрограммныйИнтерфейс
// Код процедур и функций
#КонецОбласти
#Область ОбработчикиСобытий
// Код процедур и функций
#КонецОбласти
#Область СлужебныйПрограммныйИнтерфейс
// Код процедур и функций
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
// Код процедур и функций
#КонецОбласти
#Область Инициализация
#КонецОбласти
#КонецЕсли

View File

@ -0,0 +1,16 @@
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
#Область ОбработчикиСобытий
// Код процедур и функций
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
// Код процедур и функций
#КонецОбласти
#КонецЕсли

View File

@ -0,0 +1,36 @@
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
#Область ОписаниеПеременных
#КонецОбласти
#Область ПрограммныйИнтерфейс
// Код процедур и функций
#КонецОбласти
#Область ОбработчикиСобытий
// Код процедур и функций
#КонецОбласти
#Область СлужебныйПрограммныйИнтерфейс
// Код процедур и функций
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
// Код процедур и функций
#КонецОбласти
#Область Инициализация
#КонецОбласти
#КонецЕсли

View File

@ -0,0 +1,12 @@
#Область ОбработчикиСобытий
// Код процедур и функций
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
// Код процедур и функций
#КонецОбласти

View File

@ -13,6 +13,8 @@
- Дополнительные инструменты, улучшающие и ускоряющие работу по стандартам 1С - Дополнительные инструменты, улучшающие и ускоряющие работу по стандартам 1С
- [Авто-сортировка метаданных](tools/autosort.md) - [Авто-сортировка метаданных](tools/autosort.md)
- [Создание общих модулей по типам](tools/common-module-types.md) - [Создание общих модулей по типам](tools/common-module-types.md)
- [Панель "Bsl Документирующий комментарий"](tools/bsl-doc-comment-view.md)
- [Автоматическое создание структуры модуля](tools/module-structure.md)
## Участие в проекте ## Участие в проекте

View File

@ -0,0 +1,55 @@
# Автоматическое создание структуры модуля
При создании объектов метаданных для всех модулей автоматически создается структура модуля.
Для каждого из типов модулей используется своя структура модуля. Подробнее см. стандарт
## Отключение авто-создания
Для проекта можно принудительно отключить или включить создание структуры модуля.
Отрокройте свйства проекта: `Properties -> V8 -> Built-in language -> Module structure -> Automatically create module structure`.
Альтернативный способ: создать файл настроек `ProjectName/.settings/com.e1c.v8codestyle.bsl.prefs` с ключем управления созданием структуры модуля:
```
eclipse.preferences.version=1
createModuleStructure=false
```
Для отключения создания структуры модуля в текущем воркспейсе откройте:
Меню Window или 1C:EDT (в macOS): `Preferences -> V8 -> Built-in language -> Module structure -> Automatically create module structure`.
Общие настройки могут быть заданы для всей инсталяции 1C:EDT или поствлятся через 1С:Стартер.
## Переопределение шаблонов
Отрокройте свйства проекта: `Properties -> V8 -> Built-in language -> Module structure`.
Установите флажок для тех типов модулей, для которых в текущем проекте следует изменить шаблон структуры модуля.
При этом будет создан файл с типом модуля для которого необходимо переопределение. Например, для модуля менеджера: `ProjectName/.settings/templates/manager_module.bsl`
Имена файлов модулей по типам:
- `manager_module.bsl` - для модуля менеджера
- `object_module.bsl` - для модуля объекта
- `recordset_module.bsl` - для модуля набора записей регистра
- `command_module.bsl` - для модуля команды
- `form_module.bsl` - для модуля формы
- `common_module.bsl` - для общего модуля
- `value_manager_module.bsl` - для модуля менеджера значения константы
- `external_conn_module.bsl` - для модуля внешнего соединения
- `session_module.bsl` - для модуля сессии
- `managed_app_module.bsl` - для модуля приложения
- `ordinary_app_module.bsl` - для модуля обычного приложения
- `web_service_module.bsl` - для модуля веб-сервиса
- `http_service_module.bsl` - для модуля http-сервиса
- `integration_service_module.bsl` - для модуля сервиса интеграции
- `bot_module.bsl` - для модуля бота
## См. также
- [Стандарт 455: Структура модуля](https://its.1c.ru/db/v8std#content:455:hdoc)

View File

@ -5,3 +5,4 @@
- [Авто-сортировка метаданных](autosort.md) - [Авто-сортировка метаданных](autosort.md)
- [Создание общих модулей по типам](common-module-types.md) - [Создание общих модулей по типам](common-module-types.md)
- [Панель "Bsl Документирующий комментарий"](bsl-doc-comment-view.md) - [Панель "Bsl Документирующий комментарий"](bsl-doc-comment-view.md)
- [Автоматическое создание структуры модуля](module-structure.md)

View File

@ -0,0 +1,93 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
/**
*
*/
package com.e1c.v8codestyle.bsl.ui.itests;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.preference.PreferenceDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.intro.IIntroPart;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import com._1c.g5.v8.dt.testing.TestingWorkspace;
import com.e1c.v8codestyle.internal.bsl.ui.preferences.ModuleStructurePreferencePage;
/**
* Integration test of the {@link ModuleStructurePreferencePage}.
*
* @author Dmitriy Marmyshev
*/
public class ModuleStructurePreferencePageTest
{
private static final String PROJECT_NAME = "CommonModule";
private static final String PREFERENCE_PAGE_ID =
"com.e1c.v8codestyle.bsl.ui.preferences.ModuleStructurePreferencePage";
@Rule
public TestingWorkspace testingWorkspace = new TestingWorkspace(true, false);
protected static final String FOLDER_RESOURCE = "/resources/";
private IProject project;
@Before
public void setUp() throws CoreException
{
project = testingWorkspace.getProject(PROJECT_NAME);
if (!project.exists() || !project.isAccessible())
{
testingWorkspace.cleanUpWorkspace();
project = this.testingWorkspace.setUpProject(PROJECT_NAME, getClass());
}
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().closeAllEditors(false);
IIntroPart introPart = PlatformUI.getWorkbench().getIntroManager().getIntro();
PlatformUI.getWorkbench().getIntroManager().closeIntro(introPart);
}
@After
public void shutDown()
{
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().closeAllEditors(false);
}
/**
* Test open module structure preference page.
*
* @throws Exception the exception
*/
@Test
public void testOpenModuleStructurePreferencePage() throws Exception
{
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
PreferenceDialog dialog =
PreferencesUtil.createPreferenceDialogOn(shell,
PREFERENCE_PAGE_ID, null, null);
dialog.setBlockOnOpen(false);
shell.getDisplay().syncExec(dialog::open);
shell.getDisplay().syncExec(dialog::close);
}
}

View File

@ -0,0 +1,314 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
/**
*
*/
package com.e1c.v8codestyle.bsl.ui.itests;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.function.Supplier;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.dialogs.DialogPage;
import org.eclipse.jface.preference.PreferenceDialog;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.intro.IIntroPart;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import com._1c.g5.v8.dt.bsl.model.ModuleType;
import com._1c.g5.v8.dt.metadata.mdclass.ScriptVariant;
import com._1c.g5.v8.dt.testing.TestingWorkspace;
import com._1c.g5.wiring.ServiceAccess;
import com.e1c.v8codestyle.bsl.IModuleStructureProvider;
import com.e1c.v8codestyle.internal.bsl.ui.properties.ModuleStructurePropertyPage;
import com.google.common.io.CharStreams;
/**
* Integration test of the {@link ModuleStructurePropertyPage}.
*
* @author Dmitriy Marmyshev
*/
public class ModuleStructurePropertyPageTest
{
private static final String PROJECT_NAME = "CommonModule";
private static final String SETTINGS_TEMPLATES_COMMON_MODULE_BSL = ".settings/templates/common_module.bsl";
private static final String EDTOR_TITLE = "/" + PROJECT_NAME + "/" + SETTINGS_TEMPLATES_COMMON_MODULE_BSL;
private static final String PROPERTY_PAGE_ID =
"com.e1c.v8codestyle.bsl.ui.properties.moduleStructurePropertyPage";
@Rule
public TestingWorkspace testingWorkspace = new TestingWorkspace(true, false);
protected static final String FOLDER_RESOURCE = "/resources/";
private IProject project;
@Before
public void setUp() throws CoreException
{
project = testingWorkspace.getProject(PROJECT_NAME);
if (!project.exists() || !project.isAccessible())
{
testingWorkspace.cleanUpWorkspace();
project = this.testingWorkspace.setUpProject(PROJECT_NAME, getClass());
}
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().closeAllEditors(false);
IIntroPart introPart = PlatformUI.getWorkbench().getIntroManager().getIntro();
PlatformUI.getWorkbench().getIntroManager().closeIntro(introPart);
}
@After
public void shutDown()
{
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().closeAllEditors(false);
}
/**
* Test open and close module structure property page.
*
* @throws Exception the exception
*/
@Test
public void testOpenAndCloseModuleStructurePropertyPage() throws Exception
{
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
PreferenceDialog dialog = PreferencesUtil.createPropertyDialogOn(shell, project, PROPERTY_PAGE_ID, null, null);
dialog.setBlockOnOpen(false);
shell.getDisplay().syncExec(dialog::open);
waitEventSetnd(dialog);
Object selected = dialog.getSelectedPage();
assertTrue(selected instanceof ModuleStructurePropertyPage);
shell.getDisplay().syncExec(dialog::close);
}
/**
* Test open module structure property page.
*
* @throws Exception the exception
*/
@Test
public void testOpenModuleTemplate() throws Exception
{
IModuleStructureProvider moduleStructureProvider = ServiceAccess.get(IModuleStructureProvider.class);
Supplier<InputStream> templateProvider = moduleStructureProvider.getModuleStructureTemplate(project,
ModuleType.COMMON_MODULE, null);
assertNull(templateProvider);
templateProvider = moduleStructureProvider.getModuleStructureTemplate(project, null, ScriptVariant.ENGLISH);
assertNull(templateProvider);
templateProvider = moduleStructureProvider.getModuleStructureTemplate(project,
ModuleType.COMMON_MODULE, ScriptVariant.ENGLISH);
assertNotNull(templateProvider);
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
PreferenceDialog dialog = PreferencesUtil.createPropertyDialogOn(shell, project, PROPERTY_PAGE_ID, null, null);
dialog.setBlockOnOpen(false);
shell.getDisplay().syncExec(dialog::open);
Object selected = dialog.getSelectedPage();
assertTrue(selected instanceof ModuleStructurePropertyPage);
ModuleStructurePropertyPage page = (ModuleStructurePropertyPage)selected;
CheckboxTableViewer viewer = getViewer(page);
assertFalse(viewer.getChecked(ModuleType.COMMON_MODULE));
viewer.setChecked(ModuleType.COMMON_MODULE, true);
Button applyButton = getApplyButtonControl(page);
applyButton.notifyListeners(SWT.Selection, new Event());
waitEventSetnd(dialog);
Button buttonOpen = getButtonByName(page, "Open template");
assertNotNull(buttonOpen);
viewer.setSelection(new StructuredSelection(ModuleType.FORM_MODULE));
waitEventSetnd(dialog);
assertFalse(buttonOpen.isEnabled());
viewer.setSelection(new StructuredSelection(ModuleType.COMMON_MODULE));
waitEventSetnd(dialog);
assertTrue(buttonOpen.isEnabled());
buttonOpen.notifyListeners(SWT.Selection, new Event());
assertNull(dialog.getShell());
waitEventSetnd();
// check editor content equals base template
IFile file = project.getFile(SETTINGS_TEMPLATES_COMMON_MODULE_BSL);
assertTrue(file.exists());
try (InputStream in = file.getContents();
Reader fileReader = new InputStreamReader(in, StandardCharsets.UTF_8);
InputStream template = templateProvider.get();
Reader templateReader = new InputStreamReader(template, StandardCharsets.UTF_8);)
{
String templateText = CharStreams.toString(templateReader);
assertNotNull(templateText);
String fileText = CharStreams.toString(fileReader);
assertEquals(templateText, fileText);
}
// wait until open editor
waitEventSetnd();
IEditorPart editor = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor();
assertNotNull(editor);
assertEquals(EDTOR_TITLE, editor.getTitle());
String newContent = "New template";
try (InputStream in = new ByteArrayInputStream(newContent.getBytes(StandardCharsets.UTF_8));)
{
file.setContents(in, true, true, new NullProgressMonitor());
}
templateProvider = moduleStructureProvider.getModuleStructureTemplate(project, ModuleType.COMMON_MODULE,
ScriptVariant.ENGLISH);
try (InputStream in = file.getContents();
Reader fileReader = new InputStreamReader(in, StandardCharsets.UTF_8);
InputStream template = templateProvider.get();
Reader templateReader = new InputStreamReader(template, StandardCharsets.UTF_8);)
{
String templateText = CharStreams.toString(templateReader);
assertNotNull(templateText);
String fileText = CharStreams.toString(fileReader);
assertEquals(templateText, fileText);
}
// re-open properties to check selection
dialog = PreferencesUtil.createPropertyDialogOn(shell, project, PROPERTY_PAGE_ID, null, null);
dialog.setBlockOnOpen(false);
shell.getDisplay().syncExec(dialog::open);
selected = dialog.getSelectedPage();
assertTrue(selected instanceof ModuleStructurePropertyPage);
page = (ModuleStructurePropertyPage)selected;
viewer = getViewer(page);
assertTrue(viewer.getChecked(ModuleType.COMMON_MODULE));
viewer.setChecked(ModuleType.COMMON_MODULE, false);
applyButton = getApplyButtonControl(page);
applyButton.notifyListeners(SWT.Selection, new Event());
waitEventSetnd(dialog);
shell.getDisplay().syncExec(dialog::close);
assertFalse(file.exists());
}
private CheckboxTableViewer getViewer(ModuleStructurePropertyPage page) throws Exception
{
Field field = page.getClass().getDeclaredField("checkBoxViewer");
field.setAccessible(true);
return (CheckboxTableViewer)field.get(page);
}
private Button getButtonByName(ModuleStructurePropertyPage page, String name) throws Exception
{
Composite top = getTopControl(page);
assertNotNull(top);
Queue<Control> toCheck = new LinkedList<>();
toCheck.add(top);
while (!toCheck.isEmpty())
{
Control control = toCheck.poll();
if (control instanceof Button && name.equalsIgnoreCase(((Button)control).getText()))
{
return (Button)control;
}
else if (control instanceof Composite)
{
toCheck.addAll(List.of(((Composite)control).getChildren()));
}
}
return null;
}
private Composite getTopControl(ModuleStructurePropertyPage page) throws Exception
{
Field field = DialogPage.class.getDeclaredField("control");
field.setAccessible(true);
return (Composite)field.get(page);
}
private Button getApplyButtonControl(ModuleStructurePropertyPage page) throws Exception
{
Field field = PreferencePage.class.getDeclaredField("applyButton");
field.setAccessible(true);
return (Button)field.get(page);
}
private void waitEventSetnd(PreferenceDialog dialog)
{
Display display = dialog.getShell().getDisplay();
while (!display.isDisposed() && display.readAndDispatch())
{
// do it
}
}
private void waitEventSetnd()
{
Display display = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell().getDisplay();
while (!display.isDisposed() && display.readAndDispatch())
{
// do it
}
}
}