JavaFX (OpenJFX) not letting me print - javafx

My JavaFX program prepares and prints out a set of VBoxes.
This is ModPrintCycle. It is the Window that gives the options to print
public PrintCycle data;
//PrintCycle is a HashMap of VBoxes containing all the details
PrinterJob pj;
ChoiceBox<String> cbxPrinters = new ChoiceBox<String>();
ArrayList<Printer> arrPrinters = new ArrayList<Printer>();
//util.say just pops out a messagebox attached to ModPrintCycle.
public void printAll(ArrayList<String> pageList){
if(cbxPrinters.getSelectionModel().getSelectedIndex() >=0){
if (data.tables.size() > 0){
Printer curP = Printer.getDefaultPrinter();
if(arrPrinters.size() > 0 ){
curP = arrPrinters.get(cbxPrinters.getSelectionModel().getSelectedIndex());
}
try{
pj = PrinterJob.createPrinterJob(curP);
PageLayout pp = curP.createPageLayout(Paper.LEGAL, PageOrientation.PORTRAIT, MarginType.DEFAULT);
PageLayout pl = curP.createPageLayout(Paper.LEGAL, PageOrientation.LANDSCAPE, MarginType.DEFAULT);
for(String p : pageList){
Printable pt = data.tables.get(p);
pt.scaleToFit();
if(pt.isLandscape()){
pj.printPage(pl,pt);
}
else{
pj.printPage(pp,pt);
}
}
pj.endJob();
}catch(Exception e){
util.say(ModPrintCycle.this, "Error on Print");
}
}else{
util.say(ModPrintCycle.this, "Nothing to print");
}
}
else{
util.say(ModPrintCycle.this, "No Printer Selected");
}
}
Printer is installed and set as default, and my program detects it. But when I print, no errors pop out, and the printer receives no jobs.
I'm sure my program worked before (A Lubuntu 15.10, 32-bit.). But now, I transfered it to a different computer. A Lubuntu 15.10, 64-bit. I have openjfx and openjdk version "1.8.0_66-internal" installed.
What can I do to find out why it's not printing?
Tried to make a smaller print job, but to the same effect.
Button testPrint = new Button("Test Print");
testPrint.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent arg0) {
try{
Printer p = Printer.getDefaultPrinter();
PrinterJob pj = PrinterJob.createPrinterJob(p);
//util.say(ModShortcuts.this, "Print: " + pj.getJobStatus());
Boolean k = pj.printPage(p.createPageLayout(Paper.LEGAL,PageOrientation.PORTRAIT,MarginType.DEFAULT), new Text("Hey"));
//util.password(); //reused for a showAndWait() dialog
//util.say(ModShortcuts.this, "Print: " + pj.getJobStatus());
//util.say(ModShortcuts.this, "attempted Print using: " + pj.getPrinter().getName());
if(k){
//util.say(ModShortcuts.this, "Print: " + pj.getJobStatus());
pj.endJob();
//util.say(ModShortcuts.this, "Print: " + pj.getJobStatus());
}
}catch(Exception e){
e.printStackTrace();
}
}
});
vbox.getChildren().add(testPrint);
Uncommented, the output is
Print: Not Printing
Print: Printing
attempted Print using: AstinePrinter
Print: Printing
Print: Done
AstinePrinter is the name of my printer.
Edit: Using
sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java8-installer
I installed Oracle Java 8, and still the same problem.
Edit: Also Oracle Java 7.
Edit:
Tried disabling the firewall, in case it was a port problem
sudo ufw disable
Still nothing.

I've found something called CUPS4J, and it allows me to bypass the problem it had concerning Java trying to access CUPS in a 64 bit Ubuntu. It prints out using Byte arrays, and luckily, JavaFX has a way to snapshot the chosen node.
It's a little blurry, but it's good enough. NOTE: I am no expert, and I don't know why this is needed. But doing this allowed me to use CUPS4J with no errors, so it must have been correct.
So, first of all, download the [ECLIPSE PROJECT] for cups4j,
because there are dependencies that have to be fixed. Import it into your project.
EDIT: The reason why the following is needed is that somehow, my package doesn't come with org.slf4j. If your class path says you have it, skip these steps.
Next, for each class there, all instances of Logger (cAsE
sEnSiTiVe) should be replaced with Log, and fix your imports (Ctrl+Shift+O). This will suggest a version of the Log, and LogFactory will be automatically detected. My import path says org.apache.commons.logging.*
Finally, remove the library dependency for org.slf4j in your build path under Libraries.
(I'm sure using the Runnable Jar is fine, but this is what I did because using the Runnable Jar gave me errors)
This is a simplification of what I did for my print function.
private void print(Region node){
//Make the image with the proper sizes
WritableImage wi = new WritableImage(
(int) Math.round(Math.ceil(node.getWidth())),
(int) Math.round(Math.ceil(node.getHeight())));
//shoot the image
wi = node.snapshot(new SnapshotParameters(), wi);
//write the image into a readable context
ByteArrayOutputStream out = new ByteArrayOutputStream();
try{
ImageIO.write(SwingFXUtils.fromFXImage(wi, null), "png", out);
}catch(Exception e){
System.out.println("Error with SnapShot function");
}
//Get your printer
CupsClient cc = new CupsClient();
CupsPrinter cp = cc.getDefaultPrinter();
//print the readable context
cp.print(new PrintJob.Builder(out.toByteArray()).build());
//unlike PrinterJob, you do not need to end it.
}
I'm not sure, but I've seen bug reports in the CUPS4J forum saying there's a problem with multiple pages, but I have yet to encounter that.
If someone has a better answer, feel free to add. But so far, this worked for me.

Related

Run .deb file in Java from file location

So I need to run a Debian(.deb) file at some point in my JavaFX program and so I tried using the code below on Linux
Runtime.getRuntime().exec("sudo dpkg -i "+pathToResource.getValue().toString());
but as you already know that requires me to also pass in the password along somehow for this to work
on Windows I used this sample code here
Runtime.getRuntime().exec(pathToResource.getValue().toString());
and it whenever administrator privilleges are needed then the software will just request them from the user and everything will run smoothly
But this doesn't seem to work on Linux, it just goes silent and nothing happens,
I already have an alternative to try to use TerminalFx, but if there's Anyone who knows what an alternative to run the .deb file or any other alternative, I'll be grateful. Thanks in Advance.
So I ended up using shellScript
Here's What I Did
Requested the device password from the user through a simple JavaFX stage with just a text field and a submit button.
Then I used the password that I just got from the user to create a shell script(Bash)
Here's my sample code to do create the sample shell Script
File shell_file = new File("path_to_the_file_where_the_shell_file_will_be_created_at_example_install.sh");
String variableName = "#!/bin/bash\npassword='" + password_from_JavaFx_stage + "'\n" +
"echo $password | sudo -S dpkg -i " + path_to_file_to_be_installed;
shell_file.createNewFile()// you can put an if to check if the function worked and otherwise do some other actions
FileWriter myWriter = new
FileWriter("path_to_the_file_where_the_shell_file_will_be_created_at_example_install.sh");
myWriter.write(messageContent);
myWriter.close();
Then Just run the command using the Processbuilder here's is a sample code to do so
String[] command = {String.valueOf(shell_file)};
ProcessBuilder processBuilder = new ProcessBuilder().command(command);
try {
Process process = processBuilder.start();
//read the output
InputStreamReader inputStreamReader = new
InputStreamReader(process.getInputStream());
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String output = null;
while ((output = bufferedReader.readLine()) != null) {
System.out.println(output);
}
process.waitFor();
//close the resources
bufferedReader.close();
process.destroy();
}catch(IOException | InterruptedException e) {
e.printStackTrace();
}
So That's the idea and it's my best hope this will save somebody's time and helps out in one way or another.

Project hangs on QProcess::start when starting QtAssistant

I am using QProcess::start to launch Qt Assistant with my custom help project file. It works fine until i load project(not help project file) to my programm. Programm generates images from specific data using custom library. Even when all processes ends and i see generated images and nothing else happens, when i trying to launch Qt Assistant, my programm hangs at QProcess:start function when trying to start process. The code is:
show() function(public):
if (!run())
return false;
QByteArray ba("setSource ");
ba.append("qthelp://insyn_help/doc/");
proc->write(ba + page.toLocal8Bit() + '\n');
return true;
run() function(private):
if (!proc)
proc = new QProcess();
if (proc->state() == QProcess::Running)
return true;
QString app = QString(QT_BIN_DIR) + QDir::separator() + QString("assistant");
QString path = QString(PREFIX) + QString(HELP_INSTALL_PATH) + QString("/help_project.qhc");
QStringList args;
args << QLatin1String("-collectionFile")
<< QLatin1String(path.toLatin1())
<< QLatin1String("-enableRemoteControl");
QFileInfo help_project(path);
if (help_project.exists()) {
proc->start(app,args);
if (!proc->waitForStarted()) {
m_exitCode = 1;
emit closed();
return false;
}
}
This code is a part of AssistantLauncher class which was registered using qmlRegisterType and added to main.qml as a member of application window. My programm doesn't touch it anywhere (except calling a method show()). It is separate object (except it is a part of appWindow). The question is why does the process can not start only after my programm did some work? And why QProcess::start even dont have timeout.
UPD: I moved proc->start(app,args); to the child process, which i getting by using fork() and now my programm hangs on pid_t child = fork(). So the problem is that new process can not be created.
The answer is to do not use fork() because it is dangerous in big projects. More at http://www.evanjones.ca/fork-is-dangerous.html . posix_spawn also hangs my project. Now i decided to fork() new process at the beginning and send commands to it through the pipe.

WAS Liberty Profile won't run external process (using Runtime.getRuntime().exec(cmd) )

As the title suggests, WLP won't run the process- it won't return anything to the process input stream nor to error stream.
If anyone knows about a configuration that needs to take place I would love to know..
(note the process Can run by running the command manually - in addition, the whole thing runs smooth on tomcat8 so..)
EDIT 1:
The problem was not the command execution under WLP as you guys stated, so I accepted the answer.
The problem is different : I sent a media file to a multipart servlet and stored it in a file on disk using the following code:
InputStream is = request.getInputStream();
String currentTime = new Long(System.currentTimeMillis()).toString();
String fileName = PATH + currentTime + "." + fileType;
File file = new File(fileName);
// write the image to a temporary location
FileOutputStream os = new FileOutputStream(file);
byte[] buffer = new byte[BUFFER_SIZE];
while(true) {
int numRead = is.read(buffer);
if(numRead == -1) {
break;
}
os.write(buffer, 0, numRead);
os.flush();
}
is.close();
os.close();
and the file gets saved along with the following prefix:
While this does not happen on tomcat8 (using the same client)..
something is not trivial in the received input stream. (Note its a multipart servlet that set up via #MultipartConfig only)
Hope this post will help others..
guys,thanks for your help!
This will work in Liberty. I was able to test out the following code in a servlet and it printed the path of my current directory just fine:
String line;
Process p = Runtime.getRuntime().exec("cmd /c cd");
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null) {
System.out.println(line);
}
input.close();
Start with a simple command like this, and when you move up to more complex commands or scripts, make sure you are not burying exceptions that may come back. Always at least print the stack trace!

Using Background Worker and process.start not able to retrieve progress status

Good evening,
I just started playing around with C# and I tried creating a GUI for a program that runs in command line. I have been able to get it running, but now I am stuck trying to implement a progress bar to it.
I have read other post but I am unable to find the exact issue or to understand how to apply the solution to my issue.
Here is my code (apologize if this is very messy):
private void MethodToProcess(Object sender, DoWorkEventArgs args)
{
// Set all the strings for passthrough
String USMTPath_Work = USMTPath + USMTArch;
String USMTPath_full = USMTPath_Work + #"\Scanstate.exe";
String USMTFlags_Capture = #"/c /v:13 /o /l:scanstate.log /localonly /efs:copyraw";
String Argument_full = SavePath + XML1 + XML2 + USMTFlags_Capture;
// Test that USMT path is correct
if (USMTPath == null)
{
MessageBox.Show("Error: There is no USMT Path defined.");
return;
}
// Test that Windows folder is correct when offline
/* if (Windows_Path == null)
{
MessageBox.Show("Error: There is no Windows Path to capture.");
return;
} */
// Runs the capture
System.Diagnostics.Process Scanstate = new System.Diagnostics.Process();
Scanstate.StartInfo.FileName = USMTPath_full;
Scanstate.StartInfo.Arguments = Argument_full;
Scanstate.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
Scanstate.StartInfo.WorkingDirectory = USMTPath_Work;
//Scanstate.StartInfo.UseShellExecute = false;
Scanstate.StartInfo.CreateNoWindow = true;
//Scanstate.StartInfo.RedirectStandardOutput = true;
Scanstate.Start();
Scanstate.WaitForExit();
String Str_ExitCode = Scanstate.ExitCode.ToString();
if (Scanstate.ExitCode == 1)
MessageBox.Show("Error: Data has not been captured. Please check the log files for details.");
if (Scanstate.ExitCode == 0)
MessageBox.Show("Success: Data has been captured. For more information, check log files.");
else
{
MessageBox.Show("Error: Unknown error has occurred. Please check the log files for details.");
MessageBox.Show("Error Code: " + Str_ExitCode);
}
Scanstate.Close();
}
Basically, I am trying to run the process scanstate.exe. Now, I am trying to run backgroundworker in order to be able to retrieve progress and pass it to the progressbar.
private void btnCapture_Click(object sender, EventArgs e)
{
progressBar1.Minimum = 0;
progressBar1.Maximum = 100;
progressBar1.Step = 1;
BackgroundWorker CaptureBG = new BackgroundWorker();
CaptureBG.WorkerReportsProgress = true;
CaptureBG.DoWork += new DoWorkEventHandler(MethodToProcess);
CaptureBG.RunWorkerCompleted +=new RunWorkerCompletedEventHandler(CaptureBG_RunWorkerCompleted);
CaptureBG.ProgressChanged += new ProgressChangedEventHandler(CaptureBG_ProgressChanged);
CaptureBG.RunWorkerAsync();
}
and
private void CaptureBG_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs args)
{
progressBar1.Value = 100;
}
private void CaptureBG_ProgressChanged(object sender, ProgressChangedEventArgs args)
{
progressBar1.Value++;
}
However I am either missunderstanding the use or I am missing something, since the process runs, but I don't get any progress on the progressbar. It only fills once the process finish.
What am I doing wrong? In general, how would a process report progress if I don't know exactly how long is going to take?
Thanks in advance
The BackgroundWorker is responsible for updating the progress as it gets further complete with its task.
There is no interaction between your process that you launch and your code that would provide progress of that process back to your code.
In order for this to work, two things have to happen:
You need to define a mechanism for your process to report progress to the BackgroundWorker.
The BackgroundWorker must update its own progress by calling the ReportProgress method so that the ProgressChanged event is fired.
The first step is the tricky one and depends on how scanstate.exe works. Does it do anything to give an indication of progress, such as write to the console? If so, you can redirect the console output and parse that output to determine or at least estimate progress.
UPDATE
Scanstate.exe provides the ability to write progress to a log, e.g.:
scanstate /i:migapp.xml /i:miguser.xml \\fileserver\migration\mystore /progress:prog.log /l:scanlog.log
You could use a FileWatcher in your BackgroundWorker to look for changes to the progress log and update progress accordingly.

