CATEGORII DOCUMENTE |
Clase pentru o interfata grafica
Programarea unei interfete grafice (GUI)
Comunicarea dintre un program de aplicatie si operatorul (beneficiarul) aplicatiei poate folosi ecranul in modul text sau in modul grafic. Majoritatea aplicatiilor actuale preiau datele de la operatorul uman in mod interactiv, printr-o interfata grafica, pusa la dispozitie de sistemul gazda (Microsoft Windows, Linux cu X-Windows etc).
Interfata grafica cu utilizatorul (GUI = Graphical User Interface) este mai sigura si mai 'prietenoasa', folosind atat tastatura cat si mouse-ul pentru introducere sau selectare de date afisate pe ecran.
O interfata grafica simpla consta dintr-o singura fereastra ecran a aplicatiei pe care se plaseaza diverse componente vizuale interactive, numite si "controale" pentru ca permit operatorului sa controleze evolutia programului prin introducerea unor date sau optiuni de lucru (care, in mod text, se transmit programului prin linia de comanda). Uneori, pe parcursul programului se deschid si alte ferestre, dar exista o fereastra initiala cu care incepe aplicatia.
Programele cu interfata grafica sunt controlate prin evenimente produse fie de apasarea unei taste fie de apasarea unui buton de mouse. Un eveniment des folosit este cel produs de pozitionarea cursorului pe suprafata unui "buton" desenat pe ecran si clic pe butonul din stanga de pe mouse.
Tipul evenimentelor este determinat de componenta vizuala implicata dar si de operatia efectuata. De exemplu, intr-un camp cu text terminarea unei linii de text (cu "Enter") genereaza un tip de eveniment, iar modificarea unor caractere din text genereaza un alt tip de eveniment.
Limbajul Java permite, fata de alte limbaje, programarea mai simpla si mai versatila a interfetei grafice prin numarul mare de clase si de facilitati de care dispune. De exemplu, aspectul ("Look and Feel") componentelor vizuale poate fi ales dintre trei (patru, mai nou) variante (Windows, MacOS sau Java), indiferent de sistemul de operare gazda.
In termenii specifici Java, componentele vizuale sunt de doua categorii:
- Componente "atomice", folosite ca atare si care nu pot contine alte componente (un buton este un exemplu de componenta atomica);
- Componente "container", care grupeaza mai multe componente atomice si/sau containere.
Componentele container sunt si ele de doua feluri:
- Containere de nivel superior ("top-level") pentru fereastra principala a aplicatiei;
- Containere intermediare (panouri), incluse in alte containere si care permit operatii cu un grup de componente vizuale (de exemplu, pozitionarea intregului grup).
Componentele atomice pot fi grupate dupa rolul pe care il au :
- Butoane de diverse tipuri: butoane simple, butoane radio
- Elemente de dialog
- Componente pentru selectarea unei alternative (optiuni)
- Indicatoare de progres a unor activitati de durata
- Componente cu text de diverse complexitati: camp text, zona text, documente
- Panouri cu derulare verticala sau orizontala (pentru liste sau texte voluminoase)
- Meniuri si bare de instrumente
In POO fiecare componenta a unei interfete grafice este un obiect dintr-o clasa predefinita sau dintr-o subclasa a clasei de biblioteca. Colectia claselor GUI constituie un cadru pentru dezvoltarea de aplicatii cu interfata grafica, in sensul ca asigura o baza de clase esentiale si impune un anumit mod de proiectare a acestor aplicatii si de folosire a claselor existente. Acest cadru ("Framework") mai este numit si infrastructura sau colectie de clase de baza ("Foundation Classes").
Ca infrastructura pentru aplicatiile Java cu interfata grafica vom considera clasele JFC (Java Foundation Classes), numite si "Swing", care reprezinta o evolutie fata de vechile clase AWT (Abstract Window Toolkit). Multe din clasele JFC extind sau folosesc clase AWT. Clasele JFC asigura elementele necesare proiectarii de interfete grafice complexe, atragatoare si personalizate dupa cerintele aplicatiei si ale beneficiarilor, reducand substantial efortul de programare a unor astfel de aplicatii (inclusiv editoare de texte, navigatoare pe retea si alte utilitare folosite frecvent).
O parte din clasele JFC sunt folosite ca atare (prin instantiere) iar altele asigura doar o baza pentru definirea de clase derivate.
Clase JFC pentru interfata grafica
O alta clasificare posibila a claselor Swing este urmatoarea:
- Clase JFC care au corespondent in clasele AWT, avand aproape acelasi nume (cu prefixul 'J' la clasele JFC) si acelasi mod de utilizare: JComponent, JButton, JCheckBox, JRadioButton, JMenu, JComboBox, JLabel, JList, JMenuBar, JPanel, JPopUpMenu, JScrollBar, JScrollPane, JTextField, JTextArea.
- Clase JFC noi sau extinse: JSlider, JSplitPanel, JTabbedPane, JTable, JToolBar, JTree, JProgressBar, JInternalFrame, JFileChooser, JColorChooser etc.
- Clase de tip "model", concepute conform arhitecturii MVC ("Model-View-Controller"): DefaultButtonModel, DefaultListSelectionModel, DefaultTreeModel, AbstractTableModel etc.
Clasele JFC container de nivel superior sunt numai trei: JFrame, JDialog si JApplet. Primele doua sunt subclase (indirecte) ale clasei Window din AWT.
Toate celelalte clase JFC sunt subclase directe sau indirecte ale clasei JComponent, inclusiv clasa container intermediar JPanel.
Controalele JFC pot fi inscriptionate cu text si/sau cu imagini (incarcate din fisiere GIF sau definite ca siruri de constante in program).
In jurul componentelor pot fi desenate borduri , fie pentru delimitarea lor, fie pentru crearea de spatii controlabile intre componente vecine.
Un program minimal cu clase JFC, creeaza si afiseaza componentele vizuale pe ecran, fara sa trateze evenimentele asociate acestor componente. Cea mai mare parte dintr-un astfel de program creeaza in memorie structurile de date ce contin atributele componentelor vizuale si relatiile dintre ele: se creeaza un obiect fereastra (panou), care constituie fundalul pentru celelalte componente; se creeaza componente atomice si se adauga la panou obiectele grafice create de programator (cu metoda "add").
In final, se stabilesc dimensiunile ferestrei principale (metoda "setSize" sau "pack") si se comanda afisarea ferestrei principale (metoda "setVisible" sau "show").
Fereastra principala a aplicatiei este in general de tipul JFrame si contine o bara de titlu si trei "butoane" standard in coltul dreapta-sus al ferestrei pentru operatii de micsorare (minimizare), marire (maximizare) si inchidere fereastra .
Exemplul urmator afiseaza o fereastra cu titlu, dar fara alte componente vizuale :
import javax.swing.*;
class EmptyFrame
}
Fereastra principala se afiseaza initial intr-o forma redusa la bara de titlu cu cele 3 butoane generale, dupa care poate fi marita. Pentru afisarea continutului ferestrei chiar de la inceput se poate folosi metoda "pack" (din clasa JFrame) sau metoda "setSize" (din clasa Container).
Adaugarea de componente vizuale la fereastra principala JFrame se poate face in doua moduri. In exemplul urmator se extrage 'panoul' ferestrei cu 'getContentPane' si se adauga o componenta JLabel (o eticheta) la acest panou:
import javax.swing.*;
class LabelFrame
}
In exemplul urmator se creeaza un panou JPanel, pe care se plaseaza eticheta, iar panoul este adaugat ulterior la fereastra JFrame:
// adaugare la un panou introdus apoi in obiectul JFrame
import javax.swing.*;
class LabelFrame
}
Dupa apelul metodei "setVisible" sau "show" nu mai trebuie create si adaugate alte componente vizuale ferestrei JFrame, chiar daca se modifica date prezentate in unele din aceste componente (cum ar fi JList, JTable s.a.).
Efectuarea unui clic pe butonul de inchidere al ferestrei principale (X) are ca efect inchiderea ferestrei, dar nu se termina aplicatia daca nu estre tratat evenimentul produs de acest clic. De aceea este necesara tratarea acestui eveniment, sau terminarea programului de catre operator, prin Ctrl-C. Incepand cu versiunea 1.3 mai exista o posibilitate de terminare a aplicatiei la inchiderea ferestrei principale:
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
Solutii de programare a interfetelor grafice
In general, crearea si afisarea unei interfete grafice necesita urmatoarele operatii din partea programatorului aplicatiei:
- Crearea unui obiect fereastra principala, de tip JFrame sau de un subtip al tipului JFrame, si stabilirea proprietatilor ferestrei (titlu, culoare, dimensiuni etc.)
- Crearea componentelor atomice si stabilirea proprietatilor acestora (dimensiuni, text afisat, culoare, tip chenar etc.)
- Gruparea componentelor atomice in containere intermediare, care sunt obiecte de tip JPanel sau de un subtip al acestei clase.
- Adaugarea containerelor intermediare la fereastra aplicatiei si stabilirea modului de asezare a acestora, daca nu se prefera modul implicit de dispunere in fereastra.
- Tratarea evenimentelor asociate componentelor si ferestrei principale, prin definirea de clase de tip "ascultator" la evenimentele generate de componentele vizuale.
- Afisarea ferestrei principale, prin metoda "setVisible" sau "show" a clasei JFrame.
Exemplele anterioare nu reprezinta solutia recomandata pentru programarea unei interfete grafice din urmatoarele motive:
- Variabilele referinta la obiecte JFC nu vor fi locale metodei "main" pentru ca ele sunt folosite si de alte metode, inclusiv metode activate prin evenimente.
- Metoda statica "main" trebuie redusa la crearea unui obiect si, eventual, la apelarea unei metode pentru acel obiect. Obiectul apartine unei clase definite de programator si care foloseste clasa JFrame sau JPanel.
Vom prezenta in continuare trei variante uzuale de definire a clasei GUI in cazul simplu al unui camp text insotit de o eticheta ce descrie continutul campului text.
Prima varianta foloseste o subclasa a clasei JFrame:
import javax.swing.*;
import java.awt.*;
class GUI1 extends JFrame
// initializare componente
private void init()
// activare interfata grafica
public static void main (String arg[])
}
Varianta a doua foloseste "delegarea" sarcinilor legate de afisare catre un obiect JFrame, continut de clasa GUI:
import javax.swing.*;
import java.awt.*;
class GUI2
// initializare componente
private void init()
// activare interfata grafica
public static void main (String arg[])
}
Varianta 3 defineste clasa GUI ca o subclasa a clasei JPanel:
import javax.swing.*;
class GUI3 extends JPanel
// initializare componente
private void init()
// activare interfata grafica
public static void main (String arg[])
}
Clasele ascultator la evenimente ( "TxtListener" si altele) sunt de obicei clase incluse in clasa GUI pentru a avea acces la variabilele ce definesc obiecte JFC. Daca sunt putini ascultatori, atunci clasa GUI poate implementa una sau cateva interfete de tip ascultator la evenimente si sa contina metodele de tratare a evenimentelor (dispare necesitatea unor clase ascultator separate).
Variabilele de tipuri JFC ( JLabel, JTextField, s.a) pot fi initializate la declarare sau in constructorul clasei GUI, deoarece va exista un singur obiect GUI. Metoda "init" de initializare a componentelor JFC poate lipsi daca are numai cateva linii. De observat ca pentru clasele GUI constructorul este cea mai importanta functie si uneori singura functie din clasa.
Dupa executia metodei "show" (sau "setVisible") nu se vor mai crea alte obiecte JFC (de exemplu, ca raspuns la evenimente generate de operatorul uman), deoarece ele nu vor mai fi vizibile pe ecran. In schimb, se practica modificarea continutului afisat in componentele deja existente; de exemplu, metoda "setText" din clasele JTextField si JLabel poate modifica textul afisat in astfel de componente JFC.
Dispunerea componentelor intr-un panou
Plasarea componentelor grafice pe un panou se poate face si prin pozitionare in coordonate absolute de catre programator, dar este mult mai simplu sa apelam la un obiect de control al asezarii in panou ("Layout Manager"), obiect selectat prin metoda "setLayout" si care stabileste automat dimensiunile si pozitia fiecarei componente intr-un panou. Pentru panoul de "continut" al ferestrei JFrame este activ implicit "BorderLayout", mod care foloseste un al doilea parametru in metoda "add". Daca nu se specifica pozitia la adaugare, atunci componenta este centrata in fereastra, iar daca sunt mai multe componente, atunci ele sunt suprapuse pe centrul ferestrei. Exemplu de plasare a trei butoane:
class DefaultLayout
}
De observat ca obiectul extras cu 'getContentPane' are tipul Container.
O solutie alternativa este alegerea modului de dispunere FlowLayout, care aseaza componentele una dupa alta de la stanga la dreapta si de sus in jos in functie de dimensiunile componentelor si ale ferestrei principale. Exemplu:
class FlowLayoutDemo
}
De observat ca pentru un panou JPanel asezarea implicita este FlowLayout.
Alte modalitati de dispunere a componentelor intr-un panou sunt GridLayout (o matrice de componente egale ca dimensiune), GridBagLayout, BoxLayout ( asezare compacta pe verticala sau pe orizontala, la alegere) si CardLayout ( componente / panouri care ocupa alternativ acelasi spatiu pe ecran).
Alegerea modului de dispunere depinde de specificul aplicatiei :
- In cazul unei singure componente in panou care sa foloseasca la maximum suprafata acestuia se va alege GridBagLayout sau BorderLayout : pentru o zona text sau o lista de selectie JList, de exemplu.
- In cazul a cateva componente ce trebuie sa apara in marimea lor naturala si cat mai compact se va folosi BoxLayout sau BorderLayout: pentru cateva butoane sau campuri text, de exemplu.
- In cazul mai multor componente de aceeasi marime se va folosi GridBagLayout: grupuri de butoane, de exemplu.
- In cazul unor componente de diferite dimensiuni BoxLayout sau GridBagLayout permite un control mai bun al plasarii componentelor si al intervalelor dintre ele.
Asezarea componentelor intr-un panou se poate modifica automat atunci cand se modifica dimensiunile panoului, dimensiunile sau numarul componentelor (in modul FlowLayout). Exista diverse metode de a mentine pozitia relativa a doua sau mai multe componente vizuale, indiferent de dimensiunile panoului unde sunt plasate.
De exemplu, o eticheta (obiect JLabel) trebuie sa apara intotdeauna la stanga unui camp text sau deasupra unei zone text. Acest efect se poate obtine folosind un GridLayout cu doua coloane sau un BoxLayout cu asezare pe orizontala.
Componente vizuale cu text
Un text scurt (nu mai lung de o linie) poate fi afisat in mod grafic (intr-o zona de pe ecran) folosind diverse componente vizuale: o eticheta (obiect JLabel) contine un text constant (nemodificabil din exterior), iar un camp text (obiect JTextField) contine un text si permite modificarea textului de catre operator sau prin program.
Un camp text (JTextField) permite afisarea, introducerea si editarea unei linii de text in cadrul unei ferestre text. La construirea unui obiect JTextField se foloseste ca parametru un sir de caractere sau un intreg pentru dimensiunea ferestrei text. Cele mai importante metode ale clasei JTextField sunt :
setText(String txt) // afisare text din program
getText() // citire text introdus de utilizator in camp
setEditable(boolean b) // permite sau interzice editarea de text
In exemplul urmator se foloseste un camp text (nemodificabil de la tastatura) pentru afisarea numelui directorului curent:
// afisare nume director curent
class UseTextField
}
Principala utilizare a unui camp text este pentru introducerea de date de catre operatorul aplicatiei. Pentru a informa operatorul asupra semnificatiei unui camp text se poate adauga o eticheta fiecarui camp. Exemplu de utilizare campuri text, cu etichete asociate, intr-un formular de introducere date:
class InputForm
}
Realizarea unui formular cu mai multe rubrici este in general mai complicata decat in exemplul anterior pentru ca necesita controlul dispunerii campurilor text si etichetelor asociate, folosind alte panouri si margini de separare intre aceste panouri.
O zona text (JTextArea) permite afisarea mai multor linii de text, care pot fi introduse sau modificate de la tastatura sau prin program (cu metoda "append"). Dimensiunile zonei text se stabilesc la construirea unui obiectului JTextArea. Exemplu de utilizare zona text :
public static void main ( String args [ ])
In AWT o zona text este automat plasata intr-o fereastra cu derulare pe verticala si pe orizontala, dar in JFC componenta JTextArea trebuie inclusa intr-un panou cu derulare (JScrollPane) pentru a putea aduce in fereastra vizibila elemente ce nu pot fi vazute din cauza dimensiunii limitate a zonei text. Exemplu cu o zona text pentru afisarea numelor fisierelor din directorul curent:
public static void main (String av[ ])
Operatorul poate deplasa cursorul in cadrul zonei text si poate modifica textul.
Clasele JList, JComboBox si JSpinner permit selectarea unei linii (unei optiuni) din mai multe linii afisate (simultan la JList, succesiv la JSpinner sau la cerere).
Un obiect JComboBox afiseaza pe ecran numai linia selectata, dar prin mouse se poate cere afisarea tuturor liniilor continute, pentru o alta selectie. Exemplu:
public static void main (String arg[ ]) ; // texte afisate in ComboBox
JComboBox cbox = new JComboBox(s); // creare obiect ComboBox
JLabel et = new JLabel ('Sort By: '); // o eticheta asociata
Container cp = frm.getContentPane();
cp.add (et,'West'); cp.add (cbox,'Center'); // adauga eticheta si ComboBox
frm.pack(); frm.show(); // comanda afisarea
}
Pentru ca programul sa poata reactiona la selectarea sau modificarea unor linii trebuie adaugate programelor anterioare secvente de tratare a evenimentelor produse de aceste actiuni exterioare programului. Tratarea unui eveniment se face intr-o metoda cu nume si argumente impuse (functie de tipul evenimentului), metoda inclusa intr-o clasa care implementeaza o anumita interfata (functie de eveniment).
In cazul unui panou cu mai multe componente text, cum ar fi un formular de introducere date sau o foaie de calcul, exista o singura componenta care primeste date de la tastatura; se spune ca tastatura este focalizata pe acea componenta sau ca acea componenta detine controlul tastaturii. Selectarea componentei focalizate se poate face fie prin program (metoda "requestFocus" sau "grabFocus"), fie de catre operator prin clic pe mouse dupa pozitionare pe componenta sau prin tasta Tab (care muta focalizarea pe urmatoarea componenta din fereastra). Orice obiect Swing care poate primi intrari de la tastatura ( inclusiv butoane) poate detine controlul ("focus").
Castigarea sau pierderea controlului de catre o componenta produce evenimente specifice ("FocusEvent") si apelarea de metode "focusGained" sau "focusLost".
In cazul unui formular cu multe campuri text sau al unui tabel (JTable) pierderea focalizarii poate insemna terminarea introducerii de date in acel camp sau celula si deci poate inlocui evenimentul produs de tasta Enter (terminare introducere text).
Panouri multiple
In cadrul unei ferestre principale avem urmatoarele posibilitati de lucru cu panouri:
- Panouri multiple afisate simultan, fara suprapunere intre ele.
- Panouri divizate in doua (pe orizontala sau pe verticala): JSplitPanel.
- Panouri multiple afisate succesiv in aceeasi zona ecran : JTabbedPane.
- Panouri multiple afisate simultan si partial suprapus: JLayeredPane.
In fiecare dintre panourile unei aplicatii putem avea un panou cu derulare JScrollPane.
Panourile pot fi independente unele de altele sau pot fi legate, astfel ca selectarea unui element dintr-un panou sa aiba ca efect modificarea continutului celuilalt panou.
Pentru inserarea de spatii intre panouri se pot crea margini (borduri) in jurul fiecarui panou.
Gruparea unor componente in (sub)panouri permite manipularea unui panou separat de celelalte si alegerea altui mod de dispunere in fiecare panou. Exemplu cu doua panouri independente afisate simultan
class MFrame extends JFrame
// utilizare MFrame
public static void main ( String args [])
}
Exemplul urmator afiseaza in doua panouri 'legate' doua liste de fisiere diferite, dar el poate fi modificat astfel ca in panoul din dreapta sa se afiseze continutul fisierului director selectat din lista afisata in panoul din stanga .
class SplitPane extends JFrame
public static JScrollPane dirlist (String dirname)
public static void main(String s[])
}
In exemplul urmator cele doua panouri sunt afisate alternativ, in aceeasi zona, in functie de selectia operatorului (fiecare panou are un "tab" de prindere, adica o mica portiune cu numele panoului, afisata permanent pe ecran alaturi de "tab"-urile celorlalte panouri selectabile).
class TabbedPane extends JFrame
}
Apleti Java
Cuvantul aplet ("applet") desemneaza o mica aplicatie care foloseste ecranul in mod grafic, dar care depinde de un alt program "gazda" pentru crearea fereastrei principale (care nu trebuie creata de programatorul apletului). Programul gazda este fie un program navigator ("browser"), fie programul "appletviewer", destinat vizualizarii rezultatului executiei unui aplet. Codul unui aplet (fisierul .class) poate fi adus de catre browser si de la un alt calculator decat cel pe care se executa.
Din punct de vedere sintactic un aplet este o clasa Java, derivata din clasa Applet sau din JApplet.
Clasa JApplet este indirect derivata din clasa Panel , care asigura oricarui aplet o fereastra cu butoane de inchidere, marire si micsorare. Fereastra de afisare a unui aplet nu poate fi manipulata direct de operatorul uman ci numai indirect, prin fereastra programului browser.
Programarea unei interfete grafice intr-un aplet este putin mai simpla decat intr-o aplicatie deoarece apletul mosteneste de la clasa Panel (si de la clasele Container si Component) o serie de metode utile (inclusiv metoda "windowClosing"). Exemplu de aplet scris in varianta AWT:
import java.awt.*;
import java.applet.*;
public class LabelAplet extends Applet
}
Acelasi aplet in varianta JFC arata astfel:
import javax.swing.*;
public class JAplet extends JApplet
}
Clasa JApplet este derivata din clasa Applet si permite in plus folosirea unui meniu intr-un aplet si a componentelor vizuale noi din JFC (fara echivalent in AWT).
Fisierul "class" generat de compilator pentru un aplet este specificat intr-un fisier "html", impreuna cu dimensiunile ferestrei folosite de aplet, intre marcajele <applet> si </applet>. Exemplu de fisier "html" necesar pentru executia apletului precedent:
<applet code='JAplet.class' width='250' height='100'> </applet>
In comanda "appletviewer" este specificat numele fisierului "html" si nu apare direct numele fisierului "class". Dimensiunile ferestrei folosite de aplet se dau in fisierul de tip 'html' si nu in codul Java.
Este posibil ca anumite programe de navigare mai vechi ("Browser") sa nu recunoasca clase JFC si din acest motiv s-a dat si varianta AWT pentru aplet.
De remarcat ca o clasa care corespunde unui aplet trebuie sa aiba atributul public si nu contine o metoda "main". Clasa aplet mosteneste si redefineste de obicei metodele "init", "start", 'paint' si alte cateva metode, apelate de programul gazda la producerea anumitor evenimente.
O clasa aplet poate fi transformata intr-o aplicatie prin adaugarea unei functii "main" in care se construieste un obiect JFrame, la care se adauga un obiect aplet si se apeleaza metoda "init":
public static void main (String args[ ])
O alta posibilitate este crearea unei clase separate in care se preia codul din aplet si se adauga crearea si afisarea ferestrei principale a aplicatiei (de tip JFrame). Functia "init" este inlocuita cu functia "main" la trecerea de la un aplet la o aplicatie.
Din punct de vedere functional un aplet contine cateva functii, care trebuie (re)definite de utilizator si sunt apelate de programul gazda. Un aplet care trateaza evenimente externe trebuie sa contina si metodele de tratare a evenimentelor, pentru ca nu se admit alte clase ascultator, separate de clasa aplet. Obiectul ascultator la evenimente este chiar obiectul aplet, ceea ce conduce la instructiuni de forma urmatoare
comp.addXXXListener(this); // comp este numele unei componente din aplet
Exemplul urmator este un aplet care afiseaza un buton in centrul ferestrei puse la dispozitie de programul gazda si emite un semnal sonor ('beep') la 'apasarea' pe buton, adica la actionarea butonului din stanga de pe mouse dupa mutare mouse pe zona ecran ocupata de buton.
public class Aplet extends JApplet implements ActionListener
public void actionPerformed(ActionEvent e)
}
Metoda 'init' este apelata o singura data, la incarcarea codului apletului in memorie, iar metoda 'start' este apelata de fiecare data cand programul browser readuce pe ecran pagina html care contine si marcajul <applet >. Metoda 'paint' are un parametru de tip Graphics, iar clasa Graphics contine metode pentru desenarea de figuri geometrice diverse si pentru afisarea de caractere cu diverse forme si marimi:
public void paint (Graphics g)
Politica de confidentialitate | Termeni si conditii de utilizare |
Vizualizari: 2348
Importanta:
Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved