JavaFX/ScalaFX & Clipboard: Cannot copy files? - scala

Copying files does not work:
def toClipboard(selectedLinesOnly: Boolean = false): Unit = {
val clipboard = Clipboard.systemClipboard
val content = new ClipboardContent
val items: Iterable[FileRecord] = selectedLinesOnly match {
case true => tableView.selectionModel.value.selectedItems.toSeq
case false => tableView.items.value
}
val files = items.map(_.file)
println(s"COPY $files")
content.putFiles(files.toSeq)
clipboard.content = content
}
Output: [info] COPY [SFX][/tmp/test/a.txt, /tmp/test/b.txt]
No files to paste.
def toClipboard(selectedLinesOnly: Boolean = false): Unit = {
val clipboard = Clipboard.systemClipboard
val content = new ClipboardContent
val items: Iterable[FileRecord] = selectedLinesOnly match {
case true => tableView.selectionModel.value.selectedItems.toSeq
case false => tableView.items.value
}
val files = items.map(_.file.getPath)
println(s"COPY $files")
content.putFilesByPath(files.toSeq)
clipboard.content = content
}
Output: [info] COPY [SFX][/tmp/test/a.txt, /tmp/test/b.txt]
No files to paste.
def toClipboard(selectedLinesOnly: Boolean = false): Unit = {
val clipboard = Clipboard.systemClipboard
val content = new ClipboardContent
val items: Iterable[FileRecord] = selectedLinesOnly match {
case true => tableView.selectionModel.value.selectedItems.toSeq
case false => tableView.items.value
}
val files = items.map("file://" + _.file.getPath)
println(s"COPY $files")
content.putFilesByPath(files.toSeq)
clipboard.content = content
}
Output: [info] COPY [SFX][file:///tmp/test/a.txt, file:///tmp/test/b.txt]
No files to paste.
But copying the paths to the string clipboard is possible:
def toClipboard(selectedLinesOnly: Boolean = false): Unit = {
val clipboard = Clipboard.systemClipboard
val content = new ClipboardContent
val items: Iterable[FileRecord] = selectedLinesOnly match {
case true => tableView.selectionModel.value.selectedItems.toSeq
case false => tableView.items.value
}
val files = items.map(_.file.getPath)
println(s"COPY $files")
content.putString(files.mkString(" "))
clipboard.content = content
}
Now this is in my clipboard: "/tmp/test/a.txt /tmp/test/b.txt"
But I need it in the form of files, not a string.
How can I make copying files work in my application?
I am working with OpenJFX 8 on Ubuntu.

ClipBoard doesn't have the functionality like FileUtils.copyDirectoryToDirectory and FileUtils.moveDirectoryToDirectory (aka copy or cut). Clipboard can give only path or general data. This features can be possible using Drag and Drop by Dragboard.
Dragboard of JavaFX:
During the drag-and-drop gesture, various types of data can be
transferred such as text, images, URLs, files, bytes, and strings.
The javafx.scene.input.DragEvent class is the basic class used to
implement the drag-and-drop gesture. For more information on
particular methods and other classes in the javafx.scene.input
package, see the API documentation.
For more, you can go through this tutorial: Drag-and-Drop Feature in JavaFX Applications
Dragboard JavaFX code sample: HelloDragAndDrop.java
package hellodraganddrop;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.input.*;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.stage.Stage;
/**
* Demonstrates a drag-and-drop feature.
*/
public class HelloDragAndDrop extends Application {
#Override public void start(Stage stage) {
stage.setTitle("Hello Drag And Drop");
Group root = new Group();
Scene scene = new Scene(root, 400, 200);
scene.setFill(Color.LIGHTGREEN);
final Text source = new Text(50, 100, "DRAG ME");
source.setScaleX(2.0);
source.setScaleY(2.0);
final Text target = new Text(250, 100, "DROP HERE");
target.setScaleX(2.0);
target.setScaleY(2.0);
source.setOnDragDetected(new EventHandler <MouseEvent>() {
public void handle(MouseEvent event) {
/* drag was detected, start drag-and-drop gesture*/
System.out.println("onDragDetected");
/* allow any transfer mode */
Dragboard db = source.startDragAndDrop(TransferMode.ANY);
/* put a string on dragboard */
ClipboardContent content = new ClipboardContent();
content.putString(source.getText());
db.setContent(content);
event.consume();
}
});
target.setOnDragOver(new EventHandler <DragEvent>() {
public void handle(DragEvent event) {
/* data is dragged over the target */
System.out.println("onDragOver");
/* accept it only if it is not dragged from the same node
* and if it has a string data */
if (event.getGestureSource() != target &&
event.getDragboard().hasString()) {
/* allow for both copying and moving, whatever user chooses */
event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
}
event.consume();
}
});
target.setOnDragEntered(new EventHandler <DragEvent>() {
public void handle(DragEvent event) {
/* the drag-and-drop gesture entered the target */
System.out.println("onDragEntered");
/* show to the user that it is an actual gesture target */
if (event.getGestureSource() != target &&
event.getDragboard().hasString()) {
target.setFill(Color.GREEN);
}
event.consume();
}
});
target.setOnDragExited(new EventHandler <DragEvent>() {
public void handle(DragEvent event) {
/* mouse moved away, remove the graphical cues */
target.setFill(Color.BLACK);
event.consume();
}
});
target.setOnDragDropped(new EventHandler <DragEvent>() {
public void handle(DragEvent event) {
/* data dropped */
System.out.println("onDragDropped");
/* if there is a string data on dragboard, read it and use it */
Dragboard db = event.getDragboard();
boolean success = false;
if (db.hasString()) {
target.setText(db.getString());
success = true;
}
/* let the source know whether the string was successfully
* transferred and used */
event.setDropCompleted(success);
event.consume();
}
});
source.setOnDragDone(new EventHandler <DragEvent>() {
public void handle(DragEvent event) {
/* the drag-and-drop gesture ended */
System.out.println("onDragDone");
/* if the data was successfully moved, clear it */
if (event.getTransferMode() == TransferMode.MOVE) {
source.setText("");
}
event.consume();
}
});
root.getChildren().add(source);
root.getChildren().add(target);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
Actually Java have some ways to copy file: 4 Ways to Copy File in Java
Resource Link:
How do I properly handle file copy/cut & paste in javafx?

My solution which I tested successfully with Ubuntu:
FilesTransferable.scala
package myapp.clipboard
import java.awt.datatransfer._
case class FilesTransferable(files: Iterable[String]) extends Transferable {
val clipboardString: String = "copy\n" + files.map(path => s"file://$path").mkString("\n")
val dataFlavor = new DataFlavor("x-special/gnome-copied-files")
def getTransferDataFlavors(): Array[DataFlavor] = {
Seq(dataFlavor).toArray
}
def isDataFlavorSupported(flavor: DataFlavor): Boolean = {
dataFlavor.equals(flavor)
}
#throws(classOf[UnsupportedFlavorException])
#throws(classOf[java.io.IOException])
def getTransferData(flavor: DataFlavor): Object = {
if(flavor.getRepresentationClass() == classOf[java.io.InputStream]) {
new java.io.ByteArrayInputStream(clipboardString.getBytes())
} else {
return null;
}
}
}
Clipboard.scala
package myapp.clipboard
import java.awt.Toolkit
import java.awt.datatransfer._
object Clipboard {
def toClipboard(
transferable: Transferable,
lostOwnershipCallback: (Clipboard, Transferable) => Unit =
{ (clipboard: Clipboard, contents: Transferable) => Unit }
): Unit = {
Toolkit.getDefaultToolkit.getSystemClipboard.setContents(
transferable,
new ClipboardOwner {
def lostOwnership(clipboard: Clipboard, contents: Transferable): Unit = {
lostOwnershipCallback(clipboard, contents)
}
}
)
}
}
Quite a lot code for such a basic functionality (and still not OS independent).
Usage Example:
val transferable = FilesTransferable(filePaths)
myapp.clipboard.Clipboard.toClipboard(transferable, { (cb, contents) =>
println(s"lost clipboard ownership (clipboard: $cb)")
})
If it is true that there still do not exist any solutions which are part of Java-AWT/Swing/JavaFX/Scala-Swing/ScalaFX (actually, I still can't believe it), my plan is to build an easy-to-use clipboard library which supports at least OS X, Ubuntu and Windows.

Related

Change 2nd parameter of method 'PlaceAutocompleteAdapter' from 'GeoDataClient' to 'GoogleApiClient'

i ma making AutoCompleteTextView in my adapter for which when i make object of PlaceAutocompleteAdapter when i pass GoogleApiClient object as second parameter to my PlaceAutocompleteAdapter it gives me red error and sys to pass GEODataClient object instead of GoogleApiClient
while the code for my Fragment containing map is this
package com.example.anonymous.ghar_ka_khana;
import android.app.FragmentManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.net.Uri;
import android.os.Bundle;
import android.app.Fragment;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.places.Places;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import android.Manifest;
import android.widget.AutoCompleteTextView;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.Executor;
public class GoogleFragment extends Fragment implements OnMapReadyCallback,LocationListener,GoogleApiClient.OnConnectionFailedListener {
private MapFragment m;
private GoogleMap mMap;
FusedLocationProviderClient fusedLocationProviderClient;
private int REQUEST_PERMISSIONS_REQUEST_CODE = 125;
protected Location mLastLocation;
private AutoCompleteTextView autoCompleteTextView;
private PlaceAutocompleteAdapter autocompleteAdapter;
private String mLatitiudelabel;
private String mLongitudelabel;
private GoogleApiClient mGoogleApiClient;
private static LatLngBounds Lat_Long_Bounds = new LatLngBounds(new LatLng(-40,-168),new LatLng(71,136));
View v;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
Log.i("pahlywala", "onCreateView");
v = inflater.inflate(R.layout.fragment_google, container, false);
mGoogleApiClient = new GoogleApiClient
.Builder(getActivity())
.addApi(Places.GEO_DATA_API)
.addApi(Places.PLACE_DETECTION_API)
.enableAutoManage(new DrawerActivity(), this)
.build();
autoCompleteTextView = (AutoCompleteTextView)v.findViewById(R.id.mapsearch);
autocompleteAdapter = new PlaceAutocompleteAdapter(getActivity(),mGoogleApiClient,Lat_Long_Bounds,null);
autoCompleteTextView.setAdapter(autocompleteAdapter);
return v;
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mLatitiudelabel = "Latitude";
mLongitudelabel = "Longitude";
FragmentManager fragmentManager = getActivity().getFragmentManager();
final MapFragment myMapFragment = (MapFragment) fragmentManager.findFragmentById(R.id.googlemap);
myMapFragment.getMapAsync(this);
Log.i("pahlywalass", "onViewCreated");
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(getActivity());
}
#Override
public void onMapReady(GoogleMap googleMap)
{
mMap=googleMap;
mMap.addMarker(new MarkerOptions()
.position(new LatLng(0, 0))
.title("Marker"));
}
#Override
public void onLocationChanged(Location location) {
}
#Override
public void onStart() {
super.onStart();
if (!checkPermissions()) {
requestPermissions();
} else {
getLastLocation();
}
}
private boolean checkPermissions() {
int permissionState = ActivityCompat.checkSelfPermission(getActivity(),
Manifest.permission.ACCESS_FINE_LOCATION);
return permissionState == PackageManager.PERMISSION_GRANTED;
}
private void requestPermissions() {
boolean shouldProvideRationale =
ActivityCompat.shouldShowRequestPermissionRationale(getActivity(),
Manifest.permission.ACCESS_FINE_LOCATION);
// Provide an additional rationale to the user. This would happen if the user denied the
// request previously, but didn't check the "Don't ask again" checkbox.
if (shouldProvideRationale) {
Log.i("displaying permission", "Displaying permission rationale to provide additional context.");
/* showSnackbar("warning", android.R.string.ok,
new View.OnClickListener() {
#Override
public void onClick(View view) {
// Request permission
startLocationPermissionRequest();
}
});*/
} else {
Log.i("requesting permission", "Requesting permission");
// Request permission. It's possible this can be auto answered if device policy
// sets the permission in a given state or the user denied the permission
// previously and checked "Never ask again".
startLocationPermissionRequest();
}
}
private void startLocationPermissionRequest() {
ActivityCompat.requestPermissions(new DrawerActivity(),
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
REQUEST_PERMISSIONS_REQUEST_CODE);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions,
#NonNull int[] grantResults) {
Log.i("onRequestPerm", "onRequestPermissionResult");
if (requestCode == REQUEST_PERMISSIONS_REQUEST_CODE) {
if (grantResults.length <= 0) {
// If user interaction was interrupted, the permission request is cancelled and you
// receive empty arrays.
Log.i("onRequestPerm", "User interaction was cancelled.");
} else if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted.
getLastLocation();
} else {
// Permission denied.
// Notify the user via a SnackBar that they have rejected a core permission for the
// app, which makes the Activity useless. In a real app, core permissions would
// typically be best requested during a welcome-screen flow.
// Additionally, it is important to remember that a permission might have been
// rejected without asking the user for permission (device policy or "Never ask
// again" prompts). Therefore, a user interface affordance is typically implemented
// when permissions are denied. Otherwise, your app could appear unresponsive to
// touches or interactions which have required permissions.
/*showSnackbar(R.string.textwarn, R.string.settings,
new View.OnClickListener() {
#Override
public void onClick(View view) {
// Build intent that displays the App settings screen.
Intent intent = new Intent();
intent.setAction(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package",
BuildConfig.APPLICATION_ID, null);
intent.setData(uri);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
});*/
}
}
}
private void getLastLocation() {
if (ActivityCompat.checkSelfPermission(getActivity(), android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
fusedLocationProviderClient.getLastLocation()
.addOnCompleteListener(getActivity(), new OnCompleteListener<Location>() {
#Override
public void onComplete(#NonNull Task<Location> task) {
if (task.isSuccessful() && task.getResult() != null) {
mLastLocation = task.getResult();
Log.i("Longitutde", mLastLocation.getLongitude()+"");
Log.i("Longitutde", mLastLocation.getLatitude()+"");
LatLng cur_Latlng=new LatLng(mLastLocation.getLatitude(),mLastLocation.getLongitude()); // giving your marker to zoom to your location area.
mMap.addMarker(new MarkerOptions()
.position(cur_Latlng)
.title("umair"));
mMap.moveCamera(CameraUpdateFactory.newLatLng(cur_Latlng));
mMap.animateCamera(CameraUpdateFactory.zoomTo(12));
Geocoder geocoder;
List<Address> addresses = null;
geocoder = new Geocoder(getActivity(), Locale.getDefault());
try {
addresses = geocoder.getFromLocation(mLastLocation.getLatitude(),mLastLocation.getLongitude(), 1); // Here 1 represent max location result to returned, by documents it recommended 1 to 5
} catch (IOException e) {
e.printStackTrace();
}
String address = addresses.get(0).getAddressLine(0); // If any additional address line present than only, check with max available address lines by getMaxAddressLineIndex()
String city = addresses.get(0).getLocality();
/*String state = addresses.get(0).getAdminArea();
String country = addresses.get(0).getCountryName();
String postalCode = addresses.get(0).getPostalCode();
String knownName = addresses.get(0).getFeatureName();*/
Log.i("pat", ""+city);
}
else {
Log.i("getlasts", "getLastLocation:exception", task.getException());
}
}
});
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
}
while the code for PlaceAutoCompleteAdapter is following
package com.example.anonymous.ghar_ka_khana;
/**
* Created by Anonymous on 2/19/2018.
*/
import android.content.Context;
import android.graphics.Typeface;
import android.text.style.CharacterStyle;
import android.text.style.StyleSpan;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.common.data.DataBufferUtils;
import com.google.android.gms.location.places.AutocompleteFilter;
import com.google.android.gms.location.places.AutocompletePrediction;
import com.google.android.gms.location.places.AutocompletePredictionBufferResponse;
import com.google.android.gms.location.places.GeoDataClient;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.tasks.RuntimeExecutionException;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.Tasks;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* Adapter that handles Autocomplete requests from the Places Geo Data Client.
* {#link AutocompletePrediction} results from the API are frozen and stored directly in this
* adapter. (See {#link AutocompletePrediction#freeze()}.)
*/
public class PlaceAutocompleteAdapter
extends ArrayAdapter<AutocompletePrediction> implements Filterable {
private static final String TAG = "PlaceAutocompleteAd";
private static final CharacterStyle STYLE_BOLD = new StyleSpan(Typeface.BOLD);
/**
* Current results returned by this adapter.
*/
private ArrayList<AutocompletePrediction> mResultList;
/**
* Handles autocomplete requests.
*/
private GeoDataClient mGeoDataClient;
/**
* The bounds used for Places Geo Data autocomplete API requests.
*/
private LatLngBounds mBounds;
/**
* The autocomplete filter used to restrict queries to a specific set of place types.
*/
private AutocompleteFilter mPlaceFilter;
/**
* Initializes with a resource for text rows and autocomplete query bounds.
*
* #see android.widget.ArrayAdapter#ArrayAdapter(android.content.Context, int)
*/
public PlaceAutocompleteAdapter(Context context, GeoDataClient geoDataClient,
LatLngBounds bounds, AutocompleteFilter filter) {
super(context, android.R.layout.simple_expandable_list_item_2, android.R.id.text1);
mGeoDataClient = geoDataClient;
mBounds = bounds;
mPlaceFilter = filter;
}
/**
* Sets the bounds for all subsequent queries.
*/
public void setBounds(LatLngBounds bounds) {
mBounds = bounds;
}
/**
* Returns the number of results received in the last autocomplete query.
*/
#Override
public int getCount() {
return mResultList.size();
}
/**
* Returns an item from the last autocomplete query.
*/
#Override
public AutocompletePrediction getItem(int position) {
return mResultList.get(position);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = super.getView(position, convertView, parent);
// Sets the primary and secondary text for a row.
// Note that getPrimaryText() and getSecondaryText() return a CharSequence that may contain
// styling based on the given CharacterStyle.
AutocompletePrediction item = getItem(position);
TextView textView1 = (TextView) row.findViewById(android.R.id.text1);
TextView textView2 = (TextView) row.findViewById(android.R.id.text2);
textView1.setText(item.getPrimaryText(STYLE_BOLD));
textView2.setText(item.getSecondaryText(STYLE_BOLD));
return row;
}
/**
* Returns the filter for the current set of autocomplete results.
*/
#Override
public Filter getFilter() {
return new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
// We need a separate list to store the results, since
// this is run asynchronously.
ArrayList<AutocompletePrediction> filterData = new ArrayList<>();
// Skip the autocomplete query if no constraints are given.
if (constraint != null) {
// Query the autocomplete API for the (constraint) search string.
filterData = getAutocomplete(constraint);
}
results.values = filterData;
if (filterData != null) {
results.count = filterData.size();
} else {
results.count = 0;
}
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if (results != null && results.count > 0) {
// The API returned at least one result, update the data.
mResultList = (ArrayList<AutocompletePrediction>) results.values;
notifyDataSetChanged();
} else {
// The API did not return any results, invalidate the data set.
notifyDataSetInvalidated();
}
}
#Override
public CharSequence convertResultToString(Object resultValue) {
// Override this method to display a readable result in the AutocompleteTextView
// when clicked.
if (resultValue instanceof AutocompletePrediction) {
return ((AutocompletePrediction) resultValue).getFullText(null);
} else {
return super.convertResultToString(resultValue);
}
}
};
}
/**
* Submits an autocomplete query to the Places Geo Data Autocomplete API.
* Results are returned as frozen AutocompletePrediction objects, ready to be cached.
* Returns an empty list if no results were found.
* Returns null if the API client is not available or the query did not complete
* successfully.
* This method MUST be called off the main UI thread, as it will block until data is returned
* from the API, which may include a network request.
*
* #param constraint Autocomplete query string
* #return Results from the autocomplete API or null if the query was not successful.
* #see GeoDataClient#getAutocompletePredictions(String, LatLngBounds, AutocompleteFilter)
* #see AutocompletePrediction#freeze()
*/
private ArrayList<AutocompletePrediction> getAutocomplete(CharSequence constraint) {
Log.i(TAG, "Starting autocomplete query for: " + constraint);
// Submit the query to the autocomplete API and retrieve a PendingResult that will
// contain the results when the query completes.
Task<AutocompletePredictionBufferResponse> results =
mGeoDataClient.getAutocompletePredictions(constraint.toString(), mBounds,
mPlaceFilter);
// This method should have been called off the main UI thread. Block and wait for at most
// 60s for a result from the API.
try {
Tasks.await(results, 60, TimeUnit.SECONDS);
} catch (ExecutionException | InterruptedException | TimeoutException e) {
e.printStackTrace();
}
try {
AutocompletePredictionBufferResponse autocompletePredictions = results.getResult();
Log.i(TAG, "Query completed. Received " + autocompletePredictions.getCount()
+ " predictions.");
// Freeze the results immutable representation that can be stored safely.
return DataBufferUtils.freezeAndClose(autocompletePredictions);
} catch (RuntimeExecutionException e) {
// If the query did not complete successfully return null
Toast.makeText(getContext(), "Error contacting API: " + e.toString(),
Toast.LENGTH_SHORT).show();
Log.e(TAG, "Error getting autocomplete prediction API call", e);
return null;
}
}
}
my gradle file is following
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
defaultConfig {
applicationId "com.example.anonymous.ghar_ka_khana"
minSdkVersion 17
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
productFlavors {
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
implementation 'com.google.firebase:firebase-database:11.8.0'
//11.0.4
implementation 'com.android.support:support-v4:26.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
implementation 'com.google.android.gms:play-services:11.8.0'
implementation 'com.firebaseui:firebase-ui-auth:3.1.3'
// FirebaseUI for Firebase Auth
implementation 'com.firebaseui:firebase-ui-database:3.1.3'
// FirebaseUI for Firebase Realtime Database
implementation 'com.firebaseui:firebase-ui-firestore:3.1.3'
// FirebaseUI for Cloud Firestore
compile 'com.google.firebase:firebase-firestore:11.8.0'
//Firestore dependency
implementation 'com.firebaseui:firebase-ui-storage:3.1.3'
// FirebaseUI for Cloud Storage
implementation 'com.facebook.android:facebook-login:4.29.0'
// Required only if Facebook login support is required
implementation 'de.hdodenhof:circleimageview:2.2.0'
implementation 'com.github.florent37:materialtextfield:1.0.7'
compile 'com.scalified:fab:1.1.3'
compile 'com.google.firebase:firebase-storage:11.8.0'
compile 'com.google.firebase:firebase-auth:11.8.0'
compile 'com.github.glomadrian:Grav:1.1'
implementation('com.mikepenz:materialdrawer:6.0.6#aar') {
transitive = true
}
compile 'com.wdullaer:materialdatetimepicker:3.5.1'
implementation 'com.android.support:design:26.1.0'
implementation 'com.android.support:recyclerview-v7:26.1.0'
implementation 'com.android.support:support-annotations:26.1.0'
implementation 'com.google.android.gms:play-services:11.8.0'
implementation 'com.google.android.gms:play-services-location:11.8.0'
}
apply plugin: 'com.google.gms.google-services'
configurations.all {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
def requested = details.requested
if (requested.group == 'com.android.support') {
if (!requested.name.startsWith("multidex")) {
details.useVersion '26.1.0'
}
}
}
}
Ok. I've got the solution instead of using:
autocompleteAdapter = new PlaceAutocompleteAdapter(getActivity(),mGoogleApiClient,Lat_Long_Bounds,null);
you will have to use:
autocompleteAdapter = new PlaceAutocompleteAdapter(getActivity(),Places.getGeoDataClient(getActivity(), null),Lat_Long_Bounds,null);

Updating the color of rows of a TableView consumes too much CPU

I am making an application that receives alerts.
An alert can have 4 possible states:
Unresolved_New_0
Unresolved_New_1
Unresolved_Old
Resolved
When an alert is received, it is in Unresolved_New_0 state. For 10 seconds, every 0.5s the state changes from Unresolved_New_0 to Unresolved_New_1 and vice-versa. Depending on state I, set a different background color to the table row (so that it flashes, for 10s).
When the 10s pass, the alert transitions to Unresolved_Old state. This causes its color to stop changing.
To implement this, I have a ScheduledThreadPoolExecutor that I use to submit an implementation of Runnable that for some time executes a runnable using Platform.runLater.
static class FxTask extends Runnable {
/**
*
* #param runnableDuring Runnable to be run while the task is active (run on the JavaFX application thread).
* #param runnableAfter Runnable to be run after the given duration is elapsed (run on the JavaFX application thread).
* #param duration Duration to run this task for.
* #param unit Time unit.
*/
public static FxTask create(final Runnable runnableDuring, final Runnable runnableAfter, final long duration, final TimeUnit unit) {
return new FxTask(runnableDuring, runnableAfter, duration, unit);
}
#Override
public void run() {
if (System.nanoTime() - mTimeStarted >= mTimeUnit.toNanos(mDuration) )
{
cancel();
Platform.runLater(mRunnableAfter);
}
else
Platform.runLater(mRunnableDuring);
}
private FxTask(final Runnable during, final Runnable after, final long duration, final TimeUnit unit) {
mRunnableDuring = during;
mRunnableAfter = after;
mDuration = duration;
mTimeUnit = unit;
mTimeStarted = System.nanoTime();
}
private final Runnable mRunnableDuring;
private final Runnable mRunnableAfter;
private final long mDuration;
private final TimeUnit mTimeUnit;
private final long mTimeStarted;
}
And I schedule Alerts using that Runnable as follows:
final Alert alert = new Alert(...);
scheduler.scheduleAtFixedRate(FxTask.create(
() -> {
switch (alert.alertStateProperty().get()) {
case UNRESOLVED_NEW_0:
alert.alertStateProperty().set(Alert.State.UNRESOLVED_NEW_1);
refreshTable(mAlertsTable);
break;
case UNRESOLVED_NEW_1:
alert.alertStateProperty().set(Alert.State.UNRESOLVED_NEW_0);
refreshTable(mAlertsTable);
break;
}
},
() -> { // This is run at the end
if (equalsAny(alert.alertStateProperty().get(), Alert.State.UNRESOLVED_NEW_0, SpreadAlert.State.UNRESOLVED_NEW_1)) {
alert.alertStateProperty().set(Alert.State.UNRESOLVED_OLD);
refreshTable(mAlertsTable);
}
},
10, TimeUnit.SECONDS), 0, 500, TimeUnit.MILLISECONDS
);
Note: alertStateProperty() is not shown on the TableView (it is not bound to any of its columns).
So in order to force JavaFx to redraw, I have to use refreshTable(), which unfortunately redraws the whole table (?).
public static <T> void refreshTable(final TableView<T> table) {
table.getColumns().get(0).setVisible(false);
table.getColumns().get(0).setVisible(true);
}
The problem is that even if I create a small number of Alerts at the same time, CPU usage goes very high: from 20% to 84% sometimes, averaging at about 40%. When the 10s pass for all alerts, CPU consumptions returns to 0%. If I comment out refreshTable(), CPU stays near 0%, which indicates that it is the problem.
Why is so much CPU being used? (I have 8 cores by the way).
Is there another way to redraw just a single row without redrawing the whole table?
I even tried a 'hacky' method -- changing all values of the Alerts and then resetting them back to cause JavaFx to detect the change and redraw, but CPU was again at the same levels.
Probably the most efficient way to change the color of a table row is to use a table row factory, have the table row it creates observe the appropriate property, and update one or more CSS PseudoClass states as appropriate. Then just define the colors in an external css file.
Here's a standalone version of the application you described. I just used a Timeline to perform the "flashing new alerts", which is less code; but use the executor as you have it if you prefer. The key idea here is the table row factory, and the pseudoclass state it manipulates by observing the property. On my system, if I fill the entire table with new (flashing) rows, the CPU doesn't exceed about 35% (percentage of one core), which seems perfectly acceptable.
Note that PseudoClass was introduced in Java 8. In earlier versions of JavaFX you can achieve the same by manipulating the style classes instead, though you have to be careful not to duplicate any style classes as they are stored as a List. Anecdotally, the pseudoclass approach is more efficient.
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ListChangeListener.Change;
import javafx.css.PseudoClass;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import javafx.stage.Stage;
import javafx.util.Duration;
public class AlertTableDemo extends Application {
#Override
public void start(Stage primaryStage) {
TableView<Alert> table = new TableView<>();
table.getColumns().add(createColumn("Name", Alert::nameProperty));
table.getColumns().add(createColumn("Value", Alert::valueProperty));
TableColumn<Alert, Alert> resolveCol =
createColumn("Resolve", ReadOnlyObjectWrapper<Alert>::new);
resolveCol.setCellFactory(this::createResolveCell);
table.getColumns().add(resolveCol);
// just need a wrapper really, don't need the atomicity...
AtomicInteger alertCount = new AtomicInteger();
Random rng = new Random();
Button newAlertButton = new Button("New Alert");
newAlertButton.setOnAction( event ->
table.getItems().add(new Alert("Alert "+alertCount.incrementAndGet(),
rng.nextInt(20)+1)));
// set psuedo-classes on table rows depending on alert state:
table.setRowFactory(tView -> {
TableRow<Alert> row = new TableRow<>();
ChangeListener<Alert.State> listener = (obs, oldState, newState) ->
updateTableRowPseudoClassState(row, row.getItem().getState());
row.itemProperty().addListener((obs, oldAlert, newAlert) -> {
if (oldAlert != null) {
oldAlert.stateProperty().removeListener(listener);
}
if (newAlert == null) {
clearTableRowPseudoClassState(row);
} else {
updateTableRowPseudoClassState(row, row.getItem().getState());
newAlert.stateProperty().addListener(listener);
}
});
return row ;
});
// flash new alerts:
table.getItems().addListener((Change<? extends Alert> change) -> {
while (change.next()) {
if (change.wasAdded()) {
List<? extends Alert> newAlerts =
new ArrayList<>(change.getAddedSubList());
flashAlerts(newAlerts);
}
}
});
HBox controls = new HBox(5, newAlertButton);
controls.setPadding(new Insets(10));
controls.setAlignment(Pos.CENTER);
BorderPane root = new BorderPane(table, null, null, controls, null);
Scene scene = new Scene(root, 800, 600);
scene.getStylesheets().add(
getClass().getResource("alert-table.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
private void flashAlerts(List<? extends Alert> newAlerts) {
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(0.5),
event -> {
for (Alert newAlert : newAlerts) {
if (newAlert.getState()==Alert.State.UNRESOLVED_NEW_0) {
newAlert.setState(Alert.State.UNRESOLVED_NEW_1);
} else if (newAlert.getState() == Alert.State.UNRESOLVED_NEW_1){
newAlert.setState(Alert.State.UNRESOLVED_NEW_0);
}
}
}));
timeline.setOnFinished(event -> {
for (Alert newAlert : newAlerts) {
if (newAlert.getState() != Alert.State.RESOLVED) {
newAlert.setState(Alert.State.UNRESOLVED_OLD);
}
}
});
timeline.setCycleCount(20);
timeline.play();
}
private void clearTableRowPseudoClassState(Node node) {
node.pseudoClassStateChanged(PseudoClass.getPseudoClass("unresolved-new"), false);
node.pseudoClassStateChanged(PseudoClass.getPseudoClass("unresolved-new-alt"), false);
node.pseudoClassStateChanged(PseudoClass.getPseudoClass("unresolved-old"), false);
node.pseudoClassStateChanged(PseudoClass.getPseudoClass("resolved"), false);
}
private void updateTableRowPseudoClassState(Node node, Alert.State state) {
node.pseudoClassStateChanged(PseudoClass.getPseudoClass("unresolved-new"),
state==Alert.State.UNRESOLVED_NEW_0);
node.pseudoClassStateChanged(PseudoClass.getPseudoClass("unresolved-new-alt"),
state==Alert.State.UNRESOLVED_NEW_1);
node.pseudoClassStateChanged(PseudoClass.getPseudoClass("unresolved-old"),
state==Alert.State.UNRESOLVED_OLD);
node.pseudoClassStateChanged(PseudoClass.getPseudoClass("resolved"),
state==Alert.State.RESOLVED);
}
private TableCell<Alert, Alert> createResolveCell(TableColumn<Alert, Alert> col) {
TableCell<Alert, Alert> cell = new TableCell<>();
Button resolveButton = new Button("Resolve");
resolveButton.setOnAction(event ->
cell.getItem().setState(Alert.State.RESOLVED));
cell.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
cell.setAlignment(Pos.CENTER);
cell.graphicProperty().bind(
Bindings.when(cell.emptyProperty())
.then((Node)null)
.otherwise(resolveButton));
return cell ;
}
private <S, T> TableColumn<S, T> createColumn(String title,
Function<S, ObservableValue<T>> propertyMapper) {
TableColumn<S,T> col = new TableColumn<>(title);
col.setCellValueFactory(cellData -> propertyMapper.apply(cellData.getValue()));
col.setMinWidth(Region.USE_PREF_SIZE);
col.setPrefWidth(150);
return col ;
}
public static class Alert {
public enum State {
UNRESOLVED_NEW_0, UNRESOLVED_NEW_1, UNRESOLVED_OLD, RESOLVED
}
private final ObjectProperty<State> state = new SimpleObjectProperty<>();
private final StringProperty name = new SimpleStringProperty();
private final IntegerProperty value = new SimpleIntegerProperty();
public final ObjectProperty<State> stateProperty() {
return this.state;
}
public final AlertTableDemo.Alert.State getState() {
return this.stateProperty().get();
}
public final void setState(final AlertTableDemo.Alert.State state) {
this.stateProperty().set(state);
}
public final StringProperty nameProperty() {
return this.name;
}
public final java.lang.String getName() {
return this.nameProperty().get();
}
public final void setName(final java.lang.String name) {
this.nameProperty().set(name);
}
public final IntegerProperty valueProperty() {
return this.value;
}
public final int getValue() {
return this.valueProperty().get();
}
public final void setValue(final int value) {
this.valueProperty().set(value);
}
public Alert(String name, int value) {
setName(name);
setValue(value);
setState(State.UNRESOLVED_NEW_0);
}
}
public static void main(String[] args) {
launch(args);
}
}
alert-table.css:
.table-row-cell:resolved {
-fx-background: green ;
}
.table-row-cell:unresolved-old {
-fx-background: red ;
}
.table-row-cell:unresolved-new {
-fx-background: blue ;
}
.table-row-cell:unresolved-new-alt {
-fx-background: yellow ;
}

Dragging and dropping list view items between different javafx windows

I've been wondering how you would be able to drag and drop list view items between 2 java fx windows.
The code that I used was
tilePane.setOnDragDropped((event) -> {
Dragboard db = event.getDragboard();
boolean success = false;
if (db.hasString()) {
TilePane pane = (TilePane) event.getGestureTarget();
if (pane.getChildren().size() >= 10) {
//error
} else {
ListView<Item> list = (ListView<Item>) event
.getGestureSource();
addShopItem(pane, list.getSelectionModel()
.getSelectedItem());
success = true;
}
}
event.setDropCompleted(success);
event.consume();
});
Both the list view and tile pane used to be in one window but I've decided to make seperate them into different javafx windows so it would allow for more flexibility. One window has the list view and the other has the tilepane.
I would like to drag the list view item to the tilepane(other window) but this code no longer works because getGestureTarget() is null for different applications.
Thanks
It does look like the gesture source and target both get set to null when the drag leaves the JavaFX application (e.g. moving it between two windows).
For the gesture source, you may need to manage that yourself by creating a property and setting its value in the onDragDetected handler.
The gesture target is surely just the tile pane to which you attached the onDragDropped listener. So I don't see that you need to access that from the event; though you could use the same technique.
Example:
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.Scene;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class DnDListViews extends Application {
private int counter = 0 ;
private final ObjectProperty<ListCell<String>> dragSource = new SimpleObjectProperty<>();
#Override
public void start(Stage primaryStage) {
populateStage(primaryStage);
primaryStage.show();
Stage anotherStage = new Stage();
populateStage(anotherStage);
anotherStage.setX(primaryStage.getX() + 300);
anotherStage.show();
}
private void populateStage(Stage stage) {
ListView<String> listView = new ListView<>();
for (int i=0; i<5; i++ ) {
listView.getItems().add("Item "+(++counter));
}
listView.setCellFactory(lv -> {
ListCell<String> cell = new ListCell<String>(){
#Override
public void updateItem(String item , boolean empty) {
super.updateItem(item, empty);
setText(item);
}
};
cell.setOnDragDetected(event -> {
if (! cell.isEmpty()) {
Dragboard db = cell.startDragAndDrop(TransferMode.MOVE);
ClipboardContent cc = new ClipboardContent();
cc.putString(cell.getItem());
db.setContent(cc);
dragSource.set(cell);
}
});
cell.setOnDragOver(event -> {
Dragboard db = event.getDragboard();
if (db.hasString()) {
event.acceptTransferModes(TransferMode.MOVE);
}
});
cell.setOnDragDone(event -> listView.getItems().remove(cell.getItem()));
cell.setOnDragDropped(event -> {
Dragboard db = event.getDragboard();
if (db.hasString() && dragSource.get() != null) {
// in this example you could just do
// listView.getItems().add(db.getString());
// but more generally:
ListCell<String> dragSourceCell = dragSource.get();
listView.getItems().add(dragSourceCell.getItem());
event.setDropCompleted(true);
dragSource.set(null);
} else {
event.setDropCompleted(false);
}
});
return cell ;
});
BorderPane root = new BorderPane(listView);
Scene scene = new Scene(root, 250, 450);
stage.setScene(scene);
}
public static void main(String[] args) {
launch(args);
}
}
If the dragboard supported attaching arbitrary object references for drag and drop within the same JVM (see JIRA request, and vote if so inclined) then this would be quite a bit easier...

delete Treenode not removed

I am developing in Visual Studio 2012 web interface. When I remove a parent node it removes correctly, but when I try to remove a child node the node stays and does not seem to get removed. Both methods shows the same result.
Tree1.Nodes.Remove(e.Node);
This is a postback method removing the node with e as FineUI.TreeCommandEventArgs.
Tree1.Nodes.Remove(Tree1.SelectedNode);
This is another method to remove the node. There is no update or refresh method to refresh the tree. Both of which cannot delete a child node.
Another question would be that I want to update the database based on the SelectedNode, the SelectedNodeID contains a string with the ID value, but it exist in a form like fnode1 where I only want the integer value at the end. I want to know how to get just the integer value so I can delete the selected node from the database.
what u need to do is you need to take DefaultNode from Tree and then u have to Remove it. see this.
DefaultMutableTreeNode defaultMutableTreeNode = new DefaultMutableTreeNode(node_vervesystems);
model.removeNodeFromParent(defaultMutableTreeNode);
that will Work.
Here the Example for the same.
import javax.swing.JFrame;
import javax.swing.*;
import javax.swing.tree.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* #author kishan
*/
public class JTreeRemoveNode extends JFrame{
public JTreeRemoveNode() throws HeadlessException {
initializeUI();
}
private void initializeUI() {
setSize(200, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Address Book");
String[] names = new String[] {"Alice", "Bob", "Carol", "Mallory"};
for (String name : names) {
DefaultMutableTreeNode node = new DefaultMutableTreeNode(name);
root.add(node);
}
final JTree tree = new JTree(root);
JScrollPane pane = new JScrollPane(tree);
pane.setPreferredSize(new Dimension(200, 400));
JButton removeButton = new JButton("Remove");
removeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
TreePath[] paths = tree.getSelectionPaths();
for (TreePath path : paths) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
if (node.getParent() != null) {
model.removeNodeFromParent(node);
}
}
}
});
getContentPane().setLayout(new BorderLayout());
getContentPane().add(tree, BorderLayout.CENTER);
getContentPane().add(removeButton, BorderLayout.SOUTH);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new JTreeRemoveNode().setVisible(true);
}
});
}
}
hope that will help.

