Program description
Wikilink is an extension for the Thingamablog
1.0.6 blogging software.
Since you don't know the URL
a blog entry will have after being uploaded, it's quite complicated to
interlink your blog entries. The FaVorithSoft Wikilink Extension
integrates well in the Thingamablog GUI and enables you to create cross
connections as easy as a normal hyperlink.
Update
10/5/2007:
Due to an advice
of a Wikilink user (German-speaking forum), the extension now
creates relative paths, hence the links still work after the blog has
moved to another location. Furthermore I have included another small
feature, see Extending
Thingamablog 1.0.6: Improving the Insert Special Character feature for
details.
How to get it running
Installing the extension is simple: Just download the program data (I
recommend the executable package, but if you wary about downloading an
inofficially compiled program version, you can also download the source
code package and compile it yourself), extract it and replace your old
thingamablog-1.0.6 folder with the new one you just extracted. Now you
can work as usual with Thingamablog and furthermore you have the ability
to create Wikilinks (also see the How to use section below).
To
ensure that you are working with the improved Thingamablog version, take
a look at the program title bar- there you should see something like
this:
Thingamablog 1.0.6 - WikiMod+ISCIM-Version by Fabian Voith (www.FaVorithSoft.de)
How to use
Screenshots
The extended toolbar (The Wikilink button is right to the Hyperlink
button)
The
extended Insert menu
The
new dialog for the Wikilink feature
How to develop it in 10 steps
As I have mentioned in several former entries, I use the blogging
software Thingamablog
to update the FaVorithSoft website. Intrinsically it's a nice piece of
software, however the community breathed some wishes what it would like
to be able to do with the application and what was not implemented, yet.
Due to the fact that the developer decided to make Thingamablog open
source, everybody can extend it.
Therefore, when I read
something about the wish (German) to be able to make cross
connections between various blog entries, I began to implement such a
feature for Thingamablog 1.0.6.
The result is Wikilink:
Since
I have already written a bug fix for the tool (see Huu
- buggy Thingamablog 1.0.6... + FIX!), I was familiar with the
source code and its complexity and so I could estimate my chance of
success.
I'll point out my proceeding now, but please note:
Thingamablog is an application with an extent that should not be
underestimated! There are hundreds of files, thousands of methods and
uncountable lines of code. Especially for a programmer like me, who has
not developed the source code from scratch and who has to think his way
into the program logic, it's really challenging to get new source code
up and running without influencing existing functionality. For
that reason I have coded very straight forward and without caring about
code re-using and proper OOP. What I'm trying to say is that you should
not follow my example if you want to create a new project- in other
words: the following source code has no exemplary function at all.
// Edit by Fabian Voith:
// New constructor is needed to get information about currently used database:
public EntryEditor(BlogEntry e, Weblog blog, WeblogList list, int entryMode, File curDB)
throws BackendException
{
// calling normal constructor
this(e, blog, list, entryMode);
// make curDB accessible for wiki feature
this.curDB = curDB;
}
// edit by Fabian Voith - some wikilink variables need class wide scope private JButton wikilinkbutton; private File curDB; private Weblog weblog; // this variable is declared later in the original source, // only delcared here for better overview private Frame wikiframe = this;
// Edit by Fabian Voith // old: EntryEditor ed = new EntryEditor(be, blog, weblogList, editMode); // new call offers information for current Database EntryEditor ed = new EntryEditor(be, blog, weblogList, editMode, curDB);
// edit by Fabian Voith:
// adding menu entry
JMenuItem wikim = new JMenuItem(Messages.getString("EntryEditor.Wikilink"), Utils.createIcon(RES + "wiki.png")); //$NON-NLS-1$
//Messages.setMnemonic("EntryEditor.Wikilink", wikim); //$NON-NLS-1$
wikim.addActionListener(new wikihandlerclass());
insertMenu.add(wikim);
//
// edit by Fabian Voith:
// adding toolbar button
wikilinkbutton = new JButton();
wikilinkbutton.setIcon(Utils.createIcon(RES + "wiki.png"));
wikihandlerclass wikihandler = new wikihandlerclass();
wikilinkbutton.addActionListener(wikihandler);
toolbar.add(wikilinkbutton);
configToolbarButton(wikilinkbutton);
wikilinkbutton.setToolTipText(Messages.getString("HTMLEditorActionSet.Wikilink"));
// edit by Fabian Voith- new action listener class with main code for wiki feature
// The Events for this feature cannot be handled in the same manner as the common link feature etc,
// because the original handling is unable to deal with content which is generated after the creation
// of the EntryEditor (e.g. the weblog variable, which I need to read the available entries).
private class wikihandlerclass implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
ArrayList titles = new ArrayList();
ArrayList urls = new ArrayList();
try {
//use current weblog
BlogEntry[] bles = weblog.getEntries();
net.sf.thingamablog.blog.TBWeblog tb = new net.sf.thingamablog.blog.TBWeblog(curDB);
// initiating tb with proper data would be nice, but the following line sometimes doesn't work:
// tb = (net.sf.thingamablog.blog.TBWeblog)weblogList.getWeblogAt(weblogCombo.getSelectedIndex());
// Prepare ArchiveUrl (as relative path, so Wikilinks also work if the blog is moved to another location)
String baseurl = weblog.getArchiveUrl();
StringTokenizer st = new StringTokenizer(baseurl, "/");
int c=-1;
// using StringBuffer to prevent slow String AutoBoxing
StringBuffer sb = new StringBuffer();
while (st.hasMoreTokens()) {
c++;
// don't use the first two tokens (http and baseUrl)
if (c<2) {
st.nextToken();
continue;
}
//baseurl+='/'+st.nextToken();
sb.append('/');
sb.append(st.nextToken());
}
sb.append('/');
//baseurl+='/';
baseurl=sb.toString();
// No for-each-loop in "javac -source 1.4" which is our compilation mode (see build.xml)
for (int i = 0; i < bles.length; i++) {
// the ArrayLists are being converted to String Arrays later (see below).
titles.add(bles[i].getTitle());
// tb.getUrlForEntry doesn't return the complete URL (including the ArchiveUrl),
// because tb.setBlogUrls was not called and the initiation doesn' work properly
// (see bug description above). So we have to add the ArchiveUrl manually.
//urls.add(weblog.getArchiveUrl()+tb.getUrlForEntry(bles[i]));
urls.add(baseurl+tb.getUrlForEntry(bles[i]));
}
} catch (net.sf.thingamablog.blog.BackendException exc) {
System.out.println("Error in FaVorithSoft-Wikilink-Feature: ");
exc.printStackTrace();
}
if(tabs.getSelectedIndex() == SOURCE)
{
// source edit performed
WikiLinkDialog dlg = new WikiLinkDialog(wikiframe, (String[])titles.toArray(new String[titles.size()]), (String[])urls.toArray(new String[urls.size()]));
dlg.setLocationRelativeTo(wikiframe);
dlg.setLinkDescription(srcEditor.getSelectedText());
dlg.setVisible(true);
if(dlg.hasUserCancelled())
{
return;
}
srcEditor.requestFocusInWindow();
srcEditor.replaceSelection(dlg.getHTML());
} else {
// wysiwyg action performed
WikiLinkDialog dlg = new WikiLinkDialog(wikiframe, (String[])titles.toArray(new String[titles.size()]), (String[])urls.toArray(new String[urls.size()]));
if(editor.getSelectedText() != null)
{
dlg.setLinkDescription(editor.getSelectedText());
}
dlg.setLocationRelativeTo(wikiframe);
dlg.setVisible(true);
if(dlg.hasUserCancelled())
{
return;
}
HTMLDocument document = (HTMLDocument)editor.getDocument();
HTMLEditorKit editorKit = (HTMLEditorKit)editor.getEditorKit();
String tagText = dlg.getHTML();
if(editor.getSelectedText() == null)
{
tagText += " ";
}
editor.replaceSelection("");
HTMLUtils.insertInlineHTML(tagText, HTML.Tag.A, editor);
}
}
}
/* * WikiLinkDialog.java *
* Created on October 2, 2007, 5:34 PM by Fabian Voith *
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package net.sf.thingamablog.gui.editor;
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.JTextField;
import net.sf.thingamablog.TBGlobals;
import net.sf.thingamablog.Utils;
import net.sf.thingamablog.blog.BlogEntry;
import net.sf.thingamablog.blog.Weblog;
import net.sf.thingamablog.gui.LabelledItemPanel;
import net.sf.thingamablog.gui.Messages;
public class WikiLinkDialog extends HTMLOptionDialog
{
private static final String RES = TBGlobals.RESOURCES;
private JComboBox targetCombo;
private JTextField txtDesc = new JTextField(25);
private String[] urls;
public WikiLinkDialog(Frame parent, String[] titles, String[] urls)
{
super(parent, Messages.getString("EntryEditor.Wikilink"), Utils.createIcon(RES + "wikibig.png"));
// make information accessible for whole class
this.urls = urls;
LabelledItemPanel lip = new LabelledItemPanel();
JPanel main = new JPanel(new BorderLayout());
targetCombo = new JComboBox(titles);
lip.addItem(Messages.getString("WikiDialog.Entry"), targetCombo);
lip.addItem(Messages.getString("WikiDialog.Text"), txtDesc);
targetCombo.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
updateNameBox();
}
});
updateNameBox();
main.add(lip, BorderLayout.CENTER);
setContentPanel(main);
pack();
setResizable(false);
}
private void updateNameBox()
{
boolean isdiff = true;
if (!txtDesc.getText().equals("")) // only check if textbox not empty
{
for (int i = 0; i < targetCombo.getItemCount(); i++) {
if (targetCombo.getItemAt(i).equals(txtDesc.getText()))
{
isdiff = false;
break;
}
}
} else {
isdiff = false;
}
if (!isdiff) // only update if no user-defined text in txtDesc
{
// update contents
txtDesc.setText((String)targetCombo.getSelectedItem());
}
}
public void setLinkDescription(String s)
{
txtDesc.setText(s);
}
public String getHTML()
{
// create html data
String aTag = "<a href=\""+urls[targetCombo.getSelectedIndex()]+"\">"+txtDesc.getText()+"</a>";
return aTag;
}
}
// edit by Fabian Voith // mark as modified TAMB version: f.setTitle(TBGlobals.APP_NAME + ' ' + TBGlobals.VERSION + " - WikiMod-Version by Fabian Voith (www.FaVorithSoft.de)");
# Edit by Fabian Voith HTMLEditorActionSet.Wikilink=Wikilink... EntryEditor.Wikilink=Wikilink... WikiDialog.Entry=Entry WikiDialog.Text=Text #Additionally you have to extract the files from /lib/lang.zip, located within the internal folder structure, and edit them, too. Insert the following texts in the mentioned files:
# Edit by Fabian Voith HTMLEditorActionSet.Wikilink=Wikilink... EntryEditor.Wikilink=Wikilink... WikiDialog.Entry=Eintrag WikiDialog.Text=Text #
# Edit by Fabian Voith HTMLEditorActionSet.Wikilink=Wikilink... EntryEditor.Wikilink=Wikilink... WikiDialog.Entry=Entry WikiDialog.Text=Text #
# Edit by Fabian Voith HTMLEditorActionSet.Wikilink=Wikilink... EntryEditor.Wikilink=Wikilink... WikiDialog.Entry=Entrada WikiDialog.Text=Texto #
# Edit by Fabian Voith HTMLEditorActionSet.Wikilink=Lien Wiki... EntryEditor.Wikilink=Lien Wiki... WikiDialog.Entry=Entrée WikiDialog.Text=Texte #