Home » Eclipse Projects » Rich Client Platform (RCP) » Persisting MRU in RCP
| |
Re: Persisting MRU in RCP [message #450676 is a reply to message #450625] |
Wed, 07 June 2006 10:53 |
Phill Perryman Messages: 214 Registered: July 2009 |
Senior Member |
|
|
<br><font size=2 face="sans-serif">I found I could not do it as the workbench
MRU uses IDE stuff and it is internal.</font>
<br>
<br><font size=2 face="sans-serif">In the end I had to roll my own, if
it is of any use</font>
<br>
<br><font size=2 face="sans-serif"> /*********************************************************** ******************** </font>
<br><font size=2 face="sans-serif"> * Copyright (c) 2006 Mitel Corporation.</font>
<br><font size=2 face="sans-serif"> * All rights reserved. This program
and the accompanying materials </font>
<br><font size=2 face="sans-serif"> * are copyright Mitel Corporation
and and may not be reproduced, edited, </font>
<br><font size=2 face="sans-serif"> * altered, or otherwise modified,
except with the express permission of the author.</font>
<br><font size=2 face="sans-serif"> * </font>
<br><font size=2 face="sans-serif"> * Contributors:</font>
<br><font size=2 face="sans-serif"> * Phill Perryman
- Initial Implementation</font>
<br><font size=2 face="sans-serif"> ************************************************** *****************************/ </font>
<br><font size=2 face="sans-serif">package com.mitel.swb;</font>
<br>
<br><font size=2 face="sans-serif">import org.eclipse.jface.action.ContributionItem;</font>
<br><font size=2 face="sans-serif">import org.eclipse.jface.preference.IPreferenceStore;</font>
<br><font size=2 face="sans-serif">import org.eclipse.jface.util.IPropertyChangeListener;</font>
<br><font size=2 face="sans-serif">import org.eclipse.jface.util.PropertyChangeEvent;</font>
<br><font size=2 face="sans-serif">import org.eclipse.swt.SWT;</font>
<br><font size=2 face="sans-serif">import org.eclipse.swt.events.SelectionAdapter;</font>
<br><font size=2 face="sans-serif">import org.eclipse.swt.events.SelectionEvent;</font>
<br><font size=2 face="sans-serif">import org.eclipse.swt.widgets.Menu;</font>
<br><font size=2 face="sans-serif">import org.eclipse.swt.widgets.MenuItem;</font>
<br><font size=2 face="sans-serif">import org.eclipse.ui.IWorkbenchPage;</font>
<br><font size=2 face="sans-serif">import org.eclipse.ui.IWorkbenchWindow;</font>
<br><font size=2 face="sans-serif">import org.eclipse.ui.PartInitException;</font>
<br>
<br><font size=2 face="sans-serif">import com.mitel.swb.preferences.PreferenceConstants;</font>
<br><font size=2 face="sans-serif">import com.mitel.swb.util.FileEditorInput;</font>
<br>
<br><font size=2 face="sans-serif">/**</font>
<br><font size=2 face="sans-serif"> * This class maintains the Sales
Workbench MRU list.</font>
<br><font size=2 face="sans-serif"> * </font>
<br><font size=2 face="sans-serif"> * The list is maintained using
the FileEditorInput class. Calls to the open</font>
<br><font size=2 face="sans-serif"> * method will automatically add
the file to the MRU list. If an editor is</font>
<br><font size=2 face="sans-serif"> * opened and subsequently saved
through a saveAs then the add method should</font>
<br><font size=2 face="sans-serif"> * be called to add the new file
name.</font>
<br><font size=2 face="sans-serif"> * </font>
<br><font size=2 face="sans-serif"> * The workbench adds this class
to the file menu as a ContributionItem</font>
<br><font size=2 face="sans-serif"> * so it will be called back as
the menu is populated.</font>
<br><font size=2 face="sans-serif"> * </font>
<br><font size=2 face="sans-serif"> */</font>
<br><font size=2 face="sans-serif">public class MRUContribution extends
ContributionItem implements IPropertyChangeListener {</font>
<br><font size=2 face="sans-serif"> </font>
<br><font size=2 face="sans-serif"> private
final static String ID = "com.mitel.swb.MRUContribution"; //$NON-NLS-1$</font>
<br><font size=2 face="sans-serif"> </font>
<br><font size=2 face="sans-serif"> private
static IWorkbenchWindow window;</font>
<br><font size=2 face="sans-serif"> private
static FileEditorInput[] mruList;</font>
<br><font size=2 face="sans-serif"> private
static MRUContribution contribution;</font>
<br>
<br><font size=2 face="sans-serif"> /*</font>
<br><font size=2 face="sans-serif"> *
Singleton class so a private constructor.</font>
<br><font size=2 face="sans-serif"> */</font>
<br><font size=2 face="sans-serif"> private
MRUContribution(IWorkbenchWindow window, String id) {</font>
<br><font size=2 face="sans-serif">
super(id);</font>
<br><font size=2 face="sans-serif">
MRUContribution.window = window;</font>
<br><font size=2 face="sans-serif">
IPreferenceStore store = App.getDefault().getPreferenceStore();</font>
<br><font size=2 face="sans-serif">
store.addPropertyChangeListener(this);</font>
<br><font size=2 face="sans-serif">
int size = store.getInt(PreferenceConstants.MRU_SIZE);</font>
<br><font size=2 face="sans-serif">
mruList = new FileEditorInput[size];</font>
<br><font size=2 face="sans-serif">
for (int i = 0; i < mruList.length; i++)
{</font>
<br><font size=2 face="sans-serif">
String
pref = store.getString("mru" + i); //$NON-NLS-1$</font>
<br><font size=2 face="sans-serif">
if (!pref.equals(""))
//$NON-NLS-1$</font>
<br><font size=2 face="sans-serif">
mruList[i] = new FileEditorInput(pref.split(","));
//$NON-NLS-1$</font>
<br><font size=2 face="sans-serif">
}</font>
<br><font size=2 face="sans-serif"> }</font>
<br>
<br><font size=2 face="sans-serif"> /**</font>
<br><font size=2 face="sans-serif"> *
This is a singleton class so a factory method will create or return the
single instance.</font>
<br><font size=2 face="sans-serif"> *
@param workbenchWindow main application window</font>
<br><font size=2 face="sans-serif"> */</font>
<br><font size=2 face="sans-serif"> public
static MRUContribution getDefault(IWorkbenchWindow workbenchWindow) {</font>
<br><font size=2 face="sans-serif">
if (contribution == null)</font>
<br><font size=2 face="sans-serif">
contribution
= new MRUContribution(workbenchWindow, ID);</font>
<br><font size=2 face="sans-serif">
return contribution;</font>
<br><font size=2 face="sans-serif"> }</font>
<br>
<br><font size=2 face="sans-serif"> /**</font>
<br><font size=2 face="sans-serif"> *
Opens the editor as defined in the FileEditorInput class. The file name</font>
<br><font size=2 face="sans-serif"> *
is also added to the MRU list if it is not blank.</font>
<br><font size=2 face="sans-serif"> *
</font>
<br><font size=2 face="sans-serif"> *
The list is mantained in a "last opened at the top of the list"
order.</font>
<br><font size=2 face="sans-serif"> *
The method calls add to perform this operation if the editor is successfully
opened.</font>
<br><font size=2 face="sans-serif"> *
</font>
<br><font size=2 face="sans-serif"> *
@param input editor input for the file</font>
<br><font size=2 face="sans-serif"> *
@throws PartInitException</font>
<br><font size=2 face="sans-serif"> */</font>
<br><font size=2 face="sans-serif"> public
static void openEditor(FileEditorInput input) throws PartInitException
{</font>
<br><font size=2 face="sans-serif">
IWorkbenchPage page = window.getActivePage();</font>
<br><font size=2 face="sans-serif">
page.openEditor(input, input.getEditorId());</font>
<br><font size=2 face="sans-serif">
if (!input.getName().equals(""))
//$NON-NLS-1$</font>
<br><font size=2 face="sans-serif">
add(input);</font>
<br><font size=2 face="sans-serif"> }</font>
<br>
<br><font size=2 face="sans-serif"> /**</font>
<br><font size=2 face="sans-serif"> *
Adds the file name to the top of the MRU list. If it already exists in
the</font>
<br><font size=2 face="sans-serif"> *
list it will be removed an the list shuffled down.</font>
<br><font size=2 face="sans-serif"> *
</font>
<br><font size=2 face="sans-serif"> *
@param input editor input for the file</font>
<br><font size=2 face="sans-serif"> */</font>
<br><font size=2 face="sans-serif"> public
static void add(FileEditorInput input) {</font>
<br><font size=2 face="sans-serif">
if (mruList.length < 1)</font>
<br><font size=2 face="sans-serif">
return;</font>
<br><font size=2 face="sans-serif">
</font>
<br><font size=2 face="sans-serif">
// zero is considered the top of the MRU list</font>
<br><font size=2 face="sans-serif">
if (mruList[0] == null) {</font>
<br><font size=2 face="sans-serif">
mruList[0]
= input;</font>
<br><font size=2 face="sans-serif">
return;</font>
<br><font size=2 face="sans-serif">
}</font>
<br>
<br><font size=2 face="sans-serif">
// first see if we have it already at the
top</font>
<br><font size=2 face="sans-serif">
String name = input.getName();</font>
<br><font size=2 face="sans-serif">
if (mruList[0].getName().equals(name))</font>
<br><font size=2 face="sans-serif">
return;</font>
<br>
<br><font size=2 face="sans-serif">
// if not might be lower down</font>
<br><font size=2 face="sans-serif">
for (int i = 1; i < mruList.length; i++)
{</font>
<br><font size=2 face="sans-serif">
if (mruList[i]
!= null && mruList[i].getName().equals(name)) {</font>
<br><font size=2 face="sans-serif">
// it is so just shuffle down to the point
we found it</font>
<br><font size=2 face="sans-serif">
for (int j = i - 1; j >= 0; j--) {</font>
<br><font size=2 face="sans-serif">
mruList[j
+ 1] = mruList[j];</font>
<br><font size=2 face="sans-serif">
}</font>
<br><font size=2 face="sans-serif">
mruList[0] = input;</font>
<br><font size=2 face="sans-serif">
return;</font>
<br><font size=2 face="sans-serif">
}</font>
<br><font size=2 face="sans-serif">
}</font>
<br>
<br><font size=2 face="sans-serif">
// new one so shuffle down and add at the
top</font>
<br><font size=2 face="sans-serif">
for (int i = mruList.length - 2; i >= 0;
i--) {</font>
<br><font size=2 face="sans-serif">
mruList[i
+ 1] = mruList[i];</font>
<br><font size=2 face="sans-serif">
}</font>
<br><font size=2 face="sans-serif">
mruList[0] = input;</font>
<br><font size=2 face="sans-serif"> }</font>
<br>
<br><font size=2 face="sans-serif"> /**</font>
<br><font size=2 face="sans-serif"> *
Persists the MRU to the preference store. The Workbench calls this method
on shutdown.</font>
<br><font size=2 face="sans-serif"> *
User is not required to call this method.</font>
<br><font size=2 face="sans-serif"> */</font>
<br><font size=2 face="sans-serif"> public
void persist() {</font>
<br><font size=2 face="sans-serif">
IPreferenceStore store = App.getDefault().getPreferenceStore();</font>
<br><font size=2 face="sans-serif">
for (int i = 0; i < mruList.length; i++)
{</font>
<br><font size=2 face="sans-serif">
if (mruList[i]
!= null)</font>
<br><font size=2 face="sans-serif">
store.setValue("mru" + i, mruList[i].toString());
//$NON-NLS-1$</font>
<br><font size=2 face="sans-serif">
}</font>
<br><font size=2 face="sans-serif"> }</font>
<br>
<br><font size=2 face="sans-serif"> /**</font>
<br><font size=2 face="sans-serif"> *
Fills the given menu with menu items for all windows.</font>
<br><font size=2 face="sans-serif"> *
</font>
<br><font size=2 face="sans-serif"> *
Not user callable.</font>
<br><font size=2 face="sans-serif"> */</font>
<br><font size=2 face="sans-serif"> public
void fill(final Menu menu, int index) {</font>
<br>
<br><font size=2 face="sans-serif">
if (window.getActivePage() == null || window.getActivePage().getPerspective()
== null) {</font>
<br><font size=2 face="sans-serif">
return;</font>
<br><font size=2 face="sans-serif">
}</font>
<br>
<br><font size=2 face="sans-serif">
// Get items.</font>
<br><font size=2 face="sans-serif">
for (int i = 0; i < mruList.length; i++)
{</font>
<br><font size=2 face="sans-serif">
if (mruList[i]
!= null) {</font>
<br><font size=2 face="sans-serif">
MenuItem mi = new MenuItem(menu, SWT.PUSH,
index++);</font>
<br><font size=2 face="sans-serif">
mi.setText(mruList[i].getShortName());</font>
<br><font size=2 face="sans-serif">
mi.setData("editor", mruList[i]);
//$NON-NLS-1$</font>
<br><font size=2 face="sans-serif">
mi.addSelectionListener(new SelectionAdapter()
{</font>
<br><font size=2 face="sans-serif">
public
void widgetSelected(SelectionEvent e) {</font>
<br><font size=2 face="sans-serif">
MenuItem item = (MenuItem) e.getSource();</font>
<br><font size=2 face="sans-serif">
try {</font>
<br><font size=2 face="sans-serif">
MRUContribution.openEditor((FileEditorInput)
item.getData("editor")); //$NON-NLS-1$</font>
<br><font size=2 face="sans-serif">
} catch (Exception e1) {</font>
<br><font size=2 face="sans-serif">
App.errorMessage("MRUContribution",
e1); //$NON-NLS-1$</font>
<br><font size=2 face="sans-serif">
}</font>
<br><font size=2 face="sans-serif">
}</font>
<br><font size=2 face="sans-serif">
});</font>
<br><font size=2 face="sans-serif">
}</font>
<br><font size=2 face="sans-serif">
}</font>
<br><font size=2 face="sans-serif"> }</font>
<br>
<br><font size=2 face="sans-serif"> /**</font>
<br><font size=2 face="sans-serif"> *
Overridden to always return true and force dynamic menu building.</font>
<br><font size=2 face="sans-serif"> */</font>
<br><font size=2 face="sans-serif"> public
boolean isDirty() {</font>
<br><font size=2 face="sans-serif">
return true;</font>
<br><font size=2 face="sans-serif"> }</font>
<br>
<br><font size=2 face="sans-serif"> /**</font>
<br><font size=2 face="sans-serif"> *
Overridden to always return true and force dynamic menu building.</font>
<br><font size=2 face="sans-serif"> */</font>
<br><font size=2 face="sans-serif"> public
boolean isDynamic() {</font>
<br><font size=2 face="sans-serif">
return true;</font>
<br><font size=2 face="sans-serif"> }</font>
<br>
<br><font size=2 face="sans-serif"> /**</font>
<br><font size=2 face="sans-serif"> *
Fired by a property change event, not user callable.</font>
<br><font size=2 face="sans-serif"> */</font>
<br><font size=2 face="sans-serif"> public
void propertyChange(PropertyChangeEvent event) {</font>
<br><font size=2 face="sans-serif">
if (event.getProperty().equals(PreferenceConstants.MRU_SIZE))
{</font>
<br><font size=2 face="sans-serif">
FileEditorInput[]
copy = new FileEditorInput[mruList.length];</font>
<br><font size=2 face="sans-serif">
for (int
i = 0; i < mruList.length; i++) {</font>
<br><font size=2 face="sans-serif">
copy[i] = mruList[i];</font>
<br><font size=2 face="sans-serif">
}</font>
<br><font size=2 face="sans-serif">
Integer
i = (Integer) event.getNewValue();</font>
<br><font size=2 face="sans-serif">
mruList
= new FileEditorInput[i.intValue()];</font>
<br><font size=2 face="sans-serif">
int size
= mruList.length > copy.length ? copy.length : mruList.length;</font>
<br><font size=2 face="sans-serif">
for (int
j = 0; j < size; j++) {</font>
<br><font size=2 face="sans-serif">
mruList[j] = copy[j];</font>
<br><font size=2 face="sans-serif">
}</font>
<br><font size=2 face="sans-serif">
}</font>
<br><font size=2 face="sans-serif">
</font>
<br><font size=2 face="sans-serif"> }</font>
<br>
<br><font size=2 face="sans-serif">}</font>
|
|
|
Re: Persisting MRU in RCP [message #451155 is a reply to message #450676] |
Thu, 15 June 2006 23:36 |
Damian Biollo Messages: 19 Registered: July 2009 |
Junior Member |
|
|
This is a multi-part message in MIME format.
------=_NextPart_000_00F0_01C69099.CA7B92D0
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
One problem of the MRU list is that external files do not get persisted =
correctly - instead they disappear from the list after an RCP app =
(Eclipse included) is closed.
See the bugzilla:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=3D147379
<Phill_Perryman@Mitel.COM> wrote in message =
news:e66bd2$nr2$2@utils.eclipse.org...
I found I could not do it as the workbench MRU uses IDE stuff and it =
is internal.=20
In the end I had to roll my own, if it is of any use=20
=
/*********************************************************** *************=
*******=20
* Copyright (c) 2006 Mitel Corporation.=20
* All rights reserved. This program and the accompanying materials=20
* are copyright Mitel Corporation and and may not be reproduced, =
edited,=20
* altered, or otherwise modified, except with the express permission =
of the author.=20
*=20
* Contributors:=20
* Phill Perryman - Initial Implementation=20
=
************************************************************ *************=
******/=20
package com.mitel.swb;=20
import org.eclipse.jface.action.ContributionItem;=20
import org.eclipse.jface.preference.IPreferenceStore;=20
import org.eclipse.jface.util.IPropertyChangeListener;=20
import org.eclipse.jface.util.PropertyChangeEvent;=20
import org.eclipse.swt.SWT;=20
import org.eclipse.swt.events.SelectionAdapter;=20
import org.eclipse.swt.events.SelectionEvent;=20
import org.eclipse.swt.widgets.Menu;=20
import org.eclipse.swt.widgets.MenuItem;=20
import org.eclipse.ui.IWorkbenchPage;=20
import org.eclipse.ui.IWorkbenchWindow;=20
import org.eclipse.ui.PartInitException;=20
import com.mitel.swb.preferences.PreferenceConstants;=20
import com.mitel.swb.util.FileEditorInput;=20
/**=20
* This class maintains the Sales Workbench MRU list.=20
*=20
* The list is maintained using the FileEditorInput class. Calls to =
the open=20
* method will automatically add the file to the MRU list. If an =
editor is=20
* opened and subsequently saved through a saveAs then the add method =
should=20
* be called to add the new file name.=20
*=20
* The workbench adds this class to the file menu as a =
ContributionItem=20
* so it will be called back as the menu is populated.=20
*=20
*/=20
public class MRUContribution extends ContributionItem implements =
IPropertyChangeListener {=20
=20
private final static String ID =3D =
"com.mitel.swb.MRUContribution"; //$NON-NLS-1$=20
=20
private static IWorkbenchWindow window;=20
private static FileEditorInput[] mruList;=20
private static MRUContribution contribution;=20
/*=20
* Singleton class so a private constructor.=20
*/=20
private MRUContribution(IWorkbenchWindow window, String id) {=20
super(id);=20
MRUContribution.window =3D window;=20
IPreferenceStore store =3D =
App.getDefault().getPreferenceStore();=20
store.addPropertyChangeListener(this);=20
int size =3D =
store.getInt(PreferenceConstants.MRU_SIZE);=20
mruList =3D new FileEditorInput[size];=20
for (int i =3D 0; i < mruList.length; i++) {=20
String pref =3D store.getString("mru" + i); =
//$NON-NLS-1$=20
if (!pref.equals("")) //$NON-NLS-1$=20
mruList[i] =3D new =
FileEditorInput(pref.split(",")); //$NON-NLS-1$=20
}=20
}=20
/**=20
* This is a singleton class so a factory method will create =
or return the single instance.=20
* @param workbenchWindow main application window=20
*/=20
public static MRUContribution getDefault(IWorkbenchWindow =
workbenchWindow) {=20
if (contribution =3D=3D null)=20
contribution =3D new =
MRUContribution(workbenchWindow, ID);=20
return contribution;=20
}=20
/**=20
* Opens the editor as defined in the FileEditorInput class. =
The file name=20
* is also added to the MRU list if it is not blank.=20
*=20
* The list is mantained in a "last opened at the top of the =
list" order.=20
* The method calls add to perform this operation if the =
editor is successfully opened.=20
*=20
* @param input editor input for the file=20
* @throws PartInitException=20
*/=20
public static void openEditor(FileEditorInput input) throws =
PartInitException {=20
IWorkbenchPage page =3D window.getActivePage();=20
page.openEditor(input, input.getEditorId());=20
if (!input.getName().equals("")) //$NON-NLS-1$=20
add(input);=20
}=20
/**=20
* Adds the file name to the top of the MRU list. If it =
already exists in the=20
* list it will be removed an the list shuffled down.=20
*=20
* @param input editor input for the file=20
*/=20
public static void add(FileEditorInput input) {=20
if (mruList.length < 1)=20
return;=20
=20
// zero is considered the top of the MRU list=20
if (mruList[0] =3D=3D null) {=20
mruList[0] =3D input;=20
return;=20
}=20
// first see if we have it already at the top=20
String name =3D input.getName();=20
if (mruList[0].getName().equals(name))=20
return;=20
// if not might be lower down=20
for (int i =3D 1; i < mruList.length; i++) {=20
if (mruList[i] !=3D null && =
mruList[i].getName().equals(name)) {=20
// it is so just shuffle down to the =
point we found it=20
for (int j =3D i - 1; j >=3D 0; j--) { =
mruList[j + 1] =3D mruList[j]; =
}=20
mruList[0] =3D input;=20
return;=20
}=20
}=20
// new one so shuffle down and add at the top=20
for (int i =3D mruList.length - 2; i >=3D 0; i--) {=20
mruList[i + 1] =3D mruList[i];=20
}=20
mruList[0] =3D input;=20
}=20
/**=20
* Persists the MRU to the preference store. The Workbench =
calls this method on shutdown.=20
* User is not required to call this method.=20
*/=20
public void persist() {=20
IPreferenceStore store =3D =
App.getDefault().getPreferenceStore();=20
for (int i =3D 0; i < mruList.length; i++) {=20
if (mruList[i] !=3D null)=20
store.setValue("mru" + i, =
mruList[i].toString()); //$NON-NLS-1$=20
}=20
}=20
/**=20
* Fills the given menu with menu items for all windows.=20
*=20
* Not user callable.=20
*/=20
public void fill(final Menu menu, int index) {=20
if (window.getActivePage() =3D=3D null || =
window.getActivePage().getPerspective() =3D=3D null) {=20
return;=20
}=20
// Get items.=20
for (int i =3D 0; i < mruList.length; i++) {=20
if (mruList[i] !=3D null) {=20
MenuItem mi =3D new MenuItem(menu, =
SWT.PUSH, index++);=20
mi.setText(mruList[i].getShortName()); =
mi.setData("editor", mruList[i]); =
//$NON-NLS-1$=20
mi.addSelectionListener(new =
SelectionAdapter() {=20
public void =
widgetSelected(SelectionEvent e) {=20
MenuItem item =3D =
(MenuItem) e.getSource();=20
try {=20
=
MRUContribution.openEditor((FileEditorInput) item.getData("editor")); =
//$NON-NLS-1$=20
} catch (Exception e1) =
{=20
=
App.errorMessage("MRUContribution", e1); //$NON-NLS-1$=20
}=20
}=20
});=20
}=20
}=20
}=20
/**=20
* Overridden to always return true and force dynamic menu =
building.=20
*/=20
public boolean isDirty() {=20
return true;=20
}=20
/**=20
* Overridden to always return true and force dynamic menu =
building.=20
*/=20
public boolean isDynamic() {=20
return true;=20
}=20
/**=20
* Fired by a property change event, not user callable.=20
*/=20
public void propertyChange(PropertyChangeEvent event) {=20
if =
(event.getProperty().equals(PreferenceConstants.MRU_SIZE)) {=20
FileEditorInput[] copy =3D new =
FileEditorInput[mruList.length];=20
for (int i =3D 0; i < mruList.length; i++) {=20
copy[i] =3D mruList[i];=20
}=20
Integer i =3D (Integer) event.getNewValue();=20
mruList =3D new FileEditorInput[i.intValue()]; =
int size =3D mruList.length > copy.length ? =
copy.length : mruList.length;=20
for (int j =3D 0; j < size; j++) {=20
mruList[j] =3D copy[j];=20
}=20
}=20
=20
}=20
}
------=_NextPart_000_00F0_01C69099.CA7B92D0
Content-Type: text/html;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META http-equiv=3DContent-Type content=3D"text/html; =
charset=3Diso-8859-1">
<META content=3D"MSHTML 6.00.2800.1543" name=3DGENERATOR>
<STYLE></STYLE>
</HEAD>
<BODY bgColor=3D#ffffff>
<DIV>
<DIV><FONT face=3DArial size=3D2>One problem of the MRU list is that =
external files=20
do not get persisted correctly - instead they disappear from the list =
after an=20
RCP app (Eclipse included) is closed.</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT> </DIV>
<DIV><FONT face=3DArial size=3D2>See the bugzilla:</FONT></DIV>
<DIV><FONT face=3DArial size=3D2><A=20
href=3D"https://bugs.eclipse.org/bugs/show_bug.cgi?id=3D147379">https://b=
ugs.eclipse.org/bugs/show_bug.cgi?id=3D147379</A></FONT></DIV >
<DIV><FONT face=3DArial size=3D2></FONT> </DIV>
<DIV> </DIV></DIV>
<BLOCKQUOTE=20
style=3D"PADDING-RIGHT: 0px; PADDING-LEFT: 5px; MARGIN-LEFT: 5px; =
BORDER-LEFT: #000000 2px solid; MARGIN-RIGHT: 0px">
<DIV><<A=20
=
href=3D"mailto:Phill_Perryman@Mitel.COM">Phill_Perryman@Mitel.COM</A>>=
wrote=20
in message <A=20
=
href=3D"news:e66bd2$nr2$2@utils.eclipse.org">news:e66bd2$nr2$2@utils.ecli=
pse.org</A>...</DIV><BR><FONT=20
face=3Dsans-serif size=3D2>I found I could not do it as the workbench =
MRU uses IDE=20
stuff and it is internal.</FONT> <BR><BR><FONT face=3Dsans-serif =
size=3D2>In the=20
end I had to roll my own, if it is of any use</FONT> <BR><BR><FONT=20
face=3Dsans-serif=20
=
size=3D2> /*********************************************************** ****=
****************</FONT>=20
<BR><FONT face=3Dsans-serif size=3D2> * Copyright (c) 2006 Mitel=20
Corporation.</FONT> <BR><FONT face=3Dsans-serif size=3D2> * All =
rights=20
reserved. This program and the accompanying materials </FONT><BR><FONT =
face=3Dsans-serif size=3D2> * are copyright Mitel Corporation and =
and may not=20
be reproduced, edited, </FONT><BR><FONT face=3Dsans-serif =
size=3D2> *=20
altered, or otherwise modified, except with the express permission of =
the=20
author.</FONT> <BR><FONT face=3Dsans-serif size=3D2> * =
</FONT><BR><FONT=20
face=3Dsans-serif size=3D2> * Contributors:</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2> * Phill Perryman - Initial =
Implementation</FONT>=20
<BR><FONT face=3Dsans-serif=20
=
size=3D2> ************************************************** ********=
*********************/</FONT>=20
<BR><FONT face=3Dsans-serif size=3D2>package com.mitel.swb;</FONT> =
<BR><BR><FONT=20
face=3Dsans-serif size=3D2>import=20
org.eclipse.jface.action.ContributionItem;</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2>import org.eclipse.jface.preference.IPreferenceStore;</FONT> =
<BR><FONT=20
face=3Dsans-serif size=3D2>import=20
org.eclipse.jface.util.IPropertyChangeListener;</FONT> <BR><FONT=20
face=3Dsans-serif size=3D2>import=20
org.eclipse.jface.util.PropertyChangeEvent;</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2>import org.eclipse.swt.SWT;</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2>import org.eclipse.swt.events.SelectionAdapter;</FONT> =
<BR><FONT=20
face=3Dsans-serif size=3D2>import =
org.eclipse.swt.events.SelectionEvent;</FONT>=20
<BR><FONT face=3Dsans-serif size=3D2>import =
org.eclipse.swt.widgets.Menu;</FONT>=20
<BR><FONT face=3Dsans-serif size=3D2>import=20
org.eclipse.swt.widgets.MenuItem;</FONT> <BR><FONT face=3Dsans-serif=20
size=3D2>import org.eclipse.ui.IWorkbenchPage;</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2>import org.eclipse.ui.IWorkbenchWindow;</FONT> <BR><FONT=20
face=3Dsans-serif size=3D2>import =
org.eclipse.ui.PartInitException;</FONT>=20
<BR><BR><FONT face=3Dsans-serif size=3D2>import=20
com.mitel.swb.preferences.PreferenceConstants;</FONT> <BR><FONT=20
face=3Dsans-serif size=3D2>import =
com.mitel.swb.util.FileEditorInput;</FONT>=20
<BR><BR><FONT face=3Dsans-serif size=3D2>/**</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2> * This class maintains the Sales Workbench MRU =
list.</FONT>=20
<BR><FONT face=3Dsans-serif size=3D2> * </FONT><BR><FONT =
face=3Dsans-serif=20
size=3D2> * The list is maintained using the FileEditorInput =
class. Calls=20
to the open</FONT> <BR><FONT face=3Dsans-serif size=3D2> * method =
will=20
automatically add the file to the MRU list. If an editor is</FONT> =
<BR><FONT=20
face=3Dsans-serif size=3D2> * opened and subsequently saved =
through a saveAs=20
then the add method should</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> * be=20
called to add the new file name.</FONT> <BR><FONT face=3Dsans-serif=20
size=3D2> * </FONT><BR><FONT face=3Dsans-serif size=3D2> * =
The workbench=20
adds this class to the file menu as a ContributionItem</FONT> =
<BR><FONT=20
face=3Dsans-serif size=3D2> * so it will be called back as the =
menu is=20
populated.</FONT> <BR><FONT face=3Dsans-serif size=3D2> * =
</FONT><BR><FONT=20
face=3Dsans-serif size=3D2> */</FONT> <BR><FONT face=3Dsans-serif =
size=3D2>public=20
class MRUContribution extends ContributionItem implements=20
IPropertyChangeListener {</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =20
</FONT><BR><FONT face=3Dsans-serif =
size=3D2> =20
private final static String ID =3D=20
"com.mitel.swb.MRUContribution"; //$NON-NLS-1$</FONT> <BR><FONT=20
face=3Dsans-serif size=3D2> =
</FONT><BR><FONT=20
face=3Dsans-serif size=3D2> private static=20
IWorkbenchWindow window;</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =20
private static FileEditorInput[] mruList;</FONT> =
<BR><FONT=20
face=3Dsans-serif size=3D2> private static=20
MRUContribution contribution;</FONT> <BR><BR><FONT face=3Dsans-serif=20
size=3D2> /*</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2> * Singleton class so a =
private=20
constructor.</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
*/</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
private MRUContribution(IWorkbenchWindow window, String id) =
{</FONT>=20
<BR><FONT face=3Dsans-serif size=3D2> =
=20
super(id);</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =20
MRUContribution.window =3D=20
window;</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
IPreferenceStore store =3D=20
App.getDefault().getPreferenceStore();</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2> =20
store.addPropertyChangeListener(this);</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2> int =
size =3D=20
store.getInt(PreferenceConstants.MRU_SIZE);</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2> =
mruList =3D new=20
FileEditorInput[size];</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =20
for (int i =3D 0; i <=20
mruList.length; i++) {</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =20
=
String=20
pref =3D store.getString("mru" + i); //$NON-NLS-1$</FONT> <BR><FONT=20
face=3Dsans-serif size=3D2> =
=20
if (!pref.equals("")) //$NON-NLS-1$</FONT> =
<BR><FONT face=3Dsans-serif size=3D2> =
=20
=20
mruList[i] =3D new FileEditorInput(pref.split(",")); =
//$NON-NLS-1$</FONT>=20
<BR><FONT face=3Dsans-serif size=3D2> =
=20
}</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
}</FONT> <BR><BR><FONT face=3Dsans-serif size=3D2> =
=20
/**</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
* This is a singleton class so a factory method will create or =
return=20
the single instance.</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =20
* @param workbenchWindow main application =
window</FONT>=20
<BR><FONT face=3Dsans-serif size=3D2> =
*/</FONT>=20
<BR><FONT face=3Dsans-serif size=3D2> =
public static=20
MRUContribution getDefault(IWorkbenchWindow workbenchWindow) {</FONT>=20
<BR><FONT face=3Dsans-serif size=3D2> =
=20
if (contribution =3D=3D null)</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2> =
=20
contribution =3D new MRUContribution(workbenchWindow, =
ID);</FONT>=20
<BR><FONT face=3Dsans-serif size=3D2> =
=20
return contribution;</FONT> <BR><FONT face=3Dsans-serif=20
size=3D2> }</FONT> <BR><BR><FONT =
face=3Dsans-serif=20
size=3D2> /**</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2> * Opens the editor as =
defined in the=20
FileEditorInput class. The file name</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2> * is also added to the MRU =
list if it=20
is not blank.</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
* </FONT><BR><FONT face=3Dsans-serif size=3D2> =
=20
* The list is mantained in a "last opened at the top of =
the list"=20
order.</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
* The method calls add to perform this operation if the editor =
is=20
successfully opened.</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =20
* </FONT><BR><FONT face=3Dsans-serif =
size=3D2> =20
* @param input editor input for the file</FONT> =
<BR><FONT=20
face=3Dsans-serif size=3D2> * @throws =
PartInitException</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
*/</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
public static void openEditor(FileEditorInput input) throws=20
PartInitException {</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
IWorkbenchPage page =3D=20
window.getActivePage();</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =20
page.openEditor(input,=20
input.getEditorId());</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =20
if =
(!input.getName().equals(""))=20
//$NON-NLS-1$</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
=20
add(input);</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
}</FONT> <BR><BR><FONT face=3Dsans-serif size=3D2> =
=20
/**</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
* Adds the file name to the top of the MRU list. If it already =
exists in=20
the</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
* list it will be removed an the list shuffled down.</FONT> =
<BR><FONT=20
face=3Dsans-serif size=3D2> * =
</FONT><BR><FONT=20
face=3Dsans-serif size=3D2> * @param =
input editor=20
input for the file</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
*/</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =20
public static void add(FileEditorInput input) {</FONT> =
<BR><FONT=20
face=3Dsans-serif size=3D2> =
=20
if (mruList.length < 1)</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =20
=
=20
return;</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
</FONT><BR><FONT face=3Dsans-serif =
size=3D2> =20
// zero is considered =
the top=20
of the MRU list</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
if (mruList[0] =3D=3D null) =
{</FONT> <BR><FONT=20
face=3Dsans-serif size=3D2> =
=20
mruList[0] =3D input;</FONT> <BR><FONT=20
face=3Dsans-serif size=3D2> =
=20
return;</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =
}</FONT>=20
<BR><BR><FONT face=3Dsans-serif size=3D2> =
=20
// first see if we have it already at the top</FONT> =
<BR><FONT=20
face=3Dsans-serif size=3D2> =
=20
String name =3D input.getName();</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =20
if=20
(mruList[0].getName().equals(name))</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =
=20
return;</FONT> <BR><BR><FONT face=3Dsans-serif =
size=3D2> =20
// if not might be =
lower=20
down</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
for (int i =3D 1; i < mruList.length; =
i++)=20
{</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
if (mruList[i] !=3D =
null=20
&& mruList[i].getName().equals(name)) {</FONT> <BR><FONT=20
face=3Dsans-serif size=3D2> =
=20
// it is so =
just=20
shuffle down to the point we found it</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2> =
=20
for (int j =3D i - 1; j =
>=3D 0; j--)=20
{</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
=
=20
mruList[j + 1] =3D mruList[j];</FONT> =
<BR><FONT=20
face=3Dsans-serif size=3D2> =
=20
}</FONT> =
<BR><FONT=20
face=3Dsans-serif size=3D2> =
=20
mruList[0] =3D =
input;</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
=
=20
return;</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
=
}</FONT>=20
<BR><FONT face=3Dsans-serif size=3D2> =
=20
}</FONT> <BR><BR><FONT face=3Dsans-serif size=3D2> =
=20
// new one so shuffle down =
and add=20
at the top</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
for (int i =3D mruList.length - 2; i =
>=3D 0; i--)=20
{</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
mruList[i + 1] =3D=20
mruList[i];</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
}</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2> =
mruList[0] =3D=20
input;</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
}</FONT> <BR><BR><FONT face=3Dsans-serif size=3D2> =
=20
/**</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
* Persists the MRU to the preference store. The Workbench calls =
this=20
method on shutdown.</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
* User is not required to call this method.</FONT> =
<BR><FONT face=3Dsans-serif size=3D2> =
*/</FONT>=20
<BR><FONT face=3Dsans-serif size=3D2> =
public void=20
persist() {</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
IPreferenceStore store =3D=20
App.getDefault().getPreferenceStore();</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2> for =
(int i =3D 0;=20
i < mruList.length; i++) {</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =20
=
=20
if (mruList[i] !=3D null)</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =20
=
=20
store.setValue("mru" + i, mruList[i].toString()); =
//$NON-NLS-1$</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
}</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2> }</FONT> <BR><BR><FONT =
face=3Dsans-serif=20
size=3D2> /**</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2> * Fills the given menu with =
menu=20
items for all windows.</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =20
* </FONT><BR><FONT face=3Dsans-serif =
size=3D2> =20
* Not user callable.</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2> */</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2> public void fill(final Menu menu, =
int=20
index) {</FONT> <BR><BR><FONT face=3Dsans-serif size=3D2> =
=20
if (window.getActivePage() =3D=3D =
null ||=20
window.getActivePage().getPerspective() =3D=3D null) {</FONT> =
<BR><FONT=20
face=3Dsans-serif size=3D2> =
=20
return;</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =
}</FONT>=20
<BR><BR><FONT face=3Dsans-serif size=3D2> =
=20
// Get items.</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =20
for (int i =3D 0; i =
<=20
mruList.length; i++) {</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =20
=
if=20
(mruList[i] !=3D null) {</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =20
=
=20
MenuItem mi =3D new MenuItem(menu, SWT.PUSH,=20
index++);</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
=
=20
mi.setText(mruList[i].getShortName());</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2> =
=20
mi.setData("editor", =
mruList[i]);=20
//$NON-NLS-1$</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
=
=20
mi.addSelectionListener(new SelectionAdapter() {</FONT>=20
<BR><FONT face=3Dsans-serif size=3D2> =
=20
=
=20
public void widgetSelected(SelectionEvent e) =
{</FONT>=20
<BR><FONT face=3Dsans-serif size=3D2> =
=20
=
=20
MenuItem item =3D =
(MenuItem)=20
e.getSource();</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
=
=20
=
try=20
{</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
=
=20
=
=20
MRUContribution.openEditor((FileEditorInput) =
item.getData("editor"));=20
//$NON-NLS-1$</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
=
=20
=
} catch=20
(Exception e1) {</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
=
=20
=
=20
App.errorMessage("MRUContribution", e1);=20
//$NON-NLS-1$</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
=
=20
=
}</FONT>=20
<BR><FONT face=3Dsans-serif size=3D2> =
=20
=
=20
}</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =20
=
=20
});</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =20
=
}</FONT>=20
<BR><FONT face=3Dsans-serif size=3D2> =
=20
}</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
}</FONT> <BR><BR><FONT face=3Dsans-serif size=3D2> =
=20
/**</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
* Overridden to always return true and force dynamic menu=20
building.</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
*/</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
public boolean isDirty() {</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =20
return true;</FONT> =
<BR><FONT=20
face=3Dsans-serif size=3D2> }</FONT> =
<BR><BR><FONT=20
face=3Dsans-serif size=3D2> /**</FONT> =
<BR><FONT=20
face=3Dsans-serif size=3D2> * =
Overridden to=20
always return true and force dynamic menu building.</FONT> <BR><FONT=20
face=3Dsans-serif size=3D2> */</FONT> =
<BR><FONT=20
face=3Dsans-serif size=3D2> public boolean =
isDynamic()=20
{</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
return true;</FONT> <BR><FONT face=3Dsans-serif=20
size=3D2> }</FONT> <BR><BR><FONT =
face=3Dsans-serif=20
size=3D2> /**</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2> * Fired by a property =
change event,=20
not user callable.</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
*/</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =20
public void propertyChange(PropertyChangeEvent event) =
{</FONT>=20
<BR><FONT face=3Dsans-serif size=3D2> =
=20
if =
(event.getProperty().equals(PreferenceConstants.MRU_SIZE))=2 0
{</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
FileEditorInput[] =
copy =3D new=20
FileEditorInput[mruList.length];</FONT> <BR><FONT face=3Dsans-serif=20
size=3D2> =
=20
for (int i =3D 0; i < mruList.length; i++) {</FONT> =
<BR><FONT=20
face=3Dsans-serif size=3D2> =
=20
copy[i] =3D=20
mruList[i];</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
=
}</FONT>=20
<BR><FONT face=3Dsans-serif size=3D2> =
=20
Integer i =3D (Integer)=20
event.getNewValue();</FONT> <BR><FONT face=3Dsans-serif =
size=3D2> =20
=
mruList=20
=3D new FileEditorInput[i.intValue()];</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2> =
=20
int size =3D mruList.length > copy.length ? =
copy.length :=20
mruList.length;</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
for =
(int j =3D 0;=20
j < size; j++) {</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
=
=20
mruList[j] =3D copy[j];</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2> =
=20
}</FONT> <BR><FONT face=3Dsans-serif size=3D2> =
=20
}</FONT> <BR><FONT =
face=3Dsans-serif=20
size=3D2> =20
</FONT><BR><FONT face=3Dsans-serif size=3D2> =
}</FONT>=20
<BR><BR><FONT face=3Dsans-serif =
size=3D2>}</FONT></BLOCKQUOTE></BODY></HTML>
------=_NextPart_000_00F0_01C69099.CA7B92D0--
|
|
|
Goto Forum:
Current Time: Fri Mar 29 12:02:27 GMT 2024
Powered by FUDForum. Page generated in 0.03227 seconds
|