Netbeans ExplorerTopComponent Node losing focus when showing dialog

I have a netbeans RCP application that shows a set of nodes in the explorertopcomponent. When selected, I display details on the editortopcomponent and it works well. When I show a dialog using JOptionPage on the editor, the selected node in the tree is deselected, and eventually my editortopcomponent also loses the selected node details. Is there a way to save the selected node in the tree from being deselected if a dialog opens?
Thanks.
it is simple.
In your explorertopcomponent you have LookupListner, that "is waiting" on event "someYourNodeClass" (for example Album)appears in the lookup. You must removeLookupListener, when your explorertopcomponent is not visible or yust do nothing.
/**
* your explorertopcomponent
*/
#ConvertAsProperties(
dtd = "-//com.galileo.netbeans.module//Y//EN",
autostore = false)
#TopComponent.Description(
preferredID = "YTopComponent",
//iconBase="SET/PATH/TO/ICON/HERE",
persistenceType = TopComponent.PERSISTENCE_ALWAYS)
#TopComponent.Registration(mode = "explorer", openAtStartup = false)
#ActionID(category = "Window", id = "com.galileo.netbeans.module.YTopComponent")
#ActionReference(path = "Menu/Window" /*, position = 333 */)
#TopComponent.OpenActionRegistration(
displayName = "#CTL_YAction",
preferredID = "YTopComponent")
#Messages({
"CTL_YAction=Y",
"CTL_YTopComponent=Y Window",
"HINT_YTopComponent=This is a Y window"
})
public final class YTopComponent extends TopComponent implements LookupListener {
private Lookup.Result<Album> result;
public YTopComponent() {
initComponents();
setName(Bundle.CTL_YTopComponent());
setToolTipText(Bundle.HINT_YTopComponent());
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
}// </editor-fold>
// Variables declaration - do not modify
// End of variables declaration
#Override
public void componentOpened() {
result = Utilities.actionsGlobalContext().lookupResult(Album.class);
result.addLookupListener(this);
}
#Override
public void componentClosed() {
result.removeLookupListener(this);
}
void writeProperties(java.util.Properties p) {
// better to version settings since initial version as advocated at
// http://wiki.apidesign.org/wiki/PropertyFiles
p.setProperty("version", "1.0");
// TODO store your settings
}
void readProperties(java.util.Properties p) {
String version = p.getProperty("version");
// TODO read your settings according to their version
}
public void resultChanged(LookupEvent le) {
Collection<? extends Album> allInstances = result.allInstances();
TopComponent findTopComponent = WindowManager.getDefault().findTopComponent("YourNodeExplorerWindow");
if (findTopComponent == null) {
return;
}
if (!findTopComponent.isShowing()) {
return;
}
if (!allInstances.isEmpty()) {
showDetail(allInstances.iterator().next());
}
}
}
Jirka