Direct Show 9 phonon Error "Pins cannot connect"

I'm getting the following error when trying to use the Direct Show 9 backend with qt's phonon framework:
Pins cannot connect due to not supporting the same transport. (0x80040266)
Does anyone know what this error means and/or how to fix it? Is this a problem with the Direct Show 9 backend for phonon?
Apparently the problem has to do with bad metadata. If the Id3 tags aren't just right, the direct show 9 backend chokes on them. I solved the problem by writing the following function:
void removeTags(UDJ::DataStore::song_info_t& song){
static int fileCount =0;
if(song.source.fileName().endsWith(".mp3")){
UDJ::Logger::instance()->log("On windows and got mp3, copying and striping metadata tags");
QString tempCopy = QDesktopServices::storageLocation(QDesktopServices::TempLocation) + "/striped" + QString::number(fileCount) +".mp3";
if(QFile::exists(tempCopy)){
UDJ::Logger::instance()->log("Prevoius file existed, deleting now");
if(QFile::remove(tempCopy)){
UDJ::Logger::instance()->log("File removal worked");
}
}
bool fileCopyWorked = QFile::copy(song.source.fileName(), tempCopy);
if(!fileCopyWorked){
UDJ::Logger::instance()->log("File copy didn't work");
return;
}
TagLib::MPEG::File file(tempCopy.toStdString().c_str());
file.strip();
file.save();
Phonon::MediaSource newSource(tempCopy);
song.source = newSource;
if(fileCount == 3){
fileCount =0;
}
else{
fileCount++;
}
}
}
song_info_t is just a struct with a Phonon::MediaSource member in it called source. The function works by using taglib to strip off all of the metadata for a song and save the new song as a temporary file. The function also rotates the filename is uses for the temporary file so that it doesn't create an infinite number of temporary copy files. I hope this helps anyone else who is having this error.

Resources