/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
*
* 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 org.jkiss.dbeaver.ui.search.data;
import org.eclipse.jface.viewers.*;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
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.widgets.*;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.core.CoreMessages;
import org.jkiss.dbeaver.core.DBeaverCore;
import org.jkiss.dbeaver.core.DBeaverUI;
import org.jkiss.dbeaver.model.preferences.DBPPreferenceStore;
import org.jkiss.dbeaver.model.navigator.*;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.runtime.DBRRunnableWithProgress;
import org.jkiss.dbeaver.model.struct.*;
import org.jkiss.dbeaver.ui.UIUtils;
import org.jkiss.dbeaver.ui.navigator.NavigatorUtils;
import org.jkiss.dbeaver.ui.navigator.database.CheckboxTreeManager;
import org.jkiss.dbeaver.ui.navigator.database.DatabaseNavigatorTree;
import org.jkiss.dbeaver.ui.navigator.database.load.TreeLoadNode;
import org.jkiss.dbeaver.ui.search.AbstractSearchPage;
import org.jkiss.utils.CommonUtils;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
public class SearchDataPage extends AbstractSearchPage {
private static final String PROP_MASK = "search.data.mask"; //$NON-NLS-1$
private static final String PROP_CASE_SENSITIVE = "search.data.case-sensitive"; //$NON-NLS-1$
private static final String PROP_SAMPLE_ROWS = "search.data.sample-rows"; //$NON-NLS-1$
private static final String PROP_FAST_SEARCH = "search.data.fast-search"; //$NON-NLS-1$
private static final String PROP_SEARCH_NUMBERS = "search.data.search-numbers"; //$NON-NLS-1$
private static final String PROP_SEARCH_LOBS = "search.data.search-lobs"; //$NON-NLS-1$
private static final String PROP_HISTORY = "search.data.history"; //$NON-NLS-1$
private static final String PROP_SOURCES = "search.data.object-source"; //$NON-NLS-1$
private Combo searchText;
private DatabaseNavigatorTree dataSourceTree;
private SearchDataParams params = new SearchDataParams();
private Set<String> searchHistory = new LinkedHashSet<>();
private CheckboxTreeManager checkboxTreeManager;
private DBPPreferenceStore store;
public SearchDataPage() {
super("Database objects search");
}
@Override
public void createControl(Composite parent) {
super.createControl(parent);
initializeDialogUnits(parent);
Composite searchGroup = new Composite(parent, SWT.NONE);
searchGroup.setLayoutData(new GridData(GridData.FILL_BOTH));
searchGroup.setLayout(new GridLayout(3, false));
setControl(searchGroup);
UIUtils.createControlLabel(searchGroup, "String");
searchText = new Combo(searchGroup, SWT.DROP_DOWN);
searchText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
if (params.searchString != null) {
searchText.setText(params.searchString);
}
for (String history : searchHistory) {
searchText.add(history);
}
searchText.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent e)
{
params.searchString = searchText.getText();
updateEnablement();
}
});
Composite optionsGroup = new SashForm(searchGroup, SWT.NONE);
GridLayout layout = new GridLayout(2, true);
layout.marginHeight = 0;
layout.marginWidth = 0;
optionsGroup.setLayout(layout);
GridData gd = new GridData(GridData.FILL_BOTH);
gd.horizontalSpan = 3;
optionsGroup.setLayoutData(gd);
{
final DBeaverCore core = DBeaverCore.getInstance();
Group databasesGroup = UIUtils.createControlGroup(optionsGroup, "Databases", 1, GridData.FILL_BOTH, 0);
gd = new GridData(GridData.FILL_BOTH);
//gd.heightHint = 300;
databasesGroup.setLayoutData(gd);
final DBNProject projectNode = core.getNavigatorModel().getRoot().getProject(core.getProjectRegistry().getActiveProject());
DBNNode rootNode = projectNode == null ? core.getNavigatorModel().getRoot() : projectNode.getDatabases();
dataSourceTree = new DatabaseNavigatorTree(databasesGroup, rootNode, SWT.SINGLE | SWT.CHECK);
gd = new GridData(GridData.FILL_BOTH);
gd.heightHint = 300;
dataSourceTree.setLayoutData(gd);
final CheckboxTreeViewer viewer = (CheckboxTreeViewer) dataSourceTree.getViewer();
viewer.addFilter(new ViewerFilter() {
@Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
if (element instanceof TreeLoadNode) {
return true;
}
if (element instanceof DBNNode) {
if (element instanceof DBNDatabaseFolder) {
DBNDatabaseFolder folder = (DBNDatabaseFolder) element;
Class<? extends DBSObject> folderItemsClass = folder.getChildrenClass();
return folderItemsClass != null &&
(DBSObjectContainer.class.isAssignableFrom(folderItemsClass) ||
DBSEntity.class.isAssignableFrom(folderItemsClass));
}
if (element instanceof DBNLocalFolder ||
element instanceof DBNProjectDatabases ||
element instanceof DBNDataSource)
{
return true;
}
if (element instanceof DBSWrapper) {
DBSObject obj = ((DBSWrapper) element).getObject();
if (obj instanceof DBSObjectContainer) return true;
if (obj instanceof DBSDataContainer && obj instanceof DBSEntity) {
if ((((DBSDataContainer)obj).getSupportedFeatures() & DBSDataContainer.DATA_SEARCH) != 0) {
return true;
}
}
}
}
return false;
}
});
checkboxTreeManager = new CheckboxTreeManager(viewer,
new Class[]{DBSDataContainer.class});
viewer.addCheckStateListener(new ICheckStateListener() {
@Override
public void checkStateChanged(CheckStateChangedEvent event) {
updateEnablement();
}
});
}
{
//new Label(searchGroup, SWT.NONE);
Composite optionsGroup2 = UIUtils.createControlGroup(optionsGroup, "Settings", 2, GridData.FILL_HORIZONTAL, 0);
optionsGroup2.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.HORIZONTAL_ALIGN_BEGINNING | GridData.VERTICAL_ALIGN_BEGINNING));
if (params.maxResults <= 0) {
params.maxResults = 10;
}
final Spinner maxResultsSpinner = UIUtils.createLabelSpinner(optionsGroup2, "Sample rows", params.maxResults, 1, Integer.MAX_VALUE);
maxResultsSpinner.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
maxResultsSpinner.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent e)
{
params.maxResults = maxResultsSpinner.getSelection();
}
});
final Button caseCheckbox = UIUtils.createLabelCheckbox(optionsGroup2, CoreMessages.dialog_search_objects_case_sensitive, params.caseSensitive);
caseCheckbox.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
caseCheckbox.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e)
{
params.caseSensitive = caseCheckbox.getSelection();
}
});
final Button fastSearchCheckbox = UIUtils.createLabelCheckbox(optionsGroup2, "Fast search (indexed)", params.fastSearch);
fastSearchCheckbox.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
fastSearchCheckbox.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e)
{
params.fastSearch = fastSearchCheckbox.getSelection();
}
});
final Button searchNumbersCheckbox = UIUtils.createLabelCheckbox(optionsGroup2, "Search in numbers", params.searchNumbers);
searchNumbersCheckbox.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
searchNumbersCheckbox.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e)
{
params.searchNumbers = searchNumbersCheckbox.getSelection();
}
});
final Button searchLOBCheckbox = UIUtils.createLabelCheckbox(optionsGroup2, "Search in LOBs", params.searchLOBs);
searchLOBCheckbox.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
searchLOBCheckbox.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e)
{
params.searchLOBs = searchNumbersCheckbox.getSelection();
}
});
}
final List<DBNNode> checkedNodes = new ArrayList<>();
dataSourceTree.setEnabled(false);
try {
DBeaverUI.runInProgressDialog(new DBRRunnableWithProgress() {
@Override
public void run(DBRProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
monitor.beginTask("Load database nodes", 1);
try {
monitor.subTask("Load tree state");
checkedNodes.addAll(
loadTreeState(monitor, store, PROP_SOURCES));
} finally {
monitor.done();
}
}
});
} catch (InvocationTargetException e) {
UIUtils.showErrorDialog(getShell(), "Data sources load", "Error loading settings", e.getTargetException());
}
if (!checkedNodes.isEmpty()) {
boolean first = true;
for (DBNNode node : checkedNodes) {
((CheckboxTreeViewer) dataSourceTree.getViewer()).setChecked(node, true);
if (first) {
dataSourceTree.getViewer().reveal(NavigatorUtils.getDataSourceNode(node));
first = false;
}
}
checkboxTreeManager.updateCheckStates();
}
updateEnablement();
dataSourceTree.setEnabled(true);
}
@Override
public SearchDataQuery createQuery() throws DBException
{
params.sources = getCheckedSources();
// Save search query
if (!searchHistory.contains(params.searchString)) {
searchHistory.add(params.searchString);
searchText.add(params.searchString);
}
return SearchDataQuery.createQuery(params);
}
@Override
public void loadState(DBPPreferenceStore store)
{
params.searchString = store.getString(PROP_MASK);
params.caseSensitive = store.getBoolean(PROP_CASE_SENSITIVE);
params.fastSearch = store.getBoolean(PROP_FAST_SEARCH);
params.searchNumbers = store.getString(PROP_SEARCH_NUMBERS) == null || store.getBoolean(PROP_SEARCH_NUMBERS);
params.searchLOBs = store.getBoolean(PROP_SEARCH_LOBS);
params.maxResults = store.getInt(PROP_SAMPLE_ROWS);
for (int i = 0; ;i++) {
String history = store.getString(PROP_HISTORY + "." + i); //$NON-NLS-1$
if (CommonUtils.isEmpty(history)) {
break;
}
searchHistory.add(history);
}
this.store = store;
}
@Override
public void saveState(DBPPreferenceStore store)
{
store.setValue(PROP_MASK, params.searchString);
store.setValue(PROP_CASE_SENSITIVE, params.caseSensitive);
store.setValue(PROP_SAMPLE_ROWS, params.maxResults);
store.setValue(PROP_FAST_SEARCH, params.fastSearch);
store.setValue(PROP_SEARCH_NUMBERS, params.searchNumbers);
store.setValue(PROP_SEARCH_LOBS, params.searchLOBs);
saveTreeState(store, PROP_SOURCES, dataSourceTree);
{
// Search history
int historyIndex = 0;
for (String history : searchHistory) {
if (historyIndex >= 20) {
break;
}
store.setValue(PROP_HISTORY + "." + historyIndex, history); //$NON-NLS-1$
historyIndex++;
}
}
}
protected static void saveTreeState(DBPPreferenceStore store, String propName, DatabaseNavigatorTree tree)
{
// Object sources
StringBuilder sourcesString = new StringBuilder();
for (Object obj : ((CheckboxTreeViewer) tree.getViewer()).getCheckedElements()) {
DBNNode node = (DBNNode) obj;
if (node instanceof DBNDatabaseNode && ((DBNDatabaseNode) node).getObject() instanceof DBSDataContainer) {
if (sourcesString.length() > 0) {
sourcesString.append("|"); //$NON-NLS-1$
}
sourcesString.append(node.getNodeItemPath());
}
}
store.setValue(propName, sourcesString.toString());
}
protected List<DBSDataContainer> getCheckedSources()
{
List<DBSDataContainer> result = new ArrayList<>();
for (Object sel : ((CheckboxTreeViewer)dataSourceTree.getViewer()).getCheckedElements()) {
if (sel instanceof DBSWrapper) {
DBSObject object = ((DBSWrapper) sel).getObject();
if (object instanceof DBSDataContainer && object.getDataSource() != null) {
result.add((DBSDataContainer) object);
}
}
}
return result;
}
protected void updateEnablement()
{
boolean enabled = false;
if (!getCheckedSources().isEmpty()) {
enabled = true;
}
container.setPerformActionEnabled(enabled);
}
}