I am developing Java desktop based application using Swing framework and JasperReports for reporting. I have some problems, when JasperViewer comes up and I want to save the report.
How can I set the name of the file (default is blank) in the save dialog and how to limit only Pdf format?
Here is my code:
JRBeanCollectionDataSource beanCollection=new JRBeanCollectionDataSource(matakuliahs);
Map<String,Object> map=new HashMap<String, Object>();
map.put("namaMahasiswa", mahasiswa.getNama());
InputStream input=getClass().getResourceAsStream("/reportsederhana/reportsederhana.jrxml");
JasperDesign design=JRXmlLoader.load(input);
JasperReport report=JasperCompileManager.compileReport(design);
JasperPrint jasperPrint=JasperFillManager.fillReport(report, map, beanCollection);
jasperPrint.setName("Laporan "+mahasiswa.getNama()); // it doesn't give the name
JasperViewer.viewReport(jasperPrint,false);
For setting the default extension(s) to save to, one idea is that you need to somehow get the JRViewer instance from a JasperViewer (instance) and then, on the void JRViewer instance, you can set some save contributions. Have a look at JRViewer.setSaveContributors(JRSaveContributor[] saveContribs).
For setting the file name, i am not entirely sure, but have a look at JRViewer.JRViewer(String, boolean).
Also check the JRViewer and the JasperViewer source code, it may come in handy.
It is an old post but I ran into the same problem...
I extended my viewer component from net.sf.jasperreports.view.JRViewer. After some code review I saw that it is only possible to control the 'lastFolder' but not the filename from outside. So you can set the last used folder if it is not set already by:
if (lastFolder == null) {
this.lastFolder = new File(System.getProperty("user.home"));
}
But, and thats the hint: All buttons of toolbar are public fields!
So for my solution I removed all ActionListeners of the save button (btnSave):
for (ActionListener actionListener : this.btnSave.getActionListeners()) {
this.btnSave.removeActionListener(actionListener);
}
And then added my own implementation. It is pretty like the original one only with the difference that I control the file name depending to the report name and current timestamp.
...
File file = new File(lastFolder.getPath() + System.getProperty("file.separator") + DateTime.now().toString() + "_" + jasperPrint.getName());
...
Additionally I set the pre-selected file extension from .jasperprint to .pdf which is more convenient.
...
fileChooser.setFileFilter((FileFilter) saveContributors.get(1));
...
The full ActionListener code is as follows:
this.btnSave.addActionListener(new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setLocale(getLocale());
fileChooser.updateUI();
File file = new File(lastFolder.getPath() + System.getProperty("file.separator") + DateTime.now().toString() + "_" + jasperPrint.getName());
fileChooser.setSelectedFile(file);
for (int i = 0; i < saveContributors.size(); i++)
fileChooser.addChoosableFileFilter((FileFilter) saveContributors.get(i));
if (saveContributors.contains(lastSaveContributor))
fileChooser.setFileFilter(lastSaveContributor);
else if (saveContributors.size() > 1)
fileChooser.setFileFilter((FileFilter) saveContributors.get(1));
if (lastFolder != null)
fileChooser.setCurrentDirectory(lastFolder);
int retValue = fileChooser.showSaveDialog(JasperViewer.this);
if (retValue == 0) {
FileFilter fileFilter = fileChooser.getFileFilter();
file = fileChooser.getSelectedFile();
lastFolder = file.getParentFile();
JRSaveContributor contributor = null;
if (fileFilter instanceof JRSaveContributor) {
contributor = (JRSaveContributor) fileFilter;
} else {
int i = 0;
do {
if (contributor != null || i >= saveContributors.size())
break;
contributor = (JRSaveContributor) saveContributors.get(i++);
if (!contributor.accept(file))
contributor = null;
} while (true);
if (contributor == null)
contributor = new JRPrintSaveContributor(jasperReportsContext, getLocale(), null);
}
lastSaveContributor = contributor;
try {
contributor.save(jasperPrint, file);
} catch (JRException ex) {
logger.error("Could not save report.", ex);
JOptionPane.showMessageDialog(JasperViewer.this, trc("JasperViewer.error.save", "Could not save report."));
}
}
}
});
Related
I am writing my own Netbeans plugin to edit opened files. I have managed to get some information about currently active file using
TopComponent activeTC = TopComponent.getRegistry().getActivated();
FileObject fo = activeTC.getLookup().lookup(FileObject.class);
io.getOut().println(fo.getNameExt());
io.getOut().println(fo.canWrite());
io.getOut().println(fo.asText());
But I have no idea how to modify this file. Can someone help me with this?
And second question, how to get text selection ranges? I want to run my command only on selected text.
For modifying the file you could use the NetBeans org.openide.filesystems.FileUtil.toFile() and then the regular Java stuff to read and write files and for getting the selected text of the current editor window you would have to do something like:
Node[] arr = activeTC.getActivatedNodes();
for (int j = 0; j < arr.length; j++) {
EditorCookie ec = (EditorCookie) arr[j].getCookie(EditorCookie.class);
if (ec != null) {
JEditorPane[] panes = ec.getOpenedPanes();
if (panes != null) {
// USE panes
}
}
}
For more code examples see also here
After several hours of research I found out that:
The code I posted in Question can be used to obtain basic information about active file.
To get caret position or get selection range you can do:
JTextComponent editor = EditorRegistry.lastFocusedComponent();
io.getOut().println("Caret pos: "+ editor.getCaretPosition());
io.getOut().println("Selection start: "+ editor.getSelectionStart());
io.getOut().println("Selection end: "+ editor.getSelectionEnd());
To modify content of active file (in a way that the modification can be undo by Ctrl+z) you may use this code:
final StyledDocument doc = context.openDocument();
NbDocument.runAtomicAsUser(doc, new Runnable() {
public void run() {
try {
doc.insertString(ofset, "New text.", SimpleAttributeSet.EMPTY);
} catch (Exception e) {
}
}
});
I am in the middle of creating an app that allows users to apply for job positions and upload their CVs. I`m currently stuck on trying to make a search box for the admin to be able to search for Keywords. The app will than look through all the CVs and if it finds such keywords it will show up a list of Cvs that contain the keyword. I am fairly new to Gui design and app creation so not sure how to go about doing it. I wish to have it done via java and am using the Eclipse Window builder to help me design it. Any help will be greatly appreciated, hints, advice anything. Thank You.
Well, this not right design approach as real time search of words in all files of given folder will be slow and not sustainable in long run. Ideally you should have indexed all CV's for keywords. The search should run on index and then get the associated CV for that index ( think of indexes similar to tags). There are many options for indexing - simples DB indexing or using Apache Lucene or follow these steps to create a index using Maps and refer this index for search.
Create a map Map<String, List<File>> for keeping the association of
keywords to files
iterate through all files, and for each word in
each file, add that file to the list corresponding to that word in
your index map
here is the java code which will work for you but I would still suggest to change your design approach and use indexes.
File dir = new File("Folder for CV's");
if(dir.exists())
{
Pattern p = Pattern.compile("Java");
ArrayList<String> list = new ArrayList<String>(); // list of CV's
for(File f : dir.listFiles())
{
if(!f.isFile()) continue;
try
{
FileInputStream fis = new FileInputStream(f);
byte[] data = new byte[fis.available()];
fis.read(data);
String text = new String(data);
Matcher m = p.matcher(text);
if(m.find())
{
list.add(f.getName()); // add file to found-keyword list.
}
fis.close();
}
catch(Exception e)
{
System.out.print("\n\t Error processing file : "+f.getName());
}
}
System.out.print("\n\t List : "+list); // list of files containing keyword.
} // IF directory exists then only process.
else
{
System.out.print("\n Directory doesn't exist.");
}
Here you get the files list to show now for "Java". As I said use indexes :)
Thanks for taking your time to look into my problem.
I have actually come up with a solution of my own. It is probably very amateur like but it works for me.
JButton btnSearch = new JButton("Search");
btnSearch.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
list.clear();
String s = SearchBox.getText();
int i = 0,present = 0;
int id;
try
{
Class.forName(driver).newInstance();
Connection conn = DriverManager.getConnection(url+dbName,userName,password);
Statement st = conn.createStatement();
ResultSet res = st.executeQuery("SELECT * FROM javaapp.test");
while(res.next())
{
i = 0;
present = 0;
while(i < 9)
{
String out = res.getString(search[i]);
if(out.toLowerCase().contains(s.toLowerCase()))
{
present = 1;
break;
}
i++;
}
if(tglbtnNormalshortlist.isSelected())
{
if(present == 1 && res.getInt("Shortlist") == 1)
{
id = res.getInt("Candidate");
String print = res.getString("Name");
list.addElement(print+" "+id);
}
}
else
{
if(present == 1 && res.getInt("Shortlist") == 0)
{
id = res.getInt("Candidate");
String print = res.getString("Name");
list.addElement(print+" "+id);
}
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
});
I've got a JTable that is filled by Vectors. These Vectors get their content by a loop, listing all files in a specific folder. Now I want to edit a Cell (via the GUI) that contains a filename and the real File on the HD should be renamed too. So how do I archive this?
Here's my code for the method that fills the JTable.
private void reloadFiles(){
vecVectors.clear();
if (Variables.pathToFiles != null) {
Variables.listOfFiles.clear();
Variables.listOfFiles = listFilesForFolder(Variables.pathToFiles);
for (File file : Variables.listOfFiles) {
Vector<String> temp = new Vector<String>();
temp.add(file.getName());
vecVectors.add(temp);
}
table.removeAll();
table = new JTable(vecVectors, vecHeaders);
this.remove(listScroller);
listScroller.removeAll();
listScroller = new JScrollPane(table);
listScroller.setPreferredSize(new Dimension(950, 450));
this.add(listScroller);
System.out.println("Reloaded");
}
}
Instead of using vectors to fill your table, you can use a more sophisticated table model implementation that allows you to work directly with File objects as rows in your table. I'm talking about either DataObjectTableModel or Rob Camick's RowTableModel.
So, let's say you have the table model implementation solved and each row in your table is a File object. Now, I wouldn't make any cell editable and let the table just display files info, considering:
There are many factors that can go wrong (i.e: invalid or existent file name)
It's not a TableModel responsibility to reflect the update in the HD.
It can be done using TableModelListener but the events are fired once the model has changed, so if you have troubles updating the file name in the HD then you have to revert the table model's changes. Not so easy though.
In order to re-name a file, I'd attach a MouseListener to the table and show a pop up dialog to let the user input the new file name. Finally use the File API to rename the file and update the table model reflecting these changes.
Snippet
final DataObjectTableModel<File> model = new DataObjectTableModel<File>(header) {
// Override getValueAt() and getColumnClass() here
};
final JTable table = new JTable(model);
table.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() >= 2 && !e.isPopupTrigger()) {
int selectedRow = table.rowAtPoint(e.getPoint());
if (selectedRow != -1) {
String newName = JOptionPane.showInputDialog (
null
, "Please input the new name"
, "Rename file"
, JOptionPane.INFORMATION_MESSAGE
);
if (newName != null) {
int modelIndex = table.convertRowIndexToModel(selectedRow);
File file = model.getDataObject(modelIndex);
// Maybe this part should be done
// using a SwingWorker to avoid blocking the EDT
String newPath = file.getParent() + File.separator + newName;
File newFile = new File(newPath);
if (file.renameTo(newFile)) {
model.deleteDataObject(modelIndex); // remove the old file
model.insertDataObject(newFile, modelIndex); // insert the new file in the same index
} else {
JOptionPane.showMessageDialog (
null
, "An error happened trying to rename file " + file.getName()
, "Error!"
, JOptionPane.WARNING_MESSAGE
);
}
}
} // if (selectedRow != -1)
} // if (e.getClickCount() >= 2 && !e.isPopupTrigger())
}
});
I have a problem that needs solving where we use OpenOffice 1.1.4 templated reports and programmatically export them to PDF.
The team who create the templates have recently changed the header image and some images in a table to background images (before they were just inserted) since this change the current program is not creating the PDFs with the images. We can export from OpenOffice manually and the images are included. Can anyone help with a change I may need to make to get these background images included please?
The current code:
private void print(XInterface xComponent,
PrintRequestDTO printReq, File sourceFile,
Vector<String> pages) throws java.lang.Exception {
String pageRange;
// XXX create the PDF via OOo export facility
com.sun.star.frame.XStorable pdfCreator = (com.sun.star.frame.XStorable) UnoRuntime
.queryInterface(
com.sun.star.frame.XStorable.class,
xComponent);
PropertyValue[] outputOpts = new PropertyValue[2];
outputOpts[0] = new PropertyValue();
outputOpts[0].Name = "CompressionMode";
outputOpts[0].Value = "1"; // XXX Change this perhaps?
outputOpts[1] = new PropertyValue();
outputOpts[1].Name = "PageRange";
if (printReq.getPageRange() == null) {
pageRange = "1-";
}
else {
if (printReq.getPageRange().length() > 0) {
pageRange = printReq.getPageRange();
}
else {
pageRange = "1-";
}
}
log.debug("Print Instruction - page range = "
+ pageRange);
PropertyValue[] filterOpts = new PropertyValue[3];
filterOpts[0] = new PropertyValue();
filterOpts[0].Name = "FilterName";
filterOpts[0].Value = "writer_pdf_Export"; // MS Word 97
filterOpts[1] = new PropertyValue();
filterOpts[1].Name = "Overwrite";
filterOpts[1].Value = new Boolean(true);
filterOpts[2] = new PropertyValue();
filterOpts[2].Name = "FilterData";
filterOpts[2].Value = outputOpts;
if (pages.size() == 0) { // ie no forced page breaks
// set page range
outputOpts[1].Value = pageRange;
filterOpts[2] = new PropertyValue();
filterOpts[2].Name = "FilterData";
filterOpts[2].Value = outputOpts;
File outputFile = new File(
sourceFile.getParent(),
printReq.getOutputFileName()
+ ".pdf");
StringBuffer sPDFUrl = new StringBuffer(
"file:///");
sPDFUrl.append(outputFile.getCanonicalPath()
.replace('\\', '/'));
log.debug("PDF file = " + sPDFUrl.toString());
if (pdfCreator != null) {
sleep();
pdfCreator.storeToURL(sPDFUrl.toString(),
filterOpts);
}
}
else if (pages.size() > 1) {
throw new PrintDocumentException(
"Only one forced split catered for currently");
}
else { // a forced split exists.
log.debug("Page break found in "
+ (String) pages.firstElement());
String[] newPageRanges = calculatePageRanges(
(String) pages.firstElement(), pageRange);
int rangeCount = newPageRanges.length;
for (int i = 0; i < rangeCount; i++) {
outputOpts[1].Value = newPageRanges[i];
log.debug("page range = " + newPageRanges[i]);
filterOpts[2] = new PropertyValue();
filterOpts[2].Name = "FilterData";
filterOpts[2].Value = outputOpts;
String fileExtension = (i == 0 && rangeCount > 1) ? "__Summary.pdf"
: ".pdf";
File outputFile = new File(
sourceFile.getParent(),
printReq.getOutputFileName()
+ fileExtension);
StringBuffer sPDFUrl = new StringBuffer(
"file:///");
sPDFUrl.append(outputFile.getCanonicalPath()
.replace('\\', '/'));
log.debug("PDF file = " + sPDFUrl.toString());
if (pdfCreator != null) {
log.debug("about to create the PDF file");
sleep();
pdfCreator.storeToURL(
sPDFUrl.toString(), filterOpts);
log.debug("done");
}
}
}
}
Thanks in advance.
Glad that suggestion of making the document visible helped. Since it has ALSO fixed the problem you have a timing/threading issue. I suspect you'll find that another dodgy option of doing a sleep before executing the save to PDF will also allow the images to appear. Neither of these solutions is good.
Most likley best fix is to upgrade to a newer version of Open Office (the API calls you have should still work). Another option would be to try to call the API to ask the document to refresh itself.
After finding the correct property I was able to open the file with the hidden property set to false, this meant when the file was exported to PDF it included the background images. Its a shame I could not find another solultion that kept the file hidden but at least its working.
I try to Save an Excel file. The Excel file is a template with makros (*.xltm). I can open the file and edit the content, but if i try to save the destination Excel file is corrupt.
I try to save the file with:
int id = _workbook.getIDsOfNames(new String[] {"Save"})[0];
_workbook.invoke(id);
or/and
_xlsClientSite.save(_file, true);
You might try specifying a file format in your Save call.
If you're lucky, you can find the file format code you need in the Excel help. If you can't find what you need there, you'll have to get your hands dirty using the OLEVIEW.EXE program. There's likely a copy of it sitting on your hard drive somewhere, but if not, it's easy enough to find a copy with a quick Google search.
To use OLEVIEW.EXE:
Run it
Crack open the 'Type Libraries' entry
Find the version of Excel that you're using
Open that item
Search the enormous pile of text that's displayed for the string 'XlFileFormat'
Examine the XLFileFormat enum for a code that seems promising
If you are using Office2007 ("Excel12") like I am, you might try one of these values:
xlOpenXMLWorkbookMacroEnabled = 52
xlOpenXMLTemplateMacroEnabled = 53
Here's a method that I use to save Excel files using OLE:
/**
* Save the given workbook in the specified format.
*
* #param controlSiteAuto the OLE control site to use
* #param filepath the file to save to
* #param formatCode XlFileFormat code representing the file format to save as
* #param replaceExistingWithoutPrompt true to replace an existing file quietly, false to ask the user first
*/
public void saveWorkbook(OleAutomation controlSiteAuto, String filepath, Integer formatCode, boolean replaceExistingWithoutPrompt) {
Variant[] args = null;
Variant result = null;
try {
// suppress "replace existing?" prompt, if necessary
if (replaceExistingWithoutPrompt) {
setPropertyOnObject(controlSiteAuto, "Application", "DisplayAlerts", "False");
}
// if the given formatCode is null, for some reason, use a reasonable default
if (formatCode == null) {
formatCode = 51; // xlWorkbookDefault=51
}
// save the workbook
int[] id = controlSiteAuto.getIDsOfNames(new String[] {"SaveAs", "FileName", "FileFormat"});
args = new Variant[2];
args[0] = new Variant(filepath);
args[1] = new Variant(formatCode);
result = controlSiteAuto.invoke(id[0], args);
if (result == null || !result.getBoolean()) {
throw new RuntimeException("Unable to save active workbook");
}
// enable alerts again, if necessary
if (replaceExistingWithoutPrompt) {
setPropertyOnObject(controlSiteAuto, "Application", "DisplayAlerts", "True");
}
} finally {
cleanup(args);
cleanup(result);
}
}
protected void cleanup(Variant[] variants) {
if (variants != null) {
for (int i = 0; i < variants.length; i++) {
if (variants[i] != null) {
variants[i].dispose();
}
}
}
}