Quelle J2Ddemo.java
Sprache: JAVA
/*
*
* Copyright ( c ) 2007 , 2021 , Oracle and / or its affiliates . All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
*
* - Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
*
* - Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS
* IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO ,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL ,
* EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO ,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR
* PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING
* NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
package java2d;
import static java2d.CustomControlsContext.State.START;
import static java2d.CustomControlsContext.State.STOP;
import static java2d.DemoImages.newDemoImages;
import static java2d.DemoFonts.newDemoFonts;
import static java2d.RunWindow.RunWindowSettings;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JProgressBar;
import javax.swing.JSeparator;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.EtchedBorder;
/**
* A demo that shows Java 2 D ( TM ) API features .
*/
@SuppressWarnings("serial" )
public class J2Ddemo extends JPanel implements ItemListener, ActionListener, DemoInstVarsAccessor {
private final GlobalControls controls;
private final MemoryMonitor memorymonitor;
private final PerformanceMonitor performancemonitor;
private final JTabbedPane tabbedPane;
private final DemoGroup[] group;
private JCheckBoxMenuItem verboseCB;
private JCheckBoxMenuItem ccthreadCB;
private JCheckBoxMenuItem printCB = new JCheckBoxMenuItem("Default Printer" );
private Color backgroundColor;
private JCheckBoxMenuItem memoryCB, perfCB;
private final Intro intro;
public static final String[][] demos = {
{ "Arcs_Curves" , "Arcs" , "BezierAnim" , "Curves" , "Ellipses" },
{ "Clipping" , "Areas" , "ClipAnim" , "Intersection" , "Text" },
{ "Colors" , "BullsEye" , "ColorConvert" , "Rotator3D" },
{ "Composite" , "ACimages" , "ACrules" , "FadeAnim" },
{ "Fonts" , "AttributedStr" , "Highlighting" , "Outline" , "Tree" },
{ "Images" , "DukeAnim" , "ImageOps" , "JPEGFlip" , "WarpImage" },
{ "Lines" , "Caps" , "Dash" , "Joins" , "LineAnim" },
{ "Mix" , "Balls" , "BezierScroller" , "Stars3D" },
{ "Paint" , "GradAnim" , "Gradient" , "Texture" , "TextureAnim" },
{ "Paths" , "Append" , "CurveQuadTo" , "FillStroke" , "WindingRule" },
{ "Transforms" , "Rotate" , "SelectTx" , "TransformAnim" }
};
private JCheckBoxMenuItem controlsCB;
private JMenuItem runMI, cloneMI, fileMI, backgMI;
// private JMenuItem ccthreadMI, verboseMI;
private RunWindow runwindow;
private RunWindowSettings runWndSetts;
private CloningFeature cloningfeature;
private JFrame rf, cf;
// private GlobalPanel gp;
/**
* Construct the J2D Demo .
*/
public J2Ddemo(DemoProgress progress, RunWindowSettings runWndSetts) {
this .runWndSetts = runWndSetts;
setLayout(new BorderLayout());
setBorder(new EtchedBorder());
add(createMenuBar(), BorderLayout.NORTH);
// hard coding 14 = 11 demo dirs + images + fonts + Intro
progress.setMaximum(13 );
progress.setText("Loading images" );
newDemoImages();
progress.setValue(progress.getValue() + 1 );
progress.setText("Loading fonts" );
newDemoFonts();
progress.setValue(progress.getValue() + 1 );
progress.setText("Loading Intro" );
intro = new Intro();
progress.setValue(progress.getValue() + 1 );
UIManager.put("Button.margin" , new Insets(0 , 0 , 0 , 0 ));
controls = new GlobalControls(this );
memorymonitor = new MemoryMonitor();
performancemonitor = new PerformanceMonitor();
GlobalPanel gp = new GlobalPanel(this );
tabbedPane = new JTabbedPane(JTabbedPane.TOP, JTabbedPane.WRAP_TAB_LAYOUT);
tabbedPane.setFont(new Font(Font.SERIF, Font.PLAIN, 12 ));
tabbedPane.addTab("" , new J2DIcon(this ), gp);
tabbedPane.addChangeListener(gp);
group = new DemoGroup[demos.length];
for (int i = 0 ; i < demos.length; i++) {
progress.setText("Loading demos." + demos[i][0 ]);
group[i] = new DemoGroup(demos[i][0 ], this );
tabbedPane.addTab(demos[i][0 ], null );
progress.setValue(progress.getValue() + 1 );
}
add(tabbedPane, BorderLayout.CENTER);
}
private JMenuBar createMenuBar() {
JPopupMenu.setDefaultLightWeightPopupEnabled(false );
JMenuBar menuBar = new JMenuBar();
JMenu file = menuBar.add(new JMenu("File" ));
fileMI = file.add(new JMenuItem("Exit" ));
fileMI.addActionListener(this );
JMenu options = menuBar.add(new JMenu("Options" ));
controlsCB = (JCheckBoxMenuItem) options.add(
new JCheckBoxMenuItem("Global Controls" , true ));
controlsCB.addItemListener(this );
memoryCB = (JCheckBoxMenuItem) options.add(
new JCheckBoxMenuItem("Memory Monitor" , true ));
memoryCB.addItemListener(this );
perfCB = (JCheckBoxMenuItem) options.add(
new JCheckBoxMenuItem("Performance Monitor" , true ));
perfCB.addItemListener(this );
options.add(new JSeparator());
ccthreadCB = (JCheckBoxMenuItem) options.add(
new JCheckBoxMenuItem("Custom Controls Thread" ));
ccthreadCB.addItemListener(this );
printCB = (JCheckBoxMenuItem) options.add(printCB);
verboseCB = (JCheckBoxMenuItem) options.add(
new JCheckBoxMenuItem("Verbose" ));
options.add(new JSeparator());
backgMI = options.add(new JMenuItem("Background Color" ));
backgMI.addActionListener(this );
runMI = options.add(new JMenuItem("Run Window" ));
runMI.addActionListener(this );
cloneMI = options.add(new JMenuItem("Cloning Feature" ));
cloneMI.addActionListener(this );
return menuBar;
}
public void createRunWindow() {
if (rf != null ) {
rf.toFront();
return;
}
runwindow = new RunWindow(this , runWndSetts);
WindowListener l = new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
runwindow.stop();
rf.dispose();
}
@Override
public void windowClosed(WindowEvent e) {
rf = null ;
}
};
rf = new JFrame("Run" );
rf.addWindowListener(l);
rf.getContentPane().add("Center" , runwindow);
rf.pack();
rf.setSize(new Dimension(200 , 125 ));
rf.setVisible(true );
}
public void startRunWindow() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
runwindow.doRunAction();
}
});
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource().equals(fileMI)) {
System.exit(0 );
} else if (e.getSource().equals(runMI)) {
createRunWindow();
} else if (e.getSource().equals(cloneMI)) {
if (cloningfeature == null ) {
cloningfeature = new CloningFeature(this );
WindowListener l = new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
cloningfeature.stop();
cf.dispose();
}
@Override
public void windowClosed(WindowEvent e) {
cloningfeature = null ;
}
};
cf = new JFrame("Cloning Demo" );
cf.addWindowListener(l);
cf.getContentPane().add("Center" , cloningfeature);
cf.pack();
cf.setSize(new Dimension(320 , 330 ));
cf.setVisible(true );
} else {
cf.toFront();
}
} else if (e.getSource().equals(backgMI)) {
backgroundColor =
JColorChooser.showDialog(this , "Background Color" ,
Color.white);
for (int i = 1 ; i < tabbedPane.getTabCount(); i++) {
JPanel p = group[i - 1 ].getPanel();
for (int j = 0 ; j < p.getComponentCount(); j++) {
DemoPanel dp = (DemoPanel) p.getComponent(j);
if (dp.surface != null ) {
dp.surface.setBackground(backgroundColor);
}
}
}
}
}
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getSource().equals(controlsCB)) {
boolean newVisibility = !controls.isVisible();
controls.setVisible(newVisibility);
for (Component cmp : controls.texturechooser.getComponents()) {
cmp.setVisible(newVisibility);
}
} else if (e.getSource().equals(memoryCB)) {
if (memorymonitor.isVisible()) {
memorymonitor.setVisible(false );
memorymonitor.surf.setVisible(false );
memorymonitor.surf.stop();
} else {
memorymonitor.setVisible(true );
memorymonitor.surf.setVisible(true );
memorymonitor.surf.start();
}
} else if (e.getSource().equals(perfCB)) {
if (performancemonitor.isVisible()) {
performancemonitor.setVisible(false );
performancemonitor.surf.setVisible(false );
performancemonitor.surf.stop();
} else {
performancemonitor.setVisible(true );
performancemonitor.surf.setVisible(true );
performancemonitor.surf.start();
}
} else if (e.getSource().equals(ccthreadCB)) {
CustomControlsContext.State state =
ccthreadCB.isSelected() ? START : STOP;
if (tabbedPane.getSelectedIndex() != 0 ) {
JPanel p = group[tabbedPane.getSelectedIndex() - 1 ].getPanel();
for (int i = 0 ; i < p.getComponentCount(); i++) {
DemoPanel dp = (DemoPanel) p.getComponent(i);
if (dp.ccc != null ) {
dp.ccc.handleThread(state);
}
}
}
}
revalidate();
}
public void start() {
if (tabbedPane.getSelectedIndex() == 0 ) {
intro.start();
} else {
group[tabbedPane.getSelectedIndex() - 1 ].setup(false );
if (memorymonitor.surf.thread == null && memoryCB.getState()) {
memorymonitor.surf.start();
}
if (performancemonitor.surf.thread == null && perfCB.getState()) {
performancemonitor.surf.start();
}
}
}
public void stop() {
if (tabbedPane.getSelectedIndex() == 0 ) {
intro.stop();
} else {
memorymonitor.surf.stop();
performancemonitor.surf.stop();
int i = tabbedPane.getSelectedIndex() - 1 ;
group[i].shutDown(group[i].getPanel());
}
}
/**
* Start of ' DemoInstVarsAccessor ' implementation .
*/
@Override
public GlobalControls getControls() {
return controls;
}
@Override
public MemoryMonitor getMemoryMonitor() {
return memorymonitor;
}
@Override
public PerformanceMonitor getPerformanceMonitor() {
return performancemonitor;
}
@Override
public JTabbedPane getTabbedPane() {
return tabbedPane;
}
@Override
public DemoGroup[] getGroup() {
return group;
}
@Override
public void setGroupColumns(int columns) {
for (DemoGroup dg : group) {
if (dg != null ) {
dg.columns = columns;
}
}
}
@Override
public JCheckBoxMenuItem getVerboseCB() {
return verboseCB;
}
@Override
public JCheckBoxMenuItem getCcthreadCB() {
return ccthreadCB;
}
@Override
public JCheckBoxMenuItem getPrintCB() {
return printCB;
}
@Override
public Color getBackgroundColor() {
return backgroundColor;
}
@Override
public JCheckBoxMenuItem getMemoryCB() {
return memoryCB;
}
@Override
public JCheckBoxMenuItem getPerfCB() {
return perfCB;
}
@Override
public Intro getIntro() {
return intro;
}
/**
* End of ' DemoInstVarsAccessor ' implementation .
*/
static void addToGridBag(JPanel panel, Component comp,
int x, int y, int w, int h, double weightx, double weighty) {
GridBagLayout gbl = (GridBagLayout) panel.getLayout();
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.gridx = x;
c.gridy = y;
c.gridwidth = w;
c.gridheight = h;
c.weightx = weightx;
c.weighty = weighty;
panel.add(comp);
gbl.setConstraints(comp, c);
}
/**
* The Icon for the Intro tab .
*/
static class J2DIcon implements Icon {
private final DemoInstVarsAccessor demoInstVars;
private static final Color myBlue = new Color(94 , 105 , 176 );
private static final Color myBlack = new Color(20 , 20 , 20 );
private static final Font font = new Font(Font.SERIF, Font.BOLD, 12 );
private FontRenderContext frc = new FontRenderContext(null , true , true );
private TextLayout tl = new TextLayout("J2D demo" , font, frc);
public J2DIcon(DemoInstVarsAccessor demoInstVars) {
this .demoInstVars = demoInstVars;
}
@Override
public void paintIcon(Component c, Graphics g, int x, int y) {
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setFont(font);
if (demoInstVars.getTabbedPane().getSelectedIndex() == 0 ) {
g2.setColor(myBlue);
} else {
g2.setColor(myBlack);
}
tl.draw(g2, x, y + (float )(tl.getBounds().getHeight()));
}
@Override
public int getIconWidth() {
return (int )(tl.getAdvance())+5 ;
}
@Override
public int getIconHeight() {
return (int )(tl.getBounds().getHeight());
}
}
/**
* This class eliminates the need in presence of static ' JLabel ' , ' JProgressBar '
* variables in ' J2Ddemo ' class . It is a part of the fix which changed static
* variables for instance variables in certain demo classes .
*/
public static class DemoProgress {
private final JLabel progressLabel;
private final JProgressBar progressBar;
public DemoProgress(JLabel progressLabel, JProgressBar progressBar) {
if (progressLabel == null ) {
throw new IllegalArgumentException("null was transferred as 'progressLabel' argument" );
}
if (progressBar == null ) {
throw new IllegalArgumentException("null was transferred as 'progressBar' argument" );
}
this .progressLabel = progressLabel;
this .progressBar = progressBar;
}
public void setText(String text) {
progressLabel.setText(text);
}
public void setMaximum(int n) {
progressBar.setMaximum(n);
}
public int getValue() {
return progressBar.getValue();
}
public void setValue(int n) {
progressBar.setValue(n);
}
}
private static void initFrame(String[] args, RunWindowSettings runWndSetts) {
final J2Ddemo[] demoOneInstArr = new J2Ddemo[1 ];
JFrame frame = new JFrame("Java 2D(TM) Demo" );
frame.getAccessibleContext().setAccessibleDescription(
"A sample application to demonstrate Java2D(TM) features" );
int FRAME_WIDTH = 400 , FRAME_HEIGHT = 200 ;
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
frame.setLocation(d.width / 2 - FRAME_WIDTH / 2 , d.height / 2 - FRAME_HEIGHT
/ 2 );
frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0 );
}
@Override
public void windowDeiconified(WindowEvent e) {
J2Ddemo demo = demoOneInstArr[0 ];
if (demo != null ) {
demo.start();
}
}
@Override
public void windowIconified(WindowEvent e) {
J2Ddemo demo = demoOneInstArr[0 ];
if (demo != null ) {
demo.stop();
}
}
});
JOptionPane.setRootFrame(frame);
JPanel progressPanel = new JPanel() {
@Override
public Insets getInsets() {
return new Insets(40 , 30 , 20 , 30 );
}
};
progressPanel.setLayout(new BoxLayout(progressPanel, BoxLayout.Y_AXIS));
frame.getContentPane().add(progressPanel, BorderLayout.CENTER);
Dimension labelSize = new Dimension(400 , 20 );
JLabel progressLabel = new JLabel("Loading, please wait..." );
progressLabel.setAlignmentX(CENTER_ALIGNMENT);
progressLabel.setMaximumSize(labelSize);
progressLabel.setPreferredSize(labelSize);
progressPanel.add(progressLabel);
progressPanel.add(Box.createRigidArea(new Dimension(1 , 20 )));
JProgressBar progressBar = new JProgressBar();
progressBar.setStringPainted(true );
progressLabel.setLabelFor(progressBar);
progressBar.setAlignmentX(CENTER_ALIGNMENT);
progressBar.setMinimum(0 );
progressBar.setValue(0 );
progressBar.getAccessibleContext().setAccessibleName(
"J2D demo loading progress" );
progressPanel.add(progressBar);
DemoProgress demoProgress = new DemoProgress(progressLabel, progressBar);
frame.setVisible(true );
J2Ddemo demo = new J2Ddemo(demoProgress, runWndSetts);
demoOneInstArr[0 ] = demo;
frame.getContentPane().removeAll();
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(demo, BorderLayout.CENTER);
FRAME_WIDTH = 850 ;
FRAME_HEIGHT = 600 ;
frame.setLocation(d.width / 2 - FRAME_WIDTH / 2 , d.height / 2 - FRAME_HEIGHT
/ 2 );
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
for (int i = 0 ; i < args.length; i++) {
String arg = args[i];
String s = arg.substring(arg.indexOf('=' ) + 1 );
if (arg.startsWith("-runs=" )) {
runWndSetts.setNumRuns(Integer.parseInt(s));
runWndSetts.setExit(true );
demo.createRunWindow();
} else if (arg.startsWith("-screen=" )) {
demo.getControls().screenCombo.setSelectedIndex(Integer.parseInt(s));
} else if (arg.startsWith("-antialias=" )) {
demo.controls.aliasCB.setSelected(s.endsWith("true" ));
} else if (arg.startsWith("-rendering=" )) {
demo.controls.renderCB.setSelected(s.endsWith("true" ));
} else if (arg.startsWith("-texture=" )) {
demo.controls.textureCB.setSelected(s.endsWith("true" ));
} else if (arg.startsWith("-composite=" )) {
demo.controls.compositeCB.setSelected(s.endsWith("true" ));
} else if (arg.startsWith("-verbose" )) {
demo.verboseCB.setSelected(true );
} else if (arg.startsWith("-print" )) {
demo.printCB.setSelected(true );
runWndSetts.setPrintCBIsSelected(true );
} else if (arg.startsWith("-columns=" )) {
demo.setGroupColumns(Integer.parseInt(s));
} else if (arg.startsWith("-buffers=" )) {
// usage -buffers=3,10
runWndSetts.setBuffersFlag(true );
int i1 = arg.indexOf('=' ) + 1 ;
int i2 = arg.indexOf(',' );
String s1 = arg.substring(i1, i2);
runWndSetts.setBufBeg(Integer.parseInt(s1));
s1 = arg.substring(i2 + 1 , arg.length());
runWndSetts.setBufEnd(Integer.parseInt(s1));
} else if (arg.startsWith("-ccthread" )) {
demo.ccthreadCB.setSelected(true );
} else if (arg.startsWith("-zoom" )) {
runWndSetts.setZoomCBSelected(true );
} else if (arg.startsWith("-maxscreen" )) {
frame.setLocation(0 , 0 );
frame.setSize(d.width, d.height);
}
}
frame.validate();
frame.repaint();
frame.getFocusTraversalPolicy().getDefaultComponent(frame).requestFocus();
demo.start();
if (runWndSetts.getExit()) {
demo.startRunWindow();
}
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
RunWindowSettings runWndSetts = new RunWindowSettings();
for (int i = 0 ; i < args.length; i++) {
if (args[i].startsWith("-h" ) || args[i].startsWith("-help" )) {
String s = "\njava -jar J2Ddemo.jar -runs=5 -delay=5 -screen=5 "
+ "-antialias=true -rendering=true -texture=true "
+ "-composite=true -verbose -print -columns=3 "
+ "-buffers=5,10 -ccthread -zoom -maxscreen \n" ;
System.out.println(s);
s =
" -runs=5 Number of runs to execute\n"
+ " -delay=5 Sleep amount between tabs\n"
+ " -antialias= true or false for antialiasing\n"
+ " -rendering= true or false for quality or speed\n"
+ " -texture= true or false for texturing\n"
+ " -composite= true or false for compositing\n"
+ " -verbose output Surface graphic states \n"
+ " -print during run print the Surface, "
+ "use the Default Printer\n"
+ " -columns=3 # of columns to use in clone layout \n"
+ " -screen=3 demos all use this screen type \n"
+ " -buffers=5,10 during run - clone to see screens "
+ "five through ten\n"
+ " -ccthread Invoke the Custom Controls Thread \n"
+ " -zoom mouseClick on surface for zoom in \n"
+ " -maxscreen take up the entire monitor screen \n" ;
System.out.println(s);
s =
"Examples : \n" + " Print all of the demos : \n"
+ " java -jar J2Ddemo.jar -runs=1 -delay=60 -print \n"
+ " Run zoomed in with custom control thread \n"
+ " java -jar J2Ddemo.jar -runs=10 -zoom -ccthread\n" ;
System.out.println(s);
System.exit(0 );
} else if (args[i].startsWith("-delay=" )) {
String s = args[i].substring(args[i].indexOf('=' ) + 1 );
runWndSetts.setDelay(Integer.parseInt(s));
}
}
initFrame(args, runWndSetts);
}
});
}
}
Messung V0.5 in Prozent C=99 H=96 G=97
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-09-02)
¤
*© Formatika GbR, Deutschland
2026-08-25
Neuigkeiten
Aktuelles
Motto des Tages
Open Source Software
Jenseits des Üblichen ....
Besucherstatistik
Statistik
#Sources=1019547
#Domains=890699