/// <summary>
/// Automatikus Programtesztelő Kliens - Debreceni Egyetem 2009    
/// </summary>
/// <remarks>
/// Az alkalmazás megírásához felhasznált kódminták, komponensek, segédletek:
///
///     sharpSsh - A Secure Shell (SSH) library for .NET by Tamir Gal [http://www.codeproject.com/KB/IP/sharpssh.aspx?msg=3098195#xx3098195xx] [http://www.tamirgal.com/blog/page/SharpSSH.aspx]
///     Image ComboBox Control by sindhumn [http://www.codeproject.com/KB/combobox/ImageComboBoxControl.aspx]
///     Create a File Browser using C# by Abhinav Misra [http://www.dotnetspider.com/resources/23565-Create-File-Browser-using-C.aspx]
///     shellExecuteEx (shell32) Documentation [http://www.pinvoke.net/default.aspx/shell32/ShellExecuteEx.html]
///     Get all files of directory and sub directories using ASP.NET, C#, and VB.NET by Rockin J [http://www.progtalk.com/ViewArticle.aspx?ArticleID=77]
///     FtpWebRequest with ProgressBar [C# Ftp] [http://tim.mackey.ie/FtpWebRequestWithProgressBarCFtp.aspx]
///		MSDN Library [http://msdn.microsoft.com/en-us/library/default.aspx]
///		    Törlés a kukába:    http://msdn.microsoft.com/en-us/library/ms128219.aspx
///		                        http://msdn.microsoft.com/en-us/library/ms128223.aspx
/// </remarks>

#region Usings

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using prog_tesztelo.Properties;
using Tamir.SharpSsh;
using System.Linq;

#endregion

namespace prog_tesztelo
{
    #region Főbb vezérlők a formon

	/*
     * Főbb vezérlők a formon:
     *      
     *      connectButton           - Csatlakozás
     *      disconnectButton        - Kapcsolat bontása
     *      configurationButton     - Beállítások
     *      helpButton              - Súgó
     *      
     *      browserButton           - Nézetváltás tesztelés/fájlböngészés között
     *      
     *      remoteHeaderPanel       - Távoli fájlok listájának fejléce - aktuális könyvtár elérési útvonala
     *      remoteHeaderLabel       - Távoli fájlok listája fejlécének szövege
     *      remoteFilesListView     - Távoli fájlok listája - ListView - aktuális könyvtár tartalma
     *      remoteFooterLabel       - Távoli fájlok listájának lábléce - aktuálisan kijelölt fájl/könyvtár neve
     *      
     *      localHeaderPanel        - Helyi fájlok listájának fejléce - aktuális könyvtár elérési útvonala
     *      localHeaderLabel        - Helyi fájlok listája fejlécének szövege
     *      localFilesListView      - Helyi fájlok listája - ListView - aktuális könyvtár tartalma
     *      localFooterLabel        - Helyi fájlok listájának lábléce - aktuálisan kijelölt fájl/könyvtár neve
     *      
     *      groupsComboBox          - A felhasználói csoport legördülő menüje (prog1, prog2, proglab, mestint, stb.)
     *      testButton              - Tesztelés
     *      submitButton            - Beadás
     *      viewLogButton           - Naplófájl megtekintése
     *      viewSubmittedButton     - Beadott fájlok megtekintése
     *      viewTestOutButton       - Tesztelő kimenete
     *      viewResultButton        - Eredmény megtekintése
     *      
     *      testPanel               - Tesztelő felület fejléce
     *      testLabel               - Tesztelő felület fejlécének szövege
     * 
     *      mainTextBox             - Szerver kimenetét megjelenítő textbox
     *      excName1Label           - Feladatsor:
     *      excNum1TextBox          - Feladatsor száma
     *      excName2Label           - Feladat:
     *      excNum2TextBox          - Feladat száma
     * 
	 *		errorMessageStatusLabel	- Hibaüzeneteket tartalmazó lábléc
	 * 
     *      renameButton            - Átnevezés [F2]
     *      viewButton              - Nézőke [F3]
     *      editButton              - Szerkesztés [F4]
     *      copyButton              - Másolás [F5]
     *      mkdirButton             - Új könyvtár [F7]
     *      deleteButton            - Törlés [F8]
     *      
     *      gotoHomeButton          - Munkakönyvtár
     *      gotoSubmittedButton     - Beadott fájlok
     *      gotoJuryButton          - Zsűri
     *      gotoTestButton          - Tesztesetek
     * 
     */

	#endregion

	#region Delegátusok

	/// <summary>
    /// Delegátus a Csatlakozás adatainak kinyerésére
	/// </summary>
	/// <param name="host">A távoli szerver címe</param>
	/// <param name="password">A beírt felhasználói név</param>
	/// <param name="username">A beírt jelszó</param>
	/// <remarks>
	///	A csatlakozási adatokat az alkalmazás bezárásáig megtartjuk, hogy az újracsatlakozást megkönnyítsük a felhasználóknak
	/// </remarks>
    public delegate void ConnectDataDelegate(string host, string username, string password);

    /// <summary>
    /// Delegátus a rejtett fájlok megjelenítésének lekéréséhez a Beállítások menüpont alatt
	/// </summary>
	/// <param name="hiddenFiles">értéke alapján jelenítjük meg/rejtjük el a rejtett állományokat az állománylistában</param>
    public delegate void ConfigurationDelegate(bool hiddenFiles);

    /// <summary>
    /// Delegátus a fájltranszfer nyomonkövetésére a Nézőke/Szerkesztés funkciók alkalmazása során
	/// </summary>
	/// <param name="edit">értéke jelzi, hogy a letöltés sikeres volt-e</param>
	/// <param name="settings">értéke jelzi, hogy szerkesztésre nyitjuk-e meg a fájlt</param>
	/// <param name="success">a letöltendő/szerkesztendő fájl adatait tartalmazó objektum</param>
    public delegate void DownloadDelegate(bool success, bool edit, ViewerSettings settings);

    /// <summary>
    /// Delegátus a szerkesztett fájl feltöltéséhez
	/// <summary>
    /// <paraparam name="settings">a szerkesztett fájl adatait tartalmazó objektum</paraparam>
    public delegate void UploadDelegate(ViewerSettings settings);

	/// <summary>
	/// Delegátus a szerveren tárolt állomány tulajdonságainak megváltoztatásához
	/// </summary>
	/// <param name="item">az aktuális fájl neve, amelynek a tulajdonságait szeretnénk beállítani</param>
    public delegate void PropertiesDelegate(string item);

	/// <summary>
	/// A kijelölt állomány átnevezéséhez szükséges delegátus
	/// </summary>
	/// <param name="item">az átnevezendő fájl</param>
	/// <param name="isLocal">igaz érték esetén a felhasználó számítógépén, hamis érték esetén a szerveren nevezzük át az első paraméterként kapott állományt</param>
    public delegate void RenameDelegate(string item, bool isLocal);

	/// <summary>
	/// Új fájl/könyvtár létrehozásához szükséges delegátus
	/// </summary>
	/// <param name="name">az új fájl/könyvtár neve</param>
	/// <param name="isLocal">igaz érték esetén a felhasználó számítógépén, hamis érték esetén a szerveren hozzuk létre az első paraméterben megadott fájl/könyvtárat</param>
	/// <param name="isFile">igaz érték esetén fájlt, hamis érték esetén könyvtárat hozunk létre</param>
    public delegate void NewFileDelegate(string name, bool isLocal, bool isFile);

	/// <summary>
	/// A törlés végrehajtásához szükséges delegátus
	/// </summary>
	/// <param name="isLocal">igaz érték esetén a felhasználó számítógépén, hamis érték esetén a szerveren történik a törlés</param>
    public delegate void RefreshDelegate();

    #endregion

    public partial class MainForm : Form
    {
        #region Adattagok

        public static string form_title = "Automatikus Programtesztelő Kliens 1.5.1";		// a form címe
        private const int FORM_WIDTH = 950;													// a form szélessége
		private const int FORM_HEIGHT = 650;                                       			// a form magassága
		private bool fileTransferMode = false;                                      		// a fájlböngésző és a tesztelő nézet közötti váltás figyelésére szolgál
		private Double splitter_distance = 0;                                       		// a két panel szélességének aránya
		private SshShell ssh;                                                       		// az SshShell osztály látja el a SecureShell protokoll implementálását az alkalmazásba
		private static string pattern = string.Empty;                               		// a minta, ami a szerver válaszának végét jelzi - értéke a config.ini-ben található
		private static string server = string.Empty;                                		// a szerver címe - értéke a config.ini-ben található
		private static SortedList configTabe = null;                                		// a konfigurációs fájl tartalmát egy listában tároljuk az egyszerűbb kezelhetőség érdekében
		private static List<Subject> subjects = null;										// a választható tárgyak listája
		private static bool hiddenFiles = false;                                    		// rejtett fájlok megjelenítése - az értékét az alkalmazás Settings-fájljában tároljuk
		private static string remoteFileName = string.Empty;                        		// a szerkesztésre aktuálisan megnyitott fájl
		private static string tempFileName = string.Empty;                          		// a lementett fájl átmeneti neve -  a fájlt az alkalmazás Temp könyvtárában helyezzük el
		private static ListViewItem selected = null;                                		// a kijelölt elem a listviewben
		private static string attr = string.Empty;                                  		// a kijelölt fájl/könyvtár neve, amelyet átadunk a delegátus függvénynek - fájl/könyvtár tulajdonságai
		private static string actAttr = string.Empty;                               		// a kijelölt fájl/könyvtár aktuális attribútuma - fájl/könyvtár tulajdonságai
		private static string actName = string.Empty;                               		// a kijelölt fájl/könyvtár neve - az átnevezéshez
		private ConnectForm connectForm = null;                                     		// a bejelentkező adatokat összegyűjtő form
		private ViewerSettings settings = null;                                     		// az aktuális fájlinformációk
		BackgroundWorker bw = null;                                                 		// a csatlakozási folyamathoz szükséges backgroundworker

		private string host = string.Empty;													// bejelentkezési adatok
		private string user = string.Empty;
		private string pass = string.Empty;

        private const string PROG_LOG = "teszt.log";										// naplófájl neve
        private const string PROG_OUT = "teszt.out";										// fordító kimenete
		private static string S = Path.DirectorySeparatorChar.ToString();					// a könyvtár elválasztó karaktere
		public static string NOTEPAD =                                              		// az alapértelmezett nézőke/szerkesztő a windows notepade
			Environment.GetEnvironmentVariable("windir", EnvironmentVariableTarget.Machine) + S + "notepad.exe";
		public static string WORKSPACE =													// az alapértelmezett munkakönyvtár a felhasználó számítógépén
			Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
		private static string TEMP_PATH = Path.Combine(Path.GetTempPath(), "apk_temp");		// az átmeneti fájlok helye

		private static Color COLOR1 = Color.Black;											// a program alapszínei
		private static Color COLOR2 = Color.White;
		private static Color COLOR3 = Color.FromArgb( 243, 130, 26 );
		private static Color COLOR4 = Color.FromArgb( 221, 118, 24 );
		private static Color COLOR5 = Color.FromArgb( 128, 128, 128 );

        private bool remoteFilesListViewFocused = true;										// a két panel közötti fókusz követése
        private bool localFilesListViewFocused = false;

        private ListViewSorter lvSorter;                                                      // ListViewSorter
        private ListView actListView;

        #endregion

        #region Konstruktor

		/// <summary>
		/// Az alkalmazás fő formjának példányosítása, a tulajdonságok beállítása
		/// </summary>
		/// <remarks>
		/// A fő tartalmi elemeket elrejtjük a felhasználó szeme elől, amíg be nem jelentkezik.
		/// Az alkalmazás futtatásához legalább 1024*768-as felbontás szükséges, ennél kisebb felbontásnál nem indul el a program.
		/// Ha a program által használt átmeneti könyvtár nem hozható létre akkor a program nem indul el.
		/// Ha a konfigurációs állományok nem olvashatók be, akkor az alkalmazás nem futtatható.
		/// </remarks>
        public MainForm()
        {
            #region Konfigurációs beállítások

            try
            {
				InitializeComponent();

				this.StartPosition = FormStartPosition.CenterScreen;

                // Az alkalmazás megnyitásakor a fő vezérlőelemeket elrejtjük, míg a felhasználó be nem jelentkezik
                ExceptionHandler();
            }
            catch (Exception)
			{
				Environment.Exit(-1);
			}

			// Képernyőfelbontás detektálása - 1024*768-as felbontás alatt nem indul el a program
			if (Screen.PrimaryScreen.Bounds.Width < 1024 || Screen.PrimaryScreen.Bounds.Height < 768)
			{
				MessageBox.Show("A program futtatásához legalább 1024*768-as felbontás szükséges!");
				Environment.Exit(-1);
			}

            try
            {
                // Temp könyvtár létrehozása az átmeneti fájlok tárolásához
                if (!Directory.Exists(TEMP_PATH))
                {
					Directory.CreateDirectory(TEMP_PATH);
                }
            }
            catch (Exception)
            {
				MessageBox.Show("Nem hozható létre a következő könyvtár: " + TEMP_PATH);
                Environment.Exit(-1);
            }

            try
            {
                // Konfigurációs fájl tartalmának beolvasása
                // Beolvassuk és feldolgozzuk a fájl tartalmát
                Stream s = new FileStream(Path.Combine(Application.StartupPath, "config.ini"), FileMode.Open, FileAccess.Read, FileShare.Read);

                if (!s.CanRead)
                {
                    MessageBox.Show("Hiba a konfigurációs fájl beolvasása során.");
                    Environment.Exit(-1);
                }

                StreamReader sr = new StreamReader(s);
                string actLine = string.Empty;          // az aktuálisan beolvasott sor
                string[] keyValue = null;               // az aktuálisan beolvasott kulcs-érték pár

                configTabe = new SortedList();

                while (sr.Peek() != -1)
                {
                    actLine = sr.ReadLine();

                    // ha üres sort vagy kommentet találunk, továbblépünk
                    if ((keyValue = actLine.Split('=')).Length != 2 || actLine.Trim().Substring(0, 1) == ";" || actLine.Trim() == String.Empty)
                    {
                        continue;
                    }
                    // eltávolítjuk a felesleges szóközöket, és hozzáadjuk a listához
                    else
                    {
                        configTabe.Add(keyValue[0].Trim(), keyValue[1].Trim());
                    }
                }

                // a szerver címének beolvasása
                if (configTabe.ContainsKey("server"))
                {
                    server = configTabe.GetByIndex(configTabe.IndexOfKey("server")).ToString();
                }
                else
                {
                    // Ha nem található meg a szerver címe a konfigurációs fájlban, akkor hibaüzenettel leáll a program
                    MessageBox.Show("Hibás konfigurációs fájl.");
                    Environment.Exit(-1);
                }

                // a minta beolvasása
                if (configTabe.ContainsKey("pattern"))
                {
                    // Ha nem található meg a minta címe a konfigurációs fájlban, akkor hibaüzenettel leáll a program
                    pattern = configTabe.GetByIndex(configTabe.IndexOfKey("pattern")).ToString();
                }
                else
                {
                    MessageBox.Show("Hibás konfigurációs fájl.");
                    Environment.Exit(-1);
                }

                sr.Close();
                s.Close();
            }
            catch (Exception)
            {
                MessageBox.Show("Hiba a konfigurációs fájl beolvasása során.");
                Environment.Exit(-1);
            }

			try
			{
				subjects = new List<Subject>();

				foreach (string file in Directory.GetFiles(Path.Combine(Application.StartupPath, "Subjects")))
				{
					if (!(new FileInfo(file)).Extension.ToLower().Equals(".ini"))
					{
						continue;
					}
					Stream s = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read);

					if (!s.CanRead)
					{
						continue;
					}

					StreamReader sr = new StreamReader(s);
					string actLine = string.Empty;          // az aktuálisan beolvasott sor
					string a_targy_nev = string.Empty, a_zsuri = string.Empty, a_feladat = string.Empty, a_tesztesetek = string.Empty, a_beadott_fajlok = string.Empty, a_bead = string.Empty, a_beadva = string.Empty, a_eredmeny = string.Empty, a_tesztel = string.Empty;
					string[] keyValue = null;               // az aktuálisan beolvasott kulcs-érték pár
					SortedList subjectValues = new SortedList();

					while (sr.Peek() != -1)
					{
						actLine = sr.ReadLine();

						// ha üres sort vagy kommentet találunk, továbblépünk
						if ((keyValue = actLine.Split('=')).Length != 2 || actLine.Trim().Substring(0, 1) == ";" || actLine.Trim() == String.Empty)
						{
							continue;
						}
						// eltávolítjuk a felesleges szóközöket, és hozzáadjuk a listához
						else
						{
							subjectValues.Add(keyValue[0].Trim(), keyValue[1].Trim());
						}
					}

					a_targy_nev = ((subjectValues.ContainsKey("targy_nev")) ? subjectValues.GetByIndex(subjectValues.IndexOfKey("targy_nev")).ToString() : string.Empty);
					a_zsuri = ((subjectValues.ContainsKey("zsuri")) ? subjectValues.GetByIndex(subjectValues.IndexOfKey("zsuri")).ToString() : string.Empty);
					a_feladat = ((subjectValues.ContainsKey("feladat")) ? subjectValues.GetByIndex(subjectValues.IndexOfKey("feladat")).ToString() : string.Empty);
					a_tesztesetek = ((subjectValues.ContainsKey("tesztesetek")) ? subjectValues.GetByIndex(subjectValues.IndexOfKey("tesztesetek")).ToString() : string.Empty);
					a_beadott_fajlok = ((subjectValues.ContainsKey("beadott_fajlok")) ? subjectValues.GetByIndex(subjectValues.IndexOfKey("beadott_fajlok")).ToString() : string.Empty);
					a_bead = ((subjectValues.ContainsKey("bead")) ? subjectValues.GetByIndex(subjectValues.IndexOfKey("bead")).ToString() : string.Empty);
					a_beadva = ((subjectValues.ContainsKey("beadva")) ? subjectValues.GetByIndex(subjectValues.IndexOfKey("beadva")).ToString() : string.Empty);
					a_eredmeny = ((subjectValues.ContainsKey("eredmeny")) ? subjectValues.GetByIndex(subjectValues.IndexOfKey("eredmeny")).ToString() : string.Empty);
					a_tesztel = ((subjectValues.ContainsKey("tesztel")) ? subjectValues.GetByIndex(subjectValues.IndexOfKey("tesztel")).ToString() : string.Empty);
					
					if ( a_targy_nev != string.Empty )
					{
						subjects.Add( new Subject( a_targy_nev, a_zsuri, a_feladat, a_tesztesetek, a_beadott_fajlok, a_bead, a_beadva, a_eredmeny, a_tesztel ) );
					}

					sr.Close();
					s.Close();
				}
			}
			catch (Exception)
			{
				MessageBox.Show("Hiba a konfigurációs állományok beolvasása során.");
                Environment.Exit(-1);
			}

            try
            {
				// a beállításokat (nézőke, szerkesztő, munkakönyvtár), amennyiben nem léteznek vagy helytelenek, alapértelmezettre állítjuk
                if (Settings.Default.editor == string.Empty || !File.Exists(Settings.Default.editor))
                {
					Settings.Default.editor = NOTEPAD;
                }
				if (Settings.Default.viewer.Trim() == string.Empty || !File.Exists(Settings.Default.viewer))
				{
					Settings.Default.viewer = NOTEPAD;
				}
				if (Settings.Default.workingdir.Trim() == string.Empty || !Directory.Exists(Settings.Default.workingdir))
				{
					Settings.Default.workingdir = WORKSPACE;
				}
				Settings.Default.Save();
            }
            catch (Exception)
			{
				MessageBox.Show( "Hiba a programbeállítások feldolgozása során." );
				Environment.Exit( -1 );
			}

            #endregion

            #region ListViewSorter beállítása
            
            lvSorter = new ListViewSorter();
            localFilesListView.ListViewItemSorter = lvSorter;
            remoteFilesListView.ListViewItemSorter = lvSorter;

            #endregion
        }

        #endregion

        #region Form betöltődése

		/// <summary>
		/// A form betöltődésekor beállítjuk a főbb vezérlők alapértelmezett tulajdonságait,
		/// beállítjuk a színeket és beállítjuk a fájllisták tartalmát
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void MainForm_Load(object sender, EventArgs e)
        {
            #region GIU alapbeállításai

            this.Text = form_title;                                                         // beállítjuk a form címét
            this.Width = FORM_WIDTH;														// beállítjuk a form szélességét és magasságát
            this.Height = FORM_HEIGHT;
			testLabel.Text = form_title;													// a tesztelő felület fejlécének szövege kezdetben a form címe lesz
            errorMessageStatusLabel.Text = string.Empty;									// a lábléc kezdetben üres

			this.DoubleBuffered = true;

            mainTextBox.Width = 517;														// beállítjuk a szerver válaszát tartalmazó textbox szélességét és magasságát
            mainTextBox.Height = splitContainer1.Height - 227;
            mainTextBox.ScrollBars = ScrollBars.None;                                       // a textboxnak kezdetben nincsenek gördítősávjai
            mainTextBox.ReadOnly = true;                                                    // a textbox tartalma nem szerkeszthető, csak olvasható

            remoteFilesListView.GotFocus += new EventHandler(remoteFilesListView_GotFocus);
            localFilesListView.GotFocus += new EventHandler(localFilesListView_GotFocus);

            this.splitContainer1.SplitterDistance = this.Width - mainTextBox.Width - 20;	// beállítjuk a splitcontainer kezdeti paramétereit
            this.splitContainer1.IsSplitterFixed = true;
            this.splitContainer1.Panel1MinSize = 159;
            this.splitContainer1.Panel2MinSize = 154;

            localFilesListView.Visible = false;												// kezdetben a tesztelő nézetet jelenítjük meg, így a helyi gépen tárolt információk nem jelennek meg
            localFooterLabel.Visible = false;
            localHeaderLabel.Visible = false;
            localHeaderPanel.Visible = false;
			localCheckAll.Visible = false;
			localUncheckAll.Visible = false;
			localDrivesComboBox.Visible = false;

            fileTransferMode = false;														// induláskor a tesztelő nézetet jelenítjük meg

            copyButton.Enabled = false;														// a másolás, a beadott fájlokhoz és a tesztesetekhez ugrás tesztelő nézetben nem lehetséges
            gotoSubmittedButton.Enabled = true;
            gotoTestButton.Enabled = true;

            groupsComboBox.Left = this.Width - (browserButton.Width + groupsComboBox.Width) - 20;

            enableChange(connectButton, true);                                              // a 'Csatlakozás' gombot láthatóvá tesszük
            enableChange(disconnectButton, false);                                          // a 'Kapcsolat bontása' gombot inaktívvá tesszük
            remoteFooterLabel.Text = string.Empty;                                          // a textboxban aktuálisan kijelölt fájl/könyvtár neve
			remoteHeaderLabel.Text = string.Empty;
            localFooterLabel.Text = string.Empty;                                           // a textboxban aktuálisan kijelölt fájl/könyvtár neve
            localHeaderLabel.Text = string.Empty;
            hiddenFiles = Settings.Default.hidden_files;                                    // beállítjuk a rejtett fájlok megjelenítését jelző változót
            errorMessageStatusLabel.Text = string.Empty;                                    // lábléc szövege

            remoteFilesListView.ForeColor = COLOR1;											// beállítjuk a színeket
            localFilesListView.ForeColor = COLOR1;
			testPanel.ForeColor = COLOR2;
			testPanel.BackColor = COLOR5;
			changeColor(false);

			remoteFilesListView.Focus();													// a fókuszt a szerver fájllistájára állítjuk

            #region TabStop beállítása az összes vezérlőn, kivéve a két listview-t

			// a legtöbb vezérlőn a TabStop tulajdonságot hamisra állítjuk,
			// hogy csak a két listview között tudjunk nézetet váltani, mint a legtöbb fájlkezelőben

            this.menuStrip1.TabStop = false;
            this.statusStrip1.TabStop = false;
            this.splitContainer1.TabStop = false;
            this.remoteUncheckAll.TabStop = false;
            this.remoteCheckAll.TabStop = false;
            this.remoteFooterLabel.TabStop = false;
            this.contextMenuStrip1.TabStop = false;
            this.remoteHeaderPanel.TabStop = false;
            this.remoteDrivesComboBox.TabStop = false;
            this.remoteHeaderLabel.TabStop = false;
            this.localUncheckAll.TabStop = false;
            this.localCheckAll.TabStop = false;
            this.mainTextBox.TabStop = false;
            this.testButtonsPanel.TabStop = false;
            this.viewResultButton.TabStop = false;
            this.viewSubmittedButton.TabStop = false;
            this.viewTestOutButton.TabStop = false;
            this.viewLogButton.TabStop = false;
            this.submitButton.TabStop = false;
            this.testButton.TabStop = false;
            this.excNum2TextBox.TabStop = false;
            this.excNum1TextBox.TabStop = false;
            this.excName2Label.TabStop = false;
            this.excName1Label.TabStop = false;
            this.testPanel.TabStop = false;
            this.testLabel.TabStop = false;
            this.localFooterLabel.TabStop = false;
            this.localHeaderPanel.TabStop = false;
            this.localDrivesComboBox.TabStop = false;
            this.localHeaderLabel.TabStop = false;
            this.renameButton.TabStop = false;
            this.viewButton.TabStop = false;
            this.editButton.TabStop = false;
            this.copyButton.TabStop = false;
            this.mkdirButton.TabStop = false;
            this.deleteButton.TabStop = false;
            this.gotoHomeButton.TabStop = false;
            this.gotoJuryButton.TabStop = false;
            this.gotoTestButton.TabStop = false;
            this.gotoSubmittedButton.TabStop = false;
            this.splitContainer2.TabStop = false;
            this.panel1.TabStop = false;
            this.panel2.TabStop = false;
            this.groupsComboBox.TabStop = false;
            this.remoteFilesListView.TabStop = true;
            this.localFilesListView.TabStop = true;

            #endregion

            #endregion

            // A form betöltésekor feltöltjük a felhasználó számítógépén található meghajtók listáját és megjelenítjük az első meghajtó tartalmát
            loadLocalDrives();
            displayFolders();
        }

        #endregion

        #region Nézetváltás beállításai (fájlböngésző/tesztelő nézet)

        /// <summary>
		/// Nézetváltás a 'Tesztelő / Fájlböngésző nézet' között
        /// </summary>
		/// <remarks>
		/// Amikor a Tesztelő nézet aktív, Fájlböngésző nézetre váltunk, 
		/// amikor a Fájlböngésző nézet aktív, akkor pedig Tesztelő nézetre váltunk,
		/// és ennek megfelelően állítjuk át az érintett vezérlők láthatóságát és egyéb paramétereit
		/// </remarks>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void browserButton_Click(object sender, EventArgs e)
        {
			// a nézetfigyelő változót átállítjuk az ellenkezőjére
            fileTransferMode = !fileTransferMode;

			// az érintett vezérlők láthatóságát az ellenkezőjére állítjuk
            testButtonsPanel.Visible = !testButtonsPanel.Visible;
            testPanel.Visible = !testPanel.Visible;
            mainTextBox.Visible = !mainTextBox.Visible;
            splitContainer1.IsSplitterFixed = !this.splitContainer1.IsSplitterFixed;

            localFilesListView.Visible = !localFilesListView.Visible;
            localFooterLabel.Visible = !localFooterLabel.Visible;
            localHeaderLabel.Visible = !localHeaderLabel.Visible;
            localHeaderPanel.Visible = !localHeaderPanel.Visible;

            localCheckAll.Visible = !localCheckAll.Visible;
            localUncheckAll.Visible = !localUncheckAll.Visible;

			// nézettől függően beállítjuk a 'browserButton' szövegét, a 'splitter' helyzetét
			// a másolás csak fájlböngésző nézetben, a beadott fájlok könyvtárába ugrás és a tesztesetek könyvtárába ugrás csak tesztelő nézetben érhető el
            if (fileTransferMode)
            {
                browserButton.Text = "Fájlböngésző nézet";
				splitContainer1.SplitterDistance = (splitter_distance != 0 ? Convert.ToInt32(this.Width * splitter_distance) : Convert.ToInt32(Convert.ToDouble(this.Width) / 2 - Convert.ToDouble(splitContainer1.SplitterWidth) / 2));
                copyButton.Enabled = true;
                gotoSubmittedButton.Enabled = false;
                gotoTestButton.Enabled = false;
                localDrivesComboBox.Visible = true;
            }
            else
            {
                browserButton.Text = "Tesztelő nézet";
                splitContainer1.SplitterDistance = this.Width - mainTextBox.Width - 20;
                copyButton.Enabled = false;
				gotoSubmittedButton.Enabled = (subjects[groupsComboBox.SelectedIndex].Beadott_fajlok != string.Empty ? true : false);
				gotoTestButton.Enabled = (subjects[groupsComboBox.SelectedIndex].Tesztesetek != string.Empty ? true : false);
                localDrivesComboBox.Visible = false;

				changeColor(false);
            }
        }

		/// <summary>
		/// A form átméretezése során beállítjuk a két listView, a linkek, a textbox-ok és combobox-ok pozícióját, 
		/// illetve fájlböngésző módban a splitter pozícióját a 'splitter_distance' változóba elmentett érték 
		/// alapján módosítjuk, hogy a két panel aránya ugyanaz maradjon a nézetváltás után
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void MainForm_Resize(object sender, EventArgs e)
        {
            remoteFilesListView.Height = this.Height - 190;
            localFilesListView.Height = this.Height - 190;
            mainTextBox.Height = splitContainer1.Height - 163;
            groupsComboBox.Left = this.Width - (browserButton.Width + groupsComboBox.Width) - 20;

            localFooterLabel.Top = localFilesListView.Location.Y + localFilesListView.Height + 1;

            remoteCheckAll.Top = remoteUncheckAll.Top = remoteFooterLabel.Top + 5;
            localCheckAll.Top = localUncheckAll.Top = localFooterLabel.Top + 5;

            if (this.WindowState != FormWindowState.Minimized)
            {
				splitContainer1.SplitterDistance = ( fileTransferMode ? Convert.ToInt32(this.Width * splitter_distance) : this.Width - mainTextBox.Width - 20);
            }
        }

        /// <summary>
		/// A nézetváltó gomb szövegének (így szélességének) megváltozása esetén a legördülő menü pozícióját az új szélességnek megfelelően csúsztatjuk el
        /// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void browserButton_TextChanged(object sender, EventArgs e)
        {
            groupsComboBox.Left = this.Width - (browserButton.Width + groupsComboBox.Width) - 20;
        }

        /// <summary>
		/// Fájlböngésző nézetben a splitContainer1 elválasztó mezőjének mozgatása során a 'splitter_distance' 
		/// változóba mentjük el a splitter helyzetét, amit az ablak átméretezése során használunk fel 
		/// a két panel arányának megtartásához
        /// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e)
        {
				if ( fileTransferMode )
				{
					try
					{
						splitter_distance = ( Convert.ToDouble( splitContainer1.SplitterDistance ) / Convert.ToDouble( this.Width ) );
					}
					catch ( Exception )
					{
						splitter_distance = 0.5;
					}
				}
        }

        /// <summary>
		/// Fájlböngésző nézetben a splitContainer1 splitterére történő dupla klikk hatására
		/// a két panel 50%-50% százalékos szélességű lesz
        /// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void splitContainer1_DoubleClick(object sender, EventArgs e)
        {
            if (fileTransferMode)
            {
				splitContainer1.SplitterDistance = Convert.ToInt32( Convert.ToDouble( this.Width ) / 2 - Convert.ToDouble( splitContainer1.SplitterWidth ) / 2 );
            }
        }

		/// <summary>
		/// Nézet- és fókuszváltás esetén a vezérlők színeinek beállítása
		/// </summary>
		/// <param name="reverse">igaz érték esetén a fejlécek színét az inverzére változtatjuk</param>
		private void changeColor(bool reverse)
		{
			localHeaderLabel.ForeColor = (reverse ? COLOR2 : COLOR1);
			remoteHeaderLabel.ForeColor = (reverse ? COLOR1 : COLOR2);
			localHeaderPanel.BackColor = (reverse ? COLOR4 : COLOR3);
			remoteHeaderPanel.BackColor = (reverse ? COLOR3 : COLOR4);
		}

        #endregion

        #region Beolvasás

		/// <summary>
		/// Segédmetódus a szerver válaszának beolvasására
		/// </summary>
		/// <returns>a szerver válasza</returns>
        private string read()
        {
            try
            {
                return ssh.Expect(pattern).Trim();
            }
            catch (Exception)
            {
                textWriter(testLabel, "Hiba");
				ExceptionHandler();
                return "Hiba a szerver üzenetének feldolgozása során.";
            }
        }

		/// <summary>
		/// Segédmetódus a szerver válaszának beolvasására - a shell prompt és a parancs nélkül
		/// </summary>
		/// <returns>a szerver válasza a két szélső sor nélkül</returns>
        private string readText()
        {
            try
            {
                return trimLines(ssh.Expect(pattern).Trim(), 1, 1);
            }
            catch (Exception)
            {
				ExceptionHandler();
                textWriter(testLabel, "Hiba");
				return "Hiba a szerver üzenetének feldolgozása során.";
            }
        }

		/// <summary>
		/// Az első paraméterben megadott sztring elejéről és végéről a második és harmadik paraméterként megadott számú sort eltávolítunk
		/// </summary>
		/// <param name="content">a sztring amelyen a műveletet végezzük el</param>
		/// <param name="firstline">értéke megadja, hogy az első paraméterként megadott sztring elejéről mennyi sort távolítsunk el</param>
		/// <param name="lastline">értéke megadja, hogy az első paraméterként megadott sztring végéről mennyi sort távolítsunk el</param>
		/// <returns>helyes futás esetén a módosított szöveg, hiba esetén az eredeti tartalom</returns>
        private string trimLines(string content, int firstline, int lastline)
        {
            try
            {
                StringReader reader = new StringReader(content);
                string response = string.Empty;
                ArrayList list = new ArrayList();

                while (reader.Peek() != -1)
                {
                    list.Add(reader.ReadLine());
                }
                for (int j = firstline; j < list.Count - lastline; j++)
                {
                    response += list[j] + "\r\n";
                }
                return response;
            }
            catch (Exception)
            {
                return content;
            }
        }

        #endregion

        #region Csatlakozás a szerverhez

		/// <summary>
		/// A ConnectDataDelegate delegátus callback függvénye
		/// </summary>
		/// <remarks>
		/// A megadott paraméterekkel a háttérben futó szálon elvégezzük a kapcsolódást a 'bw' BakcgroundWorker segítségével,
		/// aszinkron módon, hogy a művelet végrehajtása ne blokkolja a fő form működését
		/// </remarks>
		/// <param name="serverAddress">a beállított szerver címe</param>
		/// <param name="username">a megadott felhasználói név</param>
		/// <param name="password">a megadott jelszó</param>
        private void ConnectDataCallbackFn(string serverAddress, string username, string password)
        {
			// a fókuszt a fájllistára állítjuk
			remoteFilesListView.Focus();

			// beállítjuk a BackgroundWorker tulajdonságait
            bw = new BackgroundWorker(){ WorkerSupportsCancellation = true };
            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.RunWorkerAsync(serverAddress + "|" + username + "|" + password);
        }

        #region Invoke metódusok a szálbiztos adatmódosításhoz

		/// <summary>
		/// Az első paraméterként megadott Label vezérlő Text tulajdonságának szálbiztos megváltoztatása
		/// </summary>
		/// <param name="label"></param>
		/// <param name="message"></param>
        private void textWriter(Label label, string message)
        {
            if (label.InvokeRequired)
            {
                label.Invoke((MethodInvoker)delegate(){ label.Text = message; });
            }
            else
            {
                label.Text = message;
            }
        }

		/// <summary>
		/// Az első paraméterként megadott ToolStripStatusLabel vezérlő Text tulajdonságának szálbiztos megváltoztatása
		/// </summary>
		/// <param name="label"></param>
		/// <param name="message"></param>
        private void textWriter(ToolStripStatusLabel toolStripStatusLabel, string message)
        {
            toolStripStatusLabel.Text = message;
        }

		/// <summary>
		/// Az első paraméterként megadott TextBox vezérlő Text tulajdonságának szálbiztos megváltoztatása
		/// </summary>
		/// <param name="textbox"></param>
		/// <param name="message"></param>
        private void textWriter(TextBox textbox, string message)
        {
            if (textbox.InvokeRequired)
            {
                textbox.Invoke((MethodInvoker)delegate(){ textbox.Text = message; });
            }
            else
            {
                textbox.Text = message;
            }
        }

		/// <summary>
		/// Az első paraméterként megadott Button vezérlő Enabled tulajdonságának szálbiztos megváltoztatása
		/// </summary>
		/// <param name="button"></param>
		/// <param name="value"></param>
        private void enableChange(Button button, bool value)
        {
            if (button.InvokeRequired)
            {
                button.Invoke((MethodInvoker)delegate() { button.Enabled = value; });
            }
            else
            {
                button.Enabled = value;
            }
        }

		/// <summary>
		/// Az első paraméterként megadott ComboBox vezérlő Enabled tulajdonságának szálbiztos megváltoztatása
		/// </summary>
		/// <param name="combobox"></param>
		/// <param name="value"></param>
        private void enableChange(ComboBox combobox, bool value)
        {
            if (combobox.InvokeRequired)
            {
                combobox.Invoke((MethodInvoker)delegate() { combobox.Enabled = value; });
            }
            else
            {
                combobox.Enabled = value;
            }
        }

		/// <summary>
		/// Az első paraméterként megadott Panel vezérlő Visible tulajdonságának szálbiztos megváltoztatása
		/// </summary>
		/// <param name="panel"></param>
		/// <param name="value"></param>
        private void visibleChange(Panel panel, bool value)
        {
            if (panel.InvokeRequired)
            {
                panel.Invoke((MethodInvoker)delegate() { panel.Visible = value; });
            }
            else
            {
                panel.Visible = value;
            }
        }

		/// <summary>
		/// Az első paraméterként megadott SplitContainer vezérlő Visible tulajdonságának szálbiztos megváltoztatása
		/// </summary>
		/// <param name="container"></param>
		/// <param name="value"></param>
        private void visibleChange(SplitContainer splitContainer, bool value)
        {
            if (splitContainer.InvokeRequired)
            {
                splitContainer.Invoke((MethodInvoker)delegate() { splitContainer.Visible = value; });
            }
            else
            {
                splitContainer.Visible = value;
            }
        }

		/// <summary>
		/// Az első paraméterként megadott Button vezérlő Visible tulajdonságának szálbiztos megváltoztatása
		/// </summary>
		/// <param name="button"></param>
		/// <param name="value"></param>
        private void visibleChange(Button button, bool value)
        {
            if (button.InvokeRequired)
            {
                button.Invoke((MethodInvoker)delegate() { button.Visible = value; });
            }
            else
            {
                button.Visible = value;
            }
        }

		/// <summary>
		/// Az első paraméterként megadott ToolStripMenuItem vezérlő Enabled tulajdonságának szálbiztos megváltoztatása
		/// </summary>
		/// <param name="button"></param>
		/// <param name="value"></param>
        private void enableChange(ToolStripMenuItem toolStripMenuItem, bool value)
        {
            if (toolStripMenuItem.Owner.InvokeRequired)
            {
                toolStripMenuItem.Owner.Invoke((MethodInvoker)delegate() { toolStripMenuItem.Enabled = value; });
            }
            else
            {
                toolStripMenuItem.Enabled = value;
            }
        }

		/// <summary>
		/// Az első paraméterként megadott ToolStripSplitButton vezérlő Enabled tulajdonságának szálbiztos megváltoztatása
		/// </summary>
		/// <param name="button"></param>
		/// <param name="value"></param>
        private void enableChange(ToolStripSplitButton toolStripSplitButton, bool value)
        {
            if (toolStripSplitButton.Owner.InvokeRequired)
            {
                toolStripSplitButton.Owner.Invoke((MethodInvoker)delegate() { toolStripSplitButton.Enabled = value; });
            }
            else
            {
                toolStripSplitButton.Enabled = value;
            }
        }

        #endregion
		
		/// <summary>
		/// Csatlakozás a szerverhez az eseménykezelő második paraméterében megadot adatok alapján
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e">a bejelentkezési adatok szerver|felhasználói név|jelszó alakban</param>
        void bw_DoWork(object sender, DoWorkEventArgs e)
        {
			string item = (string)e.Argument;	// a bejelentkezési adatok szerver|felhasználói név|jelszó alakban
            string[] login;						// a bejelentkezési adatok külön szegmensekben

            try
            {
                // Csatlakozás során letiltjuk a kapcsolatkezelő gombokat 
                textWriter(errorMessageStatusLabel, "Csatlakozás folyamatban...");

                Cursor.Current = Cursors.WaitCursor;

                // Átállítjuk a gombok láthatóságát
                enableChange(connectButton, false);
                enableChange(disconnectButton, false);

                // Bejelentkezési adatok 'server|username|password' formában
                login = item.Split('|');

                // a változókat feltöltjük a bejelentkezési adatokkal
                host = login[0];
                user = login[1];
                pass = login[2];
                // példányosítjuk az SshShell objektumunkat
				ssh = new SshShell(host, user) { Password = pass };
                // csatlakozunk a szerverhez
                ssh.Connect();

                // beállítjuk a mintát
                ssh.ExpectPattern = pattern;
                ssh.RemoveTerminalEmulationCharacters = true;

                textWriter(errorMessageStatusLabel, string.Empty);

				// láthatóvá tesszük az objektumokat a kapcsolat időtartama alatt
				visibleChange( splitContainer1, true );
				visibleChange( splitContainer2, true );
				enableChange( groupsComboBox, true );
				enableChange( browserButton, true );
            }
            // Kivételkezelés - kivétel esetén bontjuk a kapcsolatot és hibaüzenetet küldünk
            catch (SocketException)
            {
                textWriter(errorMessageStatusLabel, "Hálózati hiba: Nem sikerült kapcsolatot létesíteni a szerverrel.");
				ssh = null;
				ExceptionHandler();
                return;
            }
			catch ( Tamir.SharpSsh.jsch.JSchException jesc )
			{
				if ( jesc.Message.Equals( "invalid server's version String" ) )
				{
					textWriter( errorMessageStatusLabel, "A szerver váratlanul megszakította a kapcsolatot. Kérem próbálkozzon újra később." );
				}
				else
				{
					textWriter( errorMessageStatusLabel, "Helytelen bejelentkezési adatok!" );
				}

				ssh = null;
				ExceptionHandler();
				return;
			}
            catch (Exception)
            {
                textWriter(errorMessageStatusLabel, "Végzetes hiba történt. Kérem ellenőrizze az internetkapcsolatát és az alkalmazás beállításait!");
				ssh = null;
				ExceptionHandler();
                return;
            }

            try
            {
                // beolvassuk a szerver bejelentkező üzenetét
                string logintext = read();
                textWriter(mainTextBox, logintext.Substring(0, logintext.LastIndexOf('\n') - 2));

                // lekérdezzük a hallgató csoportját, és ennek megfelelő fájlkiterjesztéseket engedünk tesztelni
                //ssh.WriteLine("groups");

                //string group = read();
                //group = group.Substring(group.IndexOf('\n') + 1);
                //group = group.Substring(0, group.IndexOf('\n') - 1);
                //string[] groupitems = group.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

                /*
                 * Felhasználói csoportok beállítása
                 */
                groupsComboBox.Invoke((MethodInvoker)delegate()
                {
                    groupsComboBox.Items.Clear();                // töröljük a tárgyak listáját
					foreach (Subject s in subjects)
					{
						groupsComboBox.Items.Add(s.Targy_nev);
					}
					if (groupsComboBox.Items.Count > 0)
					{
						groupsComboBox.SelectedIndex = 0;
					}
                });

                changeDir(mainTextBox, remoteFilesListView, remoteHeaderLabel);

                enableChange(connectButton, false);
                enableChange(disconnectButton, true);

                textWriter(testLabel, form_title);

                Cursor.Current = Cursors.Arrow;
            }
            // Kivételkezelés - kivétel esetén bontjuk a kapcsolatot és hibaüzenetet küldünk
            catch (Tamir.SharpSsh.jsch.JSchException)
            {
                textWriter(errorMessageStatusLabel, "Helytelen felhasználói név vagy jelszó!");
				ssh = null;
				ExceptionHandler();
                return;
            }
            catch (SocketException)
            {
                textWriter(errorMessageStatusLabel, "Hálózati hiba: Nem sikerült kapcsolatot létesíteni a szerverrel.");
				ssh = null;
				ExceptionHandler();
                return;
            }
            catch (Exception)
            {
                textWriter(errorMessageStatusLabel, "Hálózati hiba. Kérem ellenőrizze az internetkapcsolatát!");
				ssh = null;
				ExceptionHandler();
                return;
            }
        }

        #endregion

		#region Tárgy kiválasztása

		/// <summary>
		/// A tárgyak legördülő menüjében történt változás esetén a tárgy konfigurációs állományának megfelelő funkciókat engedélyezzük csak
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void groupsComboBox_SelectedIndexChanged(object sender, EventArgs e)
		{
			try
			{
				if ( groupsComboBox.Items.Count > 0 )
				{
					submitButton.Enabled = ( subjects[groupsComboBox.SelectedIndex].Bead != string.Empty ? true : false );
					testButton.Enabled = ( subjects[groupsComboBox.SelectedIndex].Tesztel != string.Empty ? true : false );
					viewSubmittedButton.Enabled = ( subjects[groupsComboBox.SelectedIndex].Beadva != string.Empty ? true : false );
					viewResultButton.Enabled = ( subjects[groupsComboBox.SelectedIndex].Eredmeny != string.Empty ? true : false );
					gotoJuryButton.Enabled = ( subjects[groupsComboBox.SelectedIndex].Zsuri != string.Empty ? true : false );
					gotoSubmittedButton.Enabled = ( subjects[groupsComboBox.SelectedIndex].Beadott_fajlok != string.Empty && !fileTransferMode ? true : false );
					gotoTestButton.Enabled = ( subjects[groupsComboBox.SelectedIndex].Tesztesetek != string.Empty && !fileTransferMode ? true : false ); ;
				}
			}
			catch ( Exception )
			{
				ExceptionHandler();
			}
		}

		#endregion

		#region Hibakezelés, validálás és feliratozás

		/// <summary>
		/// Hibakezelő metódus
		/// </summary>
		/// <remarks>
		/// Amennyiben olyan kivétel következik be, ahol a kapcsolatot bontják
		/// - pl. amikor megszakad az internetkapcsolat, IOException adódik "Pipe closed" üzenettel -,
		/// akkor bontjuk az ssh kapcsolatot, és lehetővé tesszük a felhasználónak az újracsatlakozást.
		/// </remarks>
        private void ExceptionHandler()
        {
			if ( ssh == null || !ssh.Connected )
			{
				enableChange(connectButton, true);
				enableChange(disconnectButton, false);

				// eltüntetjük az objektumokat a kapcsolat bontásakor vagy hiba esetén
				visibleChange(splitContainer1, false);
				visibleChange(splitContainer2, false);
				enableChange(groupsComboBox, false);
				enableChange(browserButton, false);
			}
        }

		/// <summary>
		/// Feliratozó metódus - az aktuális funkciónak megfelelő címet és üzenetet jelenít meg a tesztelő felület kimenetén
		/// </summary>
		/// <param name="action">a testLabel értéke</param>
		/// <param name="text">az üzenet</param>
        protected void captureMethod(string action, string text)
        {
            if (testLabel.InvokeRequired)
            {
                testLabel.Invoke((MethodInvoker)delegate() { testLabel.Text = action; });
            }
            else
            {
                testLabel.Text = action;
            }

            if (mainTextBox.InvokeRequired)
            {
                mainTextBox.Invoke((MethodInvoker)delegate() { mainTextBox.Text = text; });
            }
            else
            {
                mainTextBox.Text = text;
            }
        }

		/// <summary>
		/// A tesztelendő feladatsor és feladat értékét ellenőrző metódus, mely segítségével
		/// a helytelenül beírt feladatszám (például alfanumerikus karakterek használata) esetén
		/// megszakítjuk a tesztelés/beadás folyamatát
		/// </summary>
		/// <param name="action">a végrehajtandó művelet (például Tesztelés vagy Beadás)</param>
		/// <returns></returns>
        protected bool correctExercise(string action)
        {
            try
            {
                if (excNum1TextBox.Text.Trim() != string.Empty && excNum2TextBox.Text.Trim() != string.Empty)
                {
                    int.Parse(excNum1TextBox.Text.Trim());
                    int.Parse(excNum2TextBox.Text.Trim());
                    return true;
                }
                else
                {
                    captureMethod(action, "Helytelen feladatsor/feladat érték! Kérem ellenőrizze, hogy helyes feladatot adott-e meg!");
                    return false;
                }
            }
            catch (Exception)
            {
				captureMethod(action, "Helytelen feladatsor/feladat érték! Kérem ellenőrizze, hogy helyes feladatot adott-e meg!");
				ExceptionHandler();
                return false;
            }
        }

        #endregion

        #region Menüsor [Fájl [Csatlakozás | Kapcsolat bontása | Beállítások | Bezárás] | Súgó]

        #region Csatlakozás

		/// <summary>
		/// 'Fájl/Csatlakozás...' menüpont
		/// </summary>
		/// <remarks>
		/// A szerverhez történő csatlakozás a Fájl menü 'Csatlakozás...' menüpontjára kattintva,
		/// az előugró formon megadott felhasználói adatok megadása után lehetséges
		/// </remarks>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void connectButton_Click(object sender, EventArgs e)
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;

                // Connect form példányosítása
                connectForm = new ConnectForm(server, user, pass) { ConnectDataCallback = new ConnectDataDelegate(this.ConnectDataCallbackFn) };

                // Connect form megnyitása
                connectForm.ShowDialog();

                Cursor.Current = Cursors.Arrow;
            }
            catch (Exception)
            {
                Cursor.Current = Cursors.Arrow;
                MessageBox.Show("Az alkamazás működése során hiba lépett fel.");
                ExceptionHandler();
            }
        }

        #endregion

        #region Kapcsolat bontása

		/// <summary>
		/// 'Fájl/Kapcsolat bontása' menüpont
		/// </summary>
		/// <remarks>
		/// A Fájl menü 'Kapcsolat bontása' menüpontjára kattintva bontjuk a kapcsolatot a szerverrel.
		/// Ezután újból lehetséges a szerverhez történő csatlakozás.
		/// </remarks>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void disconnectButton_Click(object sender, EventArgs e)
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;
				if (ssh != null && ssh.Connected) { ssh.Close(); }
				ExceptionHandler();
                groupsComboBox.Items.Clear();
                Cursor.Current = Cursors.Arrow;
            }
            catch (Exception)
            {
                Cursor.Current = Cursors.Arrow;
				MessageBox.Show( "Az alkamazás működése során hiba lépett fel." );
				ExceptionHandler();
            }
        }

        #endregion

        #region Beállítások

		/// <summary>
		/// 'Fájl/Beállítások...' menüpont
		/// </summary>
		/// <remarks>
		/// Az alapértelmezett nézőke és szerkesztő beállítása, a munkakönyvtár megadása
		/// és a rejtett fájlok beállítása lehetséges a menü által megjelenített formon
		/// </remarks>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void configurationButton_Click(object sender, EventArgs e)
        {
			try
			{
				Cursor.Current = Cursors.WaitCursor;
				ConfigurationForm form = new ConfigurationForm() { ConnectDataCallback = new ConfigurationDelegate( this.ConnectDataCallbackProperties ) };
				form.ShowDialog();
				Cursor.Current = Cursors.Arrow;
			}
			catch ( Exception )
			{
                Cursor.Current = Cursors.Arrow;
				MessageBox.Show( "Az alkamazás működése során hiba lépett fel." );
				ExceptionHandler();
			}
        }

        /// <summary>
		/// A beállításokat megváltoztató callback függvény.
        /// </summary>
        /// <param name="hidden">ha értéke igaz, akkor a rejtett fájlokat is megjelenítjük</param>
		private void ConnectDataCallbackProperties(bool hidden)
        {
            try
            {
                if (hiddenFiles != hidden)
                {
                    hiddenFiles = hidden;
                    changeDir(mainTextBox, remoteFilesListView, remoteHeaderLabel);
                    displayFolderList(localHeaderLabel.Text);
                }
            }
            catch (Exception)
            {
                MessageBox.Show("Hiba a művelet végrehajtása során.");
				ExceptionHandler();
            }
        }

        #endregion

        #region Bezárás

		/// <summary>
		/// 'Fájl/Bezárás' menüpont
		/// </summary>
		/// <remarks>
		/// A programablak bezárására szolgál
		/// </remarks>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void bezárásToolStripMenuItem_Click(object sender, EventArgs e)
        {
			closeWindow();
        }

        #endregion

        #region Súgó

		/// <summary>
		/// 'Súgó' menüpont
		/// </summary>
		/// <remarks>
		/// A program súgójának megjelenítése a Súgó menüpontra klikkelve vagy az F1 billentyűt leütve
		/// </remarks>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void helpButton_Click(object sender, EventArgs e)
        {
			HelpForm helpbox = new HelpForm(form_title) { StartPosition = FormStartPosition.CenterParent };
            helpbox.ShowDialog();
        }

        #endregion

        #endregion

        #region Billentyűparancsok

		/// <summary>
		/// Billentyűparancsok kezelése
		/// </summary>
		/// <remarks>
		/// Amennyiben valamelyik ListView aktív a formon, akkor kezeljük a következő műveleteket:
		///		Enter		Könyvtárváltás
		///		F2			Átnevezés
		///		F3			Nézőke
		///		F4			Szerkesztés
		///		F5			Másolás
		///		F7			Új könyvtár
		///		F8			Törlés
		///		Apps		Helyi menü megjelenítése
		///		Tab			Váltás a két ListView között
		/// </remarks>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void FilesListView_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                // Könyvtárváltás
                case Keys.Enter:
                    {
                        if (remoteFilesListViewFocused)
                        {
                            remoteFilesListView_PerformMouseDoubleClick();
                        }
                        else if (localFilesListViewFocused)
                        {
                            localFilesListView_PerformMouseDoubleClick();
                        }
                        break;
                    }
                // Átnevezés
                case Keys.F2:
                    {
                        renameButton_Click((object)sender, (EventArgs)e);
                        break;
                    }
                // Nézőke
                case Keys.F3:
                    {
                        viewButton_Click((object)sender, (EventArgs)e);
                        break;
                    }
                // Szerkesztés
                case Keys.F4:
                    {
                        if (e.Alt)
                        {
							closeWindow();
                        }
                        else
                        {
                            editButton_Click((object)sender, (EventArgs)e);
                        }
                        break;
                    }
                // Másolás
                case Keys.F5:
                    {
                        copyButton_Click((object)sender, (EventArgs)e);
                        break;
                    }
                // Új könyvtár
                case Keys.F7:
                    {
                        mkdirButton_Click((object)sender, (EventArgs)e);
                        break;
                    }
                // Törlés
                case Keys.F8:
                    {
                        deleteButton_Click((object)sender, (EventArgs)e);
                        break;
                    }
                // Helyi menü
                case Keys.Apps:
                    {
                        if (remoteFilesListViewFocused)
                        {
                            ListView_MouseClick((object)sender, new MouseEventArgs(MouseButtons.Right, 1, (remoteFilesListView.SelectedItems[remoteFilesListView.SelectedItems.Count - 1].Bounds.Left + remoteFilesListView.SelectedItems[remoteFilesListView.SelectedItems.Count - 1].Bounds.Right) / 2, remoteFilesListView.SelectedItems[remoteFilesListView.SelectedItems.Count - 1].Bounds.Top + 5, 0));
                        }
                        else if (localFilesListViewFocused)
                        {
                            ListView_MouseClick((object)sender, new MouseEventArgs(MouseButtons.Right, 1, (localFilesListView.SelectedItems[remoteFilesListView.SelectedItems.Count - 1].Bounds.Left + localFilesListView.SelectedItems[remoteFilesListView.SelectedItems.Count - 1].Bounds.Right) / 2, localFilesListView.SelectedItems[remoteFilesListView.SelectedItems.Count - 1].Bounds.Top + 5, 0));
                        }
                        break;
                    }
                // tabulátor hatására váltounk a két listview között
                case Keys.Tab:
                    {
                        if (remoteFilesListViewFocused)
                        {
                            localFilesListView.Focus();
                        }
                        else if (localFilesListViewFocused)
                        {
                            remoteFilesListView.Focus();
                        }
                        break;
                    }
            }
        }

		/// <summary>
		/// Globális billenyűleütések kezelése - Súgó
		/// </summary>
		/// <remarks>
		/// A Súgó megjelenítése az F1 leütésére, bármely vezérlőn is van a fókusz a formon
		/// </remarks>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void MainForm_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                // Súgó
                case Keys.F1:
                    {
                        helpButton_Click((object)sender, (EventArgs)e);
                        break;
                    }
            }
        }

        #endregion

        #region Fájlműveletek [Átnevezés | Nézőke | Szerkesztés | Másolás | Új könyvtár | Törlés]

        #region Átnevezés

		/// <summary>
		/// Átnevezés
		/// </summary>
		/// <remarks>
		/// Az Átnevezés gombra kattintva, vagy az F2 billentyűt leütve megjelenik az átnevezést végző modális form,
		/// amelynek paraméterül átadjuk az aktuálisan kijelölt fájl nevét, beállítjuk a visszahívó függvényét
		/// (RenameCallbackFunction) és az átnevezést ez a függvény végzi el.
		/// </remarks>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void renameButton_Click(object sender, EventArgs e)
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;
                if (remoteFilesListViewFocused && remoteFilesListView.SelectedItems.Count != 0 && remoteFilesListView.SelectedItems[0].SubItems[0].Text != "..")
                {
                    actName = remoteFilesListView.SelectedItems[0].SubItems[0].Text;
					RenameForm renameForm = new RenameForm(actName) { RenameFileCallback = new RenameDelegate(this.RenameCallbackFunction) };
                    renameForm.ShowDialog();                                                                
                }
                else if (localFilesListViewFocused && localFilesListView.SelectedItems.Count != 0 && localFilesListView.SelectedItems[0].SubItems[0].Text != "..")
                {
                    actName = localFilesListView.SelectedItems[0].SubItems[0].Text;
					RenameForm renameForm = new RenameForm(actName, true) { RenameFileCallback = new RenameDelegate(this.RenameCallbackFunction) };
                    renameForm.ShowDialog();                                                               
                }
                Cursor.Current = Cursors.Arrow;
            }
            catch (Exception)
            {
                Cursor.Current = Cursors.Arrow;
				MessageBox.Show( "Az alkamazás működése során hiba lépett fel." );
                ExceptionHandler();
            }
        }

		/// <summary>
		/// Az Átnevezés visszahívó függvénye
		/// </summary>
		/// <param name="item">az átnevezendő fájl/könyvtár új neve</param>
		/// <param name="isLocal">ha értéke igaz, akkor a számítógép fájlrendszerén, ha hamis, akkor a szerveren történik az átnevezés</param>
        private void RenameCallbackFunction(string item, bool isLocal)
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;

				string originalFile, newFile;
				ListViewItem i, j;
				DialogResult dr;

				// item: az új elem, actName: az eredeti elem neve
                if (item != actName)
                {
                    if (!isLocal)
                    {
						// ha létezik már az új elemmel megegyező fájl/könyvtár, akkor áthelyezzük/felülírjuk az állományt
						if ( (i = remoteFilesListView.FindItemWithText(item)) != null )
						{
							// az az új elem létező könyvtár, akkor a régi fájlt vagy könyvtárat áthelyezhetjük a létező könyvtárba
							if ( i.SubItems[1].Text.Equals( "<dir>" ) )
							{
								dr = MessageBox.Show( String.Format( "A(z) {0} könyvtár már létezik. Áthelyezi az {1} állományt ebbe a könyvtárba?", item, actName ), "Átnevezés", MessageBoxButtons.YesNo );
							}
							// ha az új elem fájl, és az eredeti is fájl, akkor felülírhatjuk, különben nem írható felül
							else
							{
								if ( ( j = remoteFilesListView.FindItemWithText( actName ) ) != null && j.SubItems[1].Text.Equals( "<dir>" ) )
								{
									MessageBox.Show( String.Format( "A(z) {0} nem könyvtár; nem írható felül a(z) {1} könyvtárral", item, actName ) );
									dr = DialogResult.No;
								}
								else
								{
									dr = MessageBox.Show( String.Format( "A(z) {0} állomány már létezik. Felülírja?", item ), "Átnevezés", MessageBoxButtons.YesNo );
								}
							}
							if ( dr == DialogResult.Yes )
							{
								// Átnevezzük a fájlt a paraméterként kapott névre, ha megváltozott
								ssh.WriteLine( "mv -f " + remoteFilesListView.SelectedItems[0].SubItems[0].Text + " " + item );
								read();

								// Frissítjük a fájllistát
								changeDir( mainTextBox, remoteFilesListView, remoteHeaderLabel );
							}
						}
						else
						{
							// Átnevezzük a fájlt a paraméterként kapott névre, ha megváltozott
							ssh.WriteLine("mv -f " + remoteFilesListView.SelectedItems[0].SubItems[0].Text + " " + item);
							read();

							// Frissítjük a fájllistát
							changeDir( mainTextBox, remoteFilesListView, remoteHeaderLabel );
						}
                    }
                    else
                    {
						bool isLocalDir = ( localFilesListView.SelectedItems[0].SubItems[1].Text.Equals( "<dir>" ) );

						originalFile = Path.Combine(localHeaderLabel.Text, localFilesListView.SelectedItems[0].SubItems[0].Text);
						newFile = Path.Combine(localHeaderLabel.Text, item);
                        // Átnevezzük a fájlt/könyvtárt a paraméterként kapott névre, ha megváltozott
						if (isLocalDir) 
						{
							Directory.Move(originalFile, newFile); 
						}
						else 
						{
							File.Move(originalFile, newFile); 
						}

                        // Frissítjük a fájllistát
                        loadLocalDrives();
                        displayFolderList(localHeaderLabel.Text);
                    }
                }
                Cursor.Current = Cursors.Arrow;
            }
            catch (Exception exc)
            {
                Cursor.Current = Cursors.Arrow;
                MessageBox.Show("Hiba az átnevezés során.\r\n\r\n" + exc.Message);
                ExceptionHandler();
            }
        }
        
		#endregion

        #region Nézőke

		/// <summary>
		/// Nézőke
		/// </summary>
		/// <remarks>
		/// A Nézőke gombra kattintva, vagy az F3 billentyűt leütve megnyitjuk a kijelölt fájlt a beállított nézőkében
		/// </remarks>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void viewButton_Click(object sender, EventArgs e)
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;

                if (remoteFilesListViewFocused && remoteFilesListView.SelectedItems.Count != 0 && remoteFilesListView.SelectedItems[0].SubItems[1].Text != "<dir>")
                {
                    // A kijelölt fájl letöltése a Temp könyvtárba
					tempFileName = Path.Combine(TEMP_PATH, remoteFilesListView.SelectedItems[0].SubItems[0].Text);
                    showDownloadForm(createViewerSettings(remoteHeaderLabel.Text + "/" + remoteFilesListView.SelectedItems[0].SubItems[0].Text, tempFileName, false, false));
                }
                else if (localFilesListViewFocused && localFilesListView.SelectedItems.Count != 0 && localFilesListView.SelectedItems[0].SubItems[1].Text != "<dir>")
                {
                    // Megnyitjuk a fájlt a beállított nézőkében
                    System.IO.FileInfo fileObj;
                    Process viewer = new Process();
                    viewer.StartInfo.FileName = Settings.Default.viewer;
					fileObj = new System.IO.FileInfo(localHeaderLabel.Text + (localHeaderLabel.Text[localHeaderLabel.Text.Length - 1].Equals(S) ? S : "") + localFilesListView.SelectedItems[0].SubItems[0].Text) { Attributes = System.IO.FileAttributes.ReadOnly };
					viewer.StartInfo.Arguments = fileObj.FullName;
                    viewer.StartInfo.ErrorDialog = true;
                    viewer.Start();
                }
                Cursor.Current = Cursors.Arrow;
            }
            catch (SshTransferException transferExc)
            {
                Cursor.Current = Cursors.Arrow;
				if ( transferExc.Message.Contains( "Permission denied" ) )
				{
					MessageBox.Show( "Hozzáférés megtagadva" );
				}
				else
				{
					MessageBox.Show( transferExc.Message );
				}
				ExceptionHandler();
            }
            catch (Exception)
            {
                Cursor.Current = Cursors.Arrow;
                captureMethod("Nézőke - Hiba", "Hiba a fájl lekérése során.");
                ExceptionHandler();
            }
        }

        #endregion

        #region Szerkesztés

		/// <summary>
		/// Szerkesztés
		/// </summary>
		/// <remarks>
		/// A Szerkesztés gombra kattintva, vagy F4-et ütve megnyitjuk az aktuálisan kijelölt fájlt
		/// a beállított szerkesztőben. Ha bezárjuk a szerkesztőt, az aktuálisan bezárt fájlt felkínálja feltöltésre.
		/// </remarks>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void editButton_Click(object sender, EventArgs e)
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;
                // ha van kijelölt elem
                if (remoteFilesListViewFocused && remoteFilesListView.SelectedItems.Count != 0 && remoteFilesListView.SelectedItems[0].SubItems[1].Text != "<dir>")
                {
                    // a kijelölt elem
                    selected = remoteFilesListView.SelectedItems[0];

                    if (selected != null && selected.SubItems[0].Text != ".." && selected.SubItems[1].Text != "<dir>")
                    {
                        // átmásoljuk a távoli fájlt a Temp könyvtárba
						tempFileName = Path.Combine(TEMP_PATH, selected.SubItems[0].Text);     // ideiglenes fájlnevet rendelünk a letöltött fájlhoz
                        remoteFileName = remoteHeaderLabel.Text + "/" + selected.SubItems[0].Text;              // eltároljuk a távoli fájl teljes elérési útvonalát a későbbi frissítés miatt
                        showDownloadForm(createViewerSettings(remoteFileName, tempFileName, true, false));
                    }
                }
                else if (localFilesListViewFocused && localFilesListView.SelectedItems.Count != 0 && localFilesListView.SelectedItems[0].SubItems[1].Text != "<dir>")
                {
                    selected = localFilesListView.SelectedItems[0];

                    if (selected != null && selected.SubItems[0].Text != ".." && selected.SubItems[1].Text != "<dir>")
                    {
                        Process editor = new Process();
                        editor.StartInfo.FileName = Settings.Default.editor;
						editor.StartInfo.Arguments = localHeaderLabel.Text + (localHeaderLabel.Text[localHeaderLabel.Text.Length - 1].Equals(S) ? S : "") + localFilesListView.SelectedItems[0].SubItems[0].Text;

                        FileInfo info = new FileInfo(editor.StartInfo.Arguments);
                        if (info.IsReadOnly)
                        {
                            DialogResult dr = MessageBox.Show("A(z) " + editor.StartInfo.Arguments + " fájl írásvédett. Mégis szerkeszti?", "Figyelmeztetés", MessageBoxButtons.YesNo);
                            if (dr == DialogResult.No) { return; } else { info.IsReadOnly = false; }
                        }
                        editor.Start();
                    }
                }
                Cursor.Current = Cursors.Arrow;
            }
            catch (SshTransferException transferExc)
            {
				if ( transferExc.Message.Contains( "Permission denied" ) )
				{
					MessageBox.Show( "Hozzáférés megtagadva" );
				}
				else
				{
					MessageBox.Show( transferExc.Message );
				}
				ExceptionHandler();
            }
            catch (Exception)
            {
                Cursor.Current = Cursors.Arrow;
                MessageBox.Show( "Hiba a fájl megnyitása során." );
                ExceptionHandler();
            }
        }

        #endregion

        #region Másolás

		/// <summary>
		/// Másolás
		/// </summary>
		/// <remarks>
		/// A Másolás gombra kattintva, vagy F5-et ütve a kijelölt állományokat átmásoljuk a szerverről a felhasználó számítógépére
		/// vagy a számítógépről a szerverre (ha a localFilesListViewFocused igaz értékű, akkor a szerverre, 
		/// ha a remoteFilesListViewFocused értéke az igaz, akkor pedig a szerverről másolunk
		/// (localFilesListViewFocused és remoteFilesListViewFocused értéke nem lehet egyszerre igaz).
		/// </remarks>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void copyButton_Click(object sender, EventArgs e)
        {
			try
			{
				Cursor.Current = Cursors.WaitCursor;
				if (fileTransferMode)
				{
					if ((localFilesListViewFocused && localFilesListView.CheckedItems.Count != 0 || !localFilesListView.SelectedItems[0].SubItems[0].Text.Equals("..")) || (remoteFilesListViewFocused && remoteFilesListView.CheckedItems.Count != 0 || !remoteFilesListView.SelectedItems[0].SubItems[0].Text.Equals("..")))
					{
						// figyelmeztető üzenetet küldünk a felhasználónak
						DialogResult dr = MessageBox.Show("Forrás:\t" + (remoteFilesListViewFocused ? remoteHeaderLabel.Text : localHeaderLabel.Text) + "\r\nCél:\t" + (remoteFilesListViewFocused ? localHeaderLabel.Text : remoteHeaderLabel.Text) + "\r\n\r\n" + "Biztosan ezt akarja tenni?", "Másolás", MessageBoxButtons.YesNo);
						if (dr == DialogResult.Yes)
						{
							ListView copy = new ListView();
							if (remoteFilesListViewFocused && (remoteFilesListView.SelectedItems.Count >= 0 || remoteFilesListView.CheckedItems.Count > 0))
							{
								if (remoteFilesListView.CheckedItems.Count == 0)
								{
									// ha nincs bejelölve egy fájl sem, akkor az aktuálisan kijelöltet bejelöljük
									remoteFilesListView.SelectedItems[0].Checked = true;
								}
								foreach (ListViewItem i in remoteFilesListView.CheckedItems)
								{
									// létrehozzuk a másolandó fájlok listáját
									if (i.SubItems[0].Text.Equals("..")) continue;
									copy.Items.Add((ListViewItem)i.Clone());
								}
								// meghívjuk a másolást végző formot (a második paraméter hamis értéke jelzi, hogy a szerverről másolunk)
								showCopyForm(copy.Items, false);
							}
							else if (localFilesListViewFocused && (localFilesListView.SelectedItems.Count >= 0 || localFilesListView.CheckedItems.Count > 0))
							{
								if (localFilesListView.CheckedItems.Count == 0)
								{
									// ha nincs bejelölve egy fájl sem, akkor az aktuálisan kijelöltet bejelöljük
									localFilesListView.SelectedItems[0].Checked = true;
								}
								foreach (ListViewItem i in localFilesListView.CheckedItems)
								{
									// létrehozzuk a másolandó fájlok listáját
									if (i.SubItems[0].Text.Equals("..")) continue;
									copy.Items.Add((ListViewItem)i.Clone());
								}
								// meghívjuk a másolást végző formot (a második paraméter hamis értéke jelzi, hogy a szerverre másolunk)
								showCopyForm(copy.Items, true);
							}
						}
					}
				}
				Cursor.Current = Cursors.Arrow;
			}
			catch (Exception)
			{
				Cursor.Current = Cursors.Arrow;
				MessageBox.Show("Hiba a másolás során.");
				changeDir(mainTextBox, remoteFilesListView, remoteHeaderLabel);
				displayFolders();
				ExceptionHandler();
			}
        }

        #endregion

        #region Új könyvtár

		/// <summary>
		/// Új könyvtár
		/// </summary>
		/// <remarks>
		/// Az 'Új könyvtár' gombra kattintva, az F7 billentyűt leütve vagy a helyi menü 'Új/Könyvtár' menüpontját kiválasztva
		/// meghívjuk az új könyvtár létrehozásáért felelős formot (a könyvtár létrehozását a NewFileDataCallbackFn visszahívó 
		/// függvény végzi)
		/// </remarks>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void mkdirButton_Click(object sender, EventArgs e)
        {
            Cursor.Current = Cursors.WaitCursor;
			try
			{
				NewFileForm newFileForm = null;
				if (remoteFilesListViewFocused)
				{
					newFileForm = new NewFileForm(false, false);
				}
				else if (localFilesListViewFocused)
				{
					newFileForm = new NewFileForm(true, false);
				}
				newFileForm.newFileCallback = new NewFileDelegate(this.NewFileDataCallbackFn);
				newFileForm.ShowDialog();
			}
			catch {}
            Cursor.Current = Cursors.Arrow;
        }

		/// <summary>
		/// Az új könyvtár/fájl létrehozását végző visszahívó függvény
		/// </summary>
		/// <param name="item">a létrehozandó fájl/könyvtár neve</param>
		/// <param name="isLocal">igaz érték esetén a számítógépen, hamis érték esetén a szerveren hozzuk létre az új fájl/könyvtárat</param>
		/// <param name="isFile">igaz érték esetén fájlt, hamis érték esetén könyvtárat hozunk létre</param>
        private void NewFileDataCallbackFn(string item, bool isLocal, bool isFile)
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;

                if (!isLocal)
                {
                    if (isFile)
                    {
                        ssh.WriteLine("touch " + item + "; echo ' ' >> " + item);
                    }
                    else
                    {
                        ssh.WriteLine("mkdir " + item);
                    }
                    read();

                    // Frissítjük a fájllistát a szerveren
                    changeDir(mainTextBox, remoteFilesListView, remoteHeaderLabel);
                }
                else
                {
                    if (isFile)
                    {
						File.Create(localHeaderLabel.Text + (localHeaderLabel.Text[localHeaderLabel.Text.Length - 1].Equals(S) ? S : "") + item);
                    }
                    else
                    {
						Directory.CreateDirectory(localHeaderLabel.Text + (localHeaderLabel.Text[localHeaderLabel.Text.Length - 1].Equals(S) ? S : "") + item);
                    }

                    // Frissítjük a fájllistát a számítógépen
                    loadLocalDrives();
                    displayFolderList(localHeaderLabel.Text);
                }
                Cursor.Current = Cursors.Arrow;
            }
            catch (Exception)
            {
                Cursor.Current = Cursors.Arrow;
                MessageBox.Show( "Hiba az állomány létrehozása során." );
                ExceptionHandler();
            }
        }

        #endregion

        #region Törlés

		/// <summary>
		/// Törlés
		/// </summary>
		/// <remarks>
		/// A Törlés gombra kattintva, vagy az F8 billentyűt leütve az aktuális fájl/könyvtár nevét paraméterül kapva
		/// meghívja a törlést végző modális formot (a logika hasonló a Másolás megvalósításához)
		/// </remarks>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void deleteButton_Click(object sender, EventArgs e)
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;
                ListView copy = new ListView();
                if (remoteFilesListViewFocused && (remoteFilesListView.SelectedItems.Count != 0 || remoteFilesListView.CheckedItems.Count > 0))
                {
					if (remoteFilesListView.CheckedItems.Count != 0 || !remoteFilesListView.SelectedItems[0].SubItems[0].Text.Equals(".."))
					{
						if (remoteFilesListView.CheckedItems.Count == 0)
						{
							remoteFilesListView.SelectedItems[0].Checked = true;
						}
						foreach (ListViewItem i in remoteFilesListView.CheckedItems)
						{
							if (i.SubItems[0].Text.Equals("..")) continue;
							copy.Items.Add((ListViewItem)i.Clone());
						}
						showDeleteForm(copy.Items, false);
					}
                }
                else if (localFilesListViewFocused && (localFilesListView.SelectedItems.Count != 0 || localFilesListView.CheckedItems.Count > 0))
                {
					if (localFilesListView.CheckedItems.Count != 0 || !localFilesListView.SelectedItems[0].SubItems[0].Text.Equals(".."))
					{
						if (localFilesListView.CheckedItems.Count == 0)
						{
							localFilesListView.SelectedItems[0].Checked = true;
						}
						foreach (ListViewItem i in localFilesListView.CheckedItems)
						{
							if (i.SubItems[0].Text.Equals("..")) continue;
							copy.Items.Add((ListViewItem)i.Clone());
						}
						showDeleteForm(copy.Items, true);
					}
                }
                Cursor.Current = Cursors.Arrow;
            }
            catch (Exception)
            {
                Cursor.Current = Cursors.Arrow;
                MessageBox.Show("Hiba a fájl/könyvtár törlése során.");
                changeDir(mainTextBox, remoteFilesListView, remoteHeaderLabel);
                ExceptionHandler();
            }
        }

        #endregion

        #endregion

        #region Speciális könyvtárakba ugrás [Munkakönyvtár | Zsűri | Beadott fájlok | Tesztesetek]

		/// <summary>
		/// Beadott fájlok könyvtárába ugrás
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void gotoSubmittedButton_Click(object sender, EventArgs e)
        {
            try
            {
                if (correctExercise("Hiba"))
                {
					ssh.WriteLine(String.Format("cd " + subjects[groupsComboBox.SelectedIndex].Beadott_fajlok, excNum1TextBox.Text, excNum2TextBox.Text));
                    read();
                    changeDir(mainTextBox, remoteFilesListView, remoteHeaderLabel);
                }
            }
            catch (Exception)
            {
                MessageBox.Show("A művelet nem hajtható végre.");
				ExceptionHandler();
            }
        }

		/// <summary>
		/// A felhasználó munkakönyvtárába ugrás
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void gotoHomeButton_Click(object sender, EventArgs e)
        {
            try
            {
				if (remoteFilesListViewFocused)
				{
					ssh.WriteLine("cd ~");
					read();
					changeDir(mainTextBox, remoteFilesListView, remoteHeaderLabel);
				}
				else if (fileTransferMode)
				{
					if ( !Directory.Exists( Settings.Default.workingdir ) )
					{ 
						MessageBox.Show(String.Format("A következő könyvtár nem létezik: {0} \r\nKérem ellenőrizze a beállításokat!", Settings.Default.workingdir));
					}
					else
					{
						displayFolderList(Settings.Default.workingdir);
					}
				}
            }
            catch (Exception)
            {
                MessageBox.Show("A művelet nem hajtható végre.");
				ExceptionHandler();
            }
        }

		/// <summary>
		/// A zsűri könyvtárába ugrás
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void gotoJuryButton_Click(object sender, EventArgs e)
        {
            try
            {
				ssh.WriteLine(String.Format("cd " + subjects[groupsComboBox.SelectedIndex].Zsuri));
				read();
				changeDir(mainTextBox, remoteFilesListView, remoteHeaderLabel);
            }
            catch (Exception)
            {
                MessageBox.Show("A művelet nem hajtható végre.");
				ExceptionHandler();
            }
        }

		/// <summary>
		/// Az adott feladat könyvtárába ugrás
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void gotoTestButton_Click(object sender, EventArgs e)
        {
            try
            {
                if (correctExercise("Hiba"))
                {
					ssh.WriteLine(String.Format("cd " + subjects[groupsComboBox.SelectedIndex].Tesztesetek, excNum1TextBox.Text, excNum2TextBox.Text));
                    read();
                    changeDir(mainTextBox, remoteFilesListView, remoteHeaderLabel);
                }
            }
            catch (Exception)
            {
				MessageBox.Show( "A művelet nem hajtható végre." );
				ExceptionHandler();
            }
        }

        #endregion

        #region Könyvtárváltás a szerveren

		/// <summary>
		/// Könyvtárváltás a szerveren
		/// </summary>
		/// <remarks>
		/// A metódus a könyvtárak közötti navigálást teszi lehetővé.
		/// A kimeneten a fájl/könyvtár neve mellett a méret, valamint az utolsó módosítás dátuma szerepel.
		/// A fájl/könyvtár további tulajdonságai, valamint a fájlműveletek a helyi menüből érhetők el.
		/// </remarks>
		/// <param name="mainTextBox">a visszajelzéseket tartalmazó textbox</param>
		/// <param name="remoteFilesListView">a ListView, amelyben megjelenítjük a fájlstruktúrát,</param>
		/// <param name="remoteHeaderLabel">a Label, amely a szerver aktuális könyvtárát tartalmazza</param>
        private void changeDir(TextBox mainTextBox, ListView remoteFilesListView, Label remoteHeaderLabel)
        {
            string list = string.Empty;									// a könyvtár állományai szöveges formában
			string[] items;												// a könyvtár állományai soronként
            List<string> dirs, files;									// a könyvtárban található fájlok és könyvtárak, külön listában a megjelenítés megkönnyítése érdekében
			
			string[] sItems;											// egyetlen állomány tulajdonságait tartalmazó tömb
            
			string név = string.Empty;									// a főbb tulajdonságok külön változókban
            string méret = string.Empty;
            string jogosultság = string.Empty;
            string módosítva = string.Empty;
            long size;
            int ikon;
			
			string pwd = string.Empty;									// az aktuális könyvtár
            
			string[] separator = { "/" };								// a könyvtárelválasztó karakter
            string[] labeltext;											// az aktuális könyvtár részeit tartalmazó tömb, amelyből felépítjük a könyvtárhierarchiát a legördülő menüben történő navigáció megvalósításához
            string actDir = string.Empty;								// aktuálisan a legördülő menübe kerülő könyvtár
            
			string command = string.Empty;                              // a kiadott parancs
            string result = string.Empty;                               // a visszaolvasott válasz

			try
			{
				new Thread((ThreadStart)delegate()
				{
					this.BeginInvoke((ThreadStart)delegate()
					{
						Cursor.Current = Cursors.WaitCursor;            // egérkurzor átállítása a folyamat ideje alatt
						remoteFilesListView.Items.Clear();              // a listview tartalmának törlése
						remoteFooterLabel.Text = string.Empty;          // töröljük az aktuálisan kijelölt fájl nevét

						// a beállításoktól függően jelenítjük meg a rejtett fájlokat
						if (hiddenFiles)
						{
							command += "ls -aog";                       // kilistázzuk a rejtett fájlokat is
						}
						else
						{
							command += "ls -og";                        // a rejtett fájlokat nem jelenítjük meg
						}

						command += ";echo \"---LIST---\"; pwd; echo \"---PWD---\"";
						ssh.WriteLine(command);
						result = read();                                  // beolvassuk a könyvtár tartalmát
						try
						{
							list = trimLines( result, 2, 0 );
							list = list.Substring( 0, list.IndexOf( "---LIST---" ) ).Trim();
						}
						catch ( Exception )
						{
							list = result;
						}
						ListView_addItem(remoteFilesListView, new string[] { "..", "<dir>", "", "" }, 26, COLOR1, String.Empty);
						items = list.Split('\n');                       // a könyvtár tartalma soronként - ebből lesznek a listview elemei

						// külön válogatjuk a könyvtárakat és a fájlokat, majd egyszerre jelenítjük meg, előbb a könyvtárakat, utána a fájlokat, hogy a rendezés ugyanúgy működjön, mint a helyi fájlok esetében
						dirs = new List<string>();
						files = new List<string>();
						foreach (string i in items)
						{
							if (i.Contains(pattern) || i.Trim().Equals(string.Empty))
							{
								continue;
							}
							else if (i[0] == 'd')
							{
								dirs.Add(i.Trim());
							}
							else if (i[0] == '-')
							{
								files.Add(i.Trim());
							}
						}
						items = dirs.Concat(files).ToArray();               // az items tömbbe fűzzük össze a könyvtárakat és a fájlokat

						for (int i = 0; i < items.Length; i++)              // feltöltjük a listview-t a könyvtár tartalmával
						{
							try
							{
								// felbontjuk a sorokat a tulajdonságoknak megfelelően, a felesleges szóközöket eltávolítva
								sItems = items[i].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

								// a név az eredeti stringben a : utáni 3. karaktertől kezdődik
								név = items[i].Substring(items[i].IndexOf(':') + 3);
								név = név.Substring(1, név.Length - 1);

								if (név == "." || név == "..")              // ha '.' vagy '..' akkor átlépünk az elemen
								{
									continue;
								}

								jogosultság = sItems[0];                    // a jogosultság a tömb nulladik eleme

								// fájlméretméret beállítása
								if (long.TryParse(sItems[2], out size))     // ha konvertálható egészre, akkor beállítjuk a helyes méretet
								{
									méret = setSize(size);
								}
								else                                        // különben a méretet bájtokban jelezzünk ki
								{
									méret = sItems[2];
								}
								módosítva = sItems[3] + " " + sItems[4];    // utolsó módosítás ideje
								méret = (jogosultság[0] == 'd' ? "<dir>" : méret);
								ikon = (méret.Equals("<dir>") ? 0 : 1);
								ListView_addItem(remoteFilesListView, new string[] { név, méret, módosítva, jogosultság }, ikon, (név[0] == '.' ? COLOR4 : COLOR1), sItems[2]);
							}
							catch
							{
								continue;
							}
						}

						// az aktuális útvonalat elhelyezzük a label-ben 
						pwd = result.Substring(result.LastIndexOf("---LIST---") + 10).Trim();
						remoteHeaderLabel.Text = pwd.Substring(0, pwd.IndexOf("---PWD---")).Trim();

						// csak akkor engedélyezzük a tesztfájl megtekintését, ha az adott könyvtárban létezik teszt.log fájl
						viewLogButton.Enabled = (remoteFilesListView.FindItemWithText(PROG_LOG) != null) ? true : false;

						// csak akkor engedélyezzük a tesztelő kimenetének megtekintését, ha az adott könyvtárban létezik teszt.out fájl
						viewTestOutButton.Enabled = (remoteFilesListView.FindItemWithText(PROG_OUT) != null) ? true : false;

						// feltöltjük a remoteDrivesComboBox elemeit az aktuális könyvtárral és a könyvtárhierarchia elemeivel
						remoteDrivesComboBox.Items.Clear();
						if (remoteHeaderLabel.Text.Trim().Equals("/"))
						{
							ImageDriveComboBox_addItem(remoteDrivesComboBox, "/", 0);
						}
						else
						{
							labeltext = remoteHeaderLabel.Text.Split(separator, StringSplitOptions.None);
							for (int i = 0; i < labeltext.Length; i++)
							{
								for (int j = 0; j <= i; j++)
								{
									actDir += "/" + labeltext[j].Trim();
								}
								if (actDir.Length >= 2 && actDir.Substring(0, 2).Equals("//"))
								{
									actDir = actDir.Substring(1);
								}

								ImageDriveComboBox_addItem(remoteDrivesComboBox, actDir, 0);
								actDir = string.Empty;
							}
						}

						remoteDrivesComboBox.SelectedIndex = remoteDrivesComboBox.Items.Count - 1;
						remoteFilesListView.Items[0].Selected = true;    // aktuálisan kijelölt elem
						Cursor.Current = Cursors.Arrow;                  // kurzor visszaállítása
					});
				}).Start();
			}
			catch (Exception)
			{
				Cursor.Current = Cursors.Arrow;
				MessageBox.Show( "Hiba a szerver válaszának feldolgozás során." );
				ssh.WriteLine("cd ~");
				read();
				changeDir(mainTextBox, remoteFilesListView, remoteHeaderLabel);
				ExceptionHandler();
			}
        }

		/// <summary>
		/// Könyvtárváltás dupla klikkre a ListView-n
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void remoteFilesListView_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                remoteFilesListView_PerformMouseDoubleClick();
            }
        }

		/// <summary>
		/// A könyvtárváltást megvalósító metódus
		/// </summary>
        private void remoteFilesListView_PerformMouseDoubleClick()
        {
            try
            {
                // bal klikk detektálása
                Cursor.Current = Cursors.WaitCursor;

                // ha könyvtárra kattintottunk, akkor könyvtárat váltunk
                if (remoteFilesListView.SelectedItems.Count != 0 && (remoteFilesListView.SelectedItems[0].SubItems[1].Text == "<dir>" || remoteFilesListView.SelectedItems[0].SubItems[1].Text == "<root>"))
                {
                    ssh.WriteLine("cd \"" + remoteFilesListView.SelectedItems[0].SubItems[0].Text + "\"");
                    read();
                    changeDir(mainTextBox, remoteFilesListView, remoteHeaderLabel);
                }
                Cursor.Current = Cursors.Arrow;
            }
            catch (Exception)
            {
                Cursor.Current = Cursors.Arrow;
				MessageBox.Show( "Hiba a könyvtárváltás során." );
                ExceptionHandler();
            }
        }

		/// <summary>
		/// Az attribútum-módosító formból érkező adatok feldolgozását végző callback függvény
		/// </summary>
		/// <param name="attrib"></param>
        private void modifyPropertiesCallback(string attrib)
        {
            // a kiválasztott fájl attribútuma oktálisan
            int attrNumber = 0;

            try
            {
                Cursor.Current = Cursors.WaitCursor;

                // átkódoljuk a karakteres attribútumot oktális formára
                if (actAttr[1] != '-') { attrNumber += 400;	}
                if (actAttr[2] != '-') { attrNumber += 200;	}
                if (actAttr[3] != '-') { attrNumber += 100; }
                if (actAttr[4] != '-') { attrNumber += 40;	}
                if (actAttr[5] != '-') { attrNumber += 20;	}
                if (actAttr[6] != '-') { attrNumber += 10;	}
                if (actAttr[7] != '-') { attrNumber += 4;	}
                if (actAttr[8] != '-') { attrNumber += 2;	}
                if (actAttr[9] != '-') { attrNumber += 1;	}

                // ha történt változás, csak akkor módosítunk, csökkentve a hálózati forgalmat
                if (!attrib.Equals(attrNumber.ToString()))
                {
                    // rekurzívan módosítjuk az attribútumokat
                    ssh.WriteLine("chmod  -R " + attrib + " " + remoteFilesListView.SelectedItems[0].SubItems[0].Text);

                    // beolvassuk a szerver válaszát 
                    read();

                    // frissítjük a könyvtár tartalmát
                    changeDir(mainTextBox, remoteFilesListView, remoteHeaderLabel);
                }
                Cursor.Current = Cursors.Arrow;
            }
            catch (Exception)
            {
                Cursor.Current = Cursors.Arrow;
				MessageBox.Show( "Hiba a  fájl/könyvtár attribútumainak módosítása során." );
                ExceptionHandler();
            }
        }

		/// <summary>
		/// A szerver könyvtárai közötti navigácót megkönnyítő legördülő menüben történő kattintás eseménykezelője
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void remoteDrivesComboBox_SelectionChangeCommitted(object sender, EventArgs e)
		{
			try
			{
				ssh.WriteLine("cd \"" + remoteDrivesComboBox.SelectedItem.ToString() + "\"");
				read();
			}
			catch { }
			changeDir(mainTextBox, remoteFilesListView, remoteHeaderLabel);
		}

        #endregion

        #region Ablak bezárása

		/// <summary>
		/// A programablak bezárása
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
			closeWindow();
        }

		/// <summary>
		/// Alt+F4 leütése esetén, a Fájl/Bezárás menüpontra klikkelve, vagy az ablakot bezárva lefutó metódus
		/// </summary>
		private void closeWindow()
		{
			try
			{
				deleteTempDir();
				if (ssh != null && ssh.Connected) ssh.Close();
			}
			catch { }
			this.Dispose(true);
			this.Close();
			Environment.Exit(-1);		
		}

        #endregion

        #region Temp könyvtár törlése

		/// <summary>
		/// Temp könyvtár tartalmának törlése a program bezárásakor
		/// </summary>
        private void deleteTempDir()
        {
			try
			{
				foreach ( string f in System.IO.Directory.GetFiles( TEMP_PATH ) )
				{
					if ( ( File.GetAttributes( f ) & FileAttributes.ReadOnly ) == FileAttributes.ReadOnly )
					{
						File.SetAttributes( f, FileAttributes.Normal );
					}
					System.IO.File.Delete( f );
				}
			}
			catch {}
        }

        #endregion

        #region Beadás

		/// <summary>
		/// A 'Beadás' parancs eseménykezelője
		/// </summary>
		/// <remarks>Az adott feladat beadása a kiválasztott tárgy, feladat és feladatsor esetén</remarks>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void submitButton_Click(object sender, EventArgs e)
        {
            try
            {
                string firstline = string.Empty;                                // a teszt.log első sora
                string actSubject = String.Empty;                               // az aktuálisan kiválasztott tárgy

                Cursor.Current = Cursors.WaitCursor;

                if (correctExercise("Feladat beadása"))
                {
					ssh.WriteLine(String.Format(subjects[groupsComboBox.SelectedIndex].Bead, excNum1TextBox.Text, excNum2TextBox.Text));
                    readSubmitResponse(read());
                }
                // Ha 'Biztosan' szerepel a kimenetben akkor egy MessageBox-ban várjuk a választ
                Cursor.Current = Cursors.Arrow;
            }
            catch (Exception)
            {
                Cursor.Current = Cursors.Arrow;
                captureMethod("Feladat beadása - Hiba", "Hiba a beadás során.");
				ExceptionHandler();
            }
        }

		/// <summary>
		/// A beadás folyamatát segítő metódus
		/// </summary>
		/// <remarks>
		/// A metódus használatával lehetséges a felhasználói interakciót váró parancsok kezelése
		/// (amikor a szkript a felhasználótól igen/nem választ vár  
		/// - például: 'Ez a feladat még nem volt tesztelve. Biztosan beadja teszteletlenül?' -,
		/// akkor ezt a választ a felhasználótól egy MessageBox-on keresztül várjuk,
		/// és a DialogResult értékének megfelelően közöljük a szerverrel).
		/// </remarks>
		/// <param name="response">a szerver válasza</param>
        private void readSubmitResponse(string response)
        {
            DialogResult dr;
            string submitResponse = response;
            if (submitResponse.Contains("Biztosan"))
            {
                dr = MessageBox.Show(trimLines(submitResponse, 1, 0).Replace(" (igen/[nem])", ""), "Figyelem", MessageBoxButtons.YesNo);
				ssh.WriteLine((dr == DialogResult.Yes) ? "igen" : "nem");
                submitResponse = read();
                readSubmitResponse(submitResponse);
            }
            else
            {
                captureMethod("Feladat beadása", trimLines(submitResponse, 1, 1));
            }
        }

        #endregion

        #region Beadva

		/// <summary>
		/// A 'Beadva' parancs eseménykezelője
		/// </summary>
		/// <remarks>
		/// A megadott feladatra beadott állományok megjelenítése
		/// </remarks>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void viewSubmittedButton_Click(object sender, EventArgs e)
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;

                if (correctExercise("Beadott fájlok"))
                {
					ssh.WriteLine(String.Format(subjects[groupsComboBox.SelectedIndex].Beadva, excNum1TextBox.Text, excNum2TextBox.Text));
                    captureMethod("Beadott fájlok", readText());
                }

                Cursor.Current = Cursors.Arrow;
            }
            catch (Exception)
            {
                Cursor.Current = Cursors.Arrow;
                captureMethod("Beadott fájlok - Hiba", "Hiba a beadott állományok lekérése során.");
				ExceptionHandler();
            }
        }

        #endregion

        #region Tesztelés

		/// <summary>
		/// A 'Tesztelés' parancs eseménykezelője
		/// </summary>
		/// <remarks>
		/// A metódus a test.sh főbb feltételeit ellenőrzi, majd ha minden teljesült, futtatja a tesztelő szkriptet,
		/// és a tesztelés eredményét közli a felhasználóval.
		/// 
		/// (A metódus elsősorban azt ellenőrzi, hogy van-e teszt.log a munkakönyvtárban - 
		/// ha nincs, akkor futtatja a tesztelőt, ha van, akkor megnézi, hogy ugyanarra vagy másik forrásra tesztelünk-e,
		/// a többi feladatot maga a test.sh szkript végzi a szerveren.)
		/// </remarks>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void testButton_Click(object sender, EventArgs e)
        {
            string firstline = string.Empty;    // a teszt.log első sora
            DialogResult otherTest;

            try
            {
                Cursor.Current = Cursors.WaitCursor;

                // ha adtunk meg feladatot, csak akkor tesztelünk
                if (correctExercise("Feladat tesztelése"))
                {
                    // ha már volt tesztelve a fájl
                    if (remoteFilesListView.FindItemWithText(PROG_LOG) != null)
                    {
                        // beolvassuk és megvizsgáljuk a napló első sorát, hogy ugyanarra, vagy másik feladatra tesztelünk-e
                        ssh.WriteLine("head -n 1 " + PROG_LOG);
                        firstline = readText().Trim();

						if (!firstline.Equals(String.Format("Feladat: " + subjects[groupsComboBox.SelectedIndex].Feladat, excNum1TextBox.Text, excNum2TextBox.Text).Trim()))
                        {
                            otherTest = MessageBox.Show("Ez a forrás legutóbb egy másik feladatra lett tesztelve. Biztosan tesztelni akarja erre a feladatra?", "Figyelmeztetés", MessageBoxButtons.YesNo);
                            if (otherTest == DialogResult.Yes)
                            {
                                ssh.WriteLine("rm " + PROG_LOG);
                                readText();
                            }
                            else
                            {
                                return;
                            }
                        }
                    }
					ssh.WriteLine(String.Format(subjects[groupsComboBox.SelectedIndex].Tesztel, excNum1TextBox.Text, excNum2TextBox.Text));

                    captureMethod("Feladat tesztelése", readText());

                    // Frissítjük a könyvtárlistát
                    changeDir(mainTextBox, remoteFilesListView, remoteHeaderLabel);
                }
                Cursor.Current = Cursors.Arrow;
            }
            catch (Exception)
            {
                Cursor.Current = Cursors.Arrow;
                captureMethod("Feladat tesztelése", "Hiba a tesztelés során.");
				ExceptionHandler();
            }
        }

        #endregion

        #region Formok generálása a letöltéshez/feltöltéshez, szerkesztéshez

		/// <summary>
		/// A megadott paraméterekkel konstruál egy ViewerSettings objektumot, amit a fájlműveletek során használhatunk fel.
		/// </summary>
		/// <param name="selectedfile">a kijelölt fájl</param>
		/// <param name="tempfilename">a temp könyvtárba letöltött átmeneti fájl</param>
		/// <param name="editable">igaz érték esetén szerkesztésre, hamis érték esetén megtekintésre nyitjuk meg a fájlt</param>
		/// <param name="upload">ha értéke igaz, akkor a szerkesztés után feltöltjük a fájlt a szerverre</param>
		/// <returns></returns>
        private ViewerSettings createViewerSettings(string selectedfile, string tempfilename, bool editable, bool upload)
        {
            ViewerSettings vs = new ViewerSettings(selectedfile, tempfilename, editable, upload, this.host, this.user, this.pass);
            return vs;
        }

		/// <summary>
		/// A paraméterként kapott ViewerSettings objektummal megjeleníti a letöltés formját
		/// </summary>
		/// <param name="vs">A fájlinformációkat tartalmazó ViewerSettings objektum</param>
        private void showDownloadForm(ViewerSettings vs)
        {
			DownloadForm downloadform = new DownloadForm(vs) { StartPosition = FormStartPosition.CenterParent, DownloadCallback = new DownloadDelegate(this.ViewCallback) };
            downloadform.ShowDialog(this);
        }

		/// <summary>
		/// Megjeleníti a törlést végző formot
		/// </summary>
		/// <remarks>
		/// A törlés előtt figyelmeztető üzenetet küldünk a felhasználónak, ezután a bejelölt elemek listájával konstruálunk
		/// egy DeleteForm-ot, ami elvégzi a törlést
		/// </remarks>
		/// <param name="checkeditems">a törlendő elemek kollekciója</param>
		/// <param name="isLocal">igaz érték esetén a számítógépről, hamis érték esetén a szerverről törlünk</param>
        private void showDeleteForm(ListView.ListViewItemCollection checkeditems, bool isLocal)
        {
            DialogResult törlés;
            DeleteForm deleteform;
            törlés = MessageBox.Show("Tényleg törli a kijelölt elem(ek)et?", "Figyelmeztetés", MessageBoxButtons.YesNo);
            if (törlés == DialogResult.Yes)
            {
				deleteform = new DeleteForm(checkeditems, (isLocal ? localHeaderLabel.Text : remoteHeaderLabel.Text), isLocal, pattern, ssh) { StartPosition = FormStartPosition.CenterParent, DeleteDataCallback = new RefreshDelegate(this.RefreshCallback) };
                deleteform.ShowDialog(this);
            }
        }

		/// <summary>
		/// Megjeleníti a másolást végző formot a megfelelő paraméterekkel
		/// </summary>
		/// <param name="checkeditems">a másolandó elemek kollekciója</param>
		/// <param name="isLocal">igaz érték esetén a szerverre, hamis érték esetén a szerverről másolunk</param>
		private void showCopyForm(ListView.ListViewItemCollection checkeditems, bool isLocal)
		{
			CopyForm copyform = new CopyForm(checkeditems, (isLocal ? localHeaderLabel.Text : remoteHeaderLabel.Text), (isLocal ? remoteHeaderLabel.Text : localHeaderLabel.Text), isLocal, host, user, pass) { StartPosition = FormStartPosition.CenterParent, CopyCallback = new RefreshDelegate(this.RefreshCallback) };
			copyform.ShowDialog(this);
		}

        #endregion

        #region Naplófájl megtekintése

		/// <summary>
		/// Naplófájl megtekintése
		/// </summary>
		/// <remarks>
		/// Letölti és a beállított nézőkében megjeleníti a naplófájlt, ha létezik
		/// </remarks>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void viewLogButtton_Click(object sender, EventArgs e)
        {
            try
            {
                String tempFileName = Path.Combine(TEMP_PATH, PROG_LOG);
                showDownloadForm(createViewerSettings(remoteHeaderLabel.Text + "/" + PROG_LOG, tempFileName, false, false));
            }
            catch (Exception)
            {
                captureMethod("Naplófájl megtekintése - Hiba", "Hiba a naplófájl lekérése során.");
                ExceptionHandler();
            }
        }

        #endregion

        #region Tesztelő kimenete

		/// <summary>
		/// Tesztelő kimenetének megtekintése
		/// </summary>
		/// <remarks>
		/// A beállított nézőkével letöltjük és megjelenítjük a tesztelő kimenetét
		/// </remarks>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void viewTestOutButton_Click(object sender, EventArgs e)
        {
            try
            {
                String tempFileName = Path.Combine(TEMP_PATH, PROG_OUT);
                showDownloadForm(createViewerSettings(remoteHeaderLabel.Text + "/" + PROG_OUT, tempFileName, false, false));
            }
            catch (Exception)
            {
                captureMethod("Tesztelő kimenetének megtekintése - Hiba", "Hiba a naplófájl lekérése során.");
                ExceptionHandler();
            }
        }

        #endregion

        #region Eredmény megtekintése

		/// <summary>
		/// Eredmény megtekintése
		/// </summary>
		/// <remarks>
		/// Kiírja a hallgatónak az aktuálisan kiválasztott tárgyra vonatkozó eredményét.
		/// </remarks>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void viewResultButton_Click(object sender, EventArgs e)
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;
				ssh.WriteLine(String.Format(subjects[groupsComboBox.SelectedIndex].Eredmeny));
                captureMethod("Eredmények", readText());
                Cursor.Current = Cursors.Arrow;
            }
            catch (Exception)
            {
                Cursor.Current = Cursors.Arrow;
                captureMethod("Eredmények - Hiba", "Hiba az eredmény lekérése során.");
				ExceptionHandler();
            }
        }

        #endregion

        #region Lábléc

		/// <summary>
		/// A fájllista alatt kiírja a láblécbe az aktuálisan kijelölt fájl/könyvtár nevét, amennyiben a ListView-nek van kijelölt eleme
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void ListView_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                if (remoteFilesListViewFocused)
                {
                    if (remoteFilesListView.SelectedItems.Count != 0 && remoteFilesListView.SelectedItems[0].SubItems[0].Text != "..")
                    {
                        remoteFooterLabel.Text = remoteFilesListView.SelectedItems[0].SubItems[0].Text;
                    }
                    else
                    {
                        remoteFooterLabel.Text = string.Empty;
                    }
                }
                else
                {
                    if (localFilesListView.SelectedItems.Count != 0 && localFilesListView.SelectedItems[0].SubItems[0].Text != "..")
                    {
                        localFooterLabel.Text = localFilesListView.SelectedItems[0].SubItems[0].Text;
                    }
                    else
                    {
                        localFooterLabel.Text = string.Empty;
                    }
                }
            }
            catch
            {
				if ( remoteFilesListViewFocused )
				{
					remoteFooterLabel.Text = string.Empty;
				}
				else if ( localFilesListViewFocused )
				{
					localFooterLabel.Text = string.Empty;
				}
			}
        }

        #endregion

        #region Callback függvények a szerkesztéshez / feltöltéshez / megtekintéshez

		/// <summary>
		/// A Nézőke és Szerkesztés parancsok callback függvénye
		/// </summary>
		/// <param name="success">ha értéke igaz, akkor a fájlátvitel sikeres volt, és a letöltött fájlt megnyithatjuk a nézőkében/szerkesztőben</param>
		/// <param name="edit">ha értéke igaz, akkor a szerkesztőben, különben a nézőkében nyitjuk meg a fájlt</param>
		/// <param name="settings">a letöltött fájl adatai</param>
        private void ViewCallback(bool success, bool edit, ViewerSettings settings)
        {
            this.settings = settings;

			try
			{
				// ha a folyamat sikeres volt
				if (success)
				{
					// ha csak megtekintjük a fájlt, megnyitjuk a beállított nézőkében
					if (!edit)
					{
						// Megnyitjuk a fájlt a beállított nézőkében
						File.SetAttributes(this.settings.Tempfilename, FileAttributes.ReadOnly);
						Process viewer = new Process();
						viewer.StartInfo.FileName = Settings.Default.viewer;
						viewer.StartInfo.Arguments = this.settings.Tempfilename;
						viewer.StartInfo.ErrorDialog = true;
						viewer.Start();
					}
					// megnyitjuk a szerkesztéshez szükséges formot
					else
					{
						EditForm form = new EditForm(settings) { StartPosition = FormStartPosition.CenterParent, Callback = new UploadDelegate(this.UploadCallback) };
						form.ShowDialog();
					}
				}
			}
			catch (Exception)
			{
				MessageBox.Show("Hiba a fájl megnyitása során!");
			}
        }

		/// <summary>
		/// A szerkesztés befejeztével feltöltjük a fájlt a szerverre.
		/// </summary>
		/// <param name="settings">a feltöltendő fájl adatai</param>
        private void UploadCallback(ViewerSettings settings)
        {
            DialogResult dr = MessageBox.Show("Frissíti a következő fájlt: " + settings.Selectedfile + " ?", "Figyelmeztetés", MessageBoxButtons.YesNo);
            if (dr == DialogResult.Yes)
            {
				DownloadForm form = new DownloadForm(settings) { StartPosition = FormStartPosition.CenterScreen };
                form.ShowDialog();
            }
            changeDir(mainTextBox, remoteFilesListView, remoteHeaderLabel);
        }

		/// <summary>
		/// A fájllista frissítésére szolgáló callback függvény törlés és másolás befejezése esetén
		/// </summary>
		private void RefreshCallback()
        {
			displayFolderList( localHeaderLabel.Text );
			changeDir( mainTextBox, remoteFilesListView, remoteHeaderLabel );
        }

        #endregion

        #region Helyi menü

		/// <summary>
		/// A 'Nézőke' eseménykezelőjének meghívása a helyi menüből
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void nézőkeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            viewButton_Click(sender, e);
        }

		/// <summary>
		/// A 'Szerkesztés' eseménykezelőjének meghívása a helyi menüből
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void szerkesztésToolStripMenuItem_Click(object sender, EventArgs e)
        {
            editButton_Click(sender, e);
        }

		/// <summary>
		/// Az 'Átnevezés' eseménykezelőjének meghívása a helyi menüből
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void átnevezésToolStripMenuItem_Click(object sender, EventArgs e)
        {
            renameButton_Click(sender, e);
        }

		/// <summary>
		/// A 'Törlés' eseménykezelőjének meghívása a helyi menüből
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void törlésToolStripMenuItem_Click(object sender, EventArgs e)
        {
            deleteButton_Click(sender, e);
        }

		/// <summary>
		/// A 'Tulajdonságok' eseménykezelőjének meg
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void PropertiesButton_Click(object sender, EventArgs e)
        {
            PropertiesForm attrForm;                // az attribútumok módosítására szolgáló form
            ListViewItem actitem;                   // az aktuálisan kijelölt elem

            try
            {
                Cursor.Current = Cursors.WaitCursor;

                if (remoteFilesListViewFocused)
                {
                    // csak akkor végezzük el a műveletet, ha van kijelölt elem
                    if (remoteFilesListView.SelectedItems.Count != 0 && remoteFilesListView.SelectedItems[0].SubItems[0].Text != "..")
                    {
                        actitem = remoteFilesListView.SelectedItems[0];
                        actAttr = actitem.SubItems[3].Text;
						attrForm = new PropertiesForm(actitem.SubItems[3].Text, actitem.SubItems[0].Text, actitem.SubItems[1].Text, actitem.SubItems[2].Text) { PropertiesDataCallback = new PropertiesDelegate(this.modifyPropertiesCallback) };
                        attrForm.ShowDialog();              // form megnyitása
                    }
                }
                else
                {
                    if (localFilesListView.SelectedItems.Count != 0 && localFilesListView.SelectedItems[0].SubItems[0].Text != "..")
                    {
                        actitem = localFilesListView.SelectedItems[0];
                        ShowFileProperties(localHeaderLabel.Text + "/" + actitem.Text);
                    }
                }
                Cursor.Current = Cursors.Arrow;
            }
            catch (Exception)
            {
                Cursor.Current = Cursors.Arrow;
                MessageBox.Show("A fájl/könyvtár attribútuma nem változtatható meg.");
                ExceptionHandler();
            }
        }

		/// <summary>
		/// A 'Másolás' eseménykezelőjének meghívása a helyi menüből
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void másolásToolStripMenuItem_Click(object sender, EventArgs e)
        {
            copyButton_Click(sender, e);
        }

		/// <summary>
		/// Az 'Új könyvtár' eseménykezelőjének meghívása a helyi menüből
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void újKönyvtárToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            mkdirButton_Click(sender, e);
        }

		/// <summary>
		/// Új fájl létrehozása a szerveren vagy a helyi számítógépen
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void újFájlToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Cursor.Current = Cursors.WaitCursor;
            NewFileForm newFileForm = new NewFileForm((remoteFilesListViewFocused ? false : true), true) { newFileCallback = new NewFileDelegate(this.NewFileDataCallbackFn) };
            newFileForm.ShowDialog();
            Cursor.Current = Cursors.Arrow;
        }

        /// <summary>
        /// A helyi menü megjelenítését végző eseménykezelő
        /// </summary>
		/// <remarks>
		/// Jobb klikk esetén a helyi menüből választhatjuk a kijelölt elem tulajdonságait megjelenítő/beállító formot
		/// (a szerveren tárolt állományok esetén a saját implementálású Tulajdonságok form,
		/// a helyi gépen tárolt állományok esetén a Windows saját Tulajdonságok-formja jelenik meg)
		/// </remarks>
        /// <param name="sender"></param>
        /// <param name="e"></param>
		private void ListView_MouseClick(object sender, MouseEventArgs e)
        {
            try
            {
                ListView list = (remoteFilesListViewFocused ? remoteFilesListView : localFilesListView);
                // jobb klikk detektálása és az első két bejegyzés figyelmen kívül hagyása
                if (e.Button == MouseButtons.Right && list.SelectedItems.Count != 0 && list.SelectedItems[0].SubItems[1].Text != "<root>" && list.SelectedItems[0].SubItems[0].Text != "..")
                {
                    // könyvtárak esetén nem elérhető a szerkesztés és a nézőke, csak fájlok esetén
					szerkesztésToolStripMenuItem.Enabled = (list.SelectedItems[0].SubItems[1].Text.Equals("<dir>") ? false : true);
					nézőkeToolStripMenuItem.Enabled = (list.SelectedItems[0].SubItems[1].Text.Equals("<dir>") ? false : true);
					másolásToolStripMenuItem.Enabled = (!fileTransferMode ? false : true);

                    // a klikkelés helyén jelenítjük meg a helyi menüt
                    contextMenuStrip1.Show(list, e.X, e.Y);
                }
            }
            catch { }
        }

        #endregion

        #region Fájllista rendezése az oszlopfejlécre kattintva

		/// <summary>
		/// Fájllista rendezése az oszlopfejlécre kattintva (növekvő vagy csökkenő sorrendben) a ListViewSorter osztály által
		/// </summary>
        /// <see cref="http://support.microsoft.com/kb/319401"/>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void FilesListView_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            if (e.Column == lvSorter.SortColumn)
            {
                // A rendezés irányának megfordítása, ha az oszlop, amelyre klikkeltünk az az oszlop, amely rendezés alatt ált
                if (lvSorter.Order == SortOrder.Ascending)
                {
                    lvSorter.Order = SortOrder.Descending;
                }
                else
                {
                    lvSorter.Order = SortOrder.Ascending;
                }
            }
            else
            {
                // Az oszlop számának beállítása, amely szerint rendezünk
                lvSorter.SortColumn = e.Column;
                lvSorter.Order = SortOrder.Ascending;
            }

            // A rendezés elvégzése az aktuális ListView-n
            actListView = (remoteFilesListViewFocused ? remoteFilesListView : localFilesListView);
            actListView.Sort();
        }

        #endregion

        #region Helyi fájlok/könyvtárak/meghajtók kezelése

		/// <summary>
		/// A helyi gépen található meghajtók listájának felépítése
		/// </summary>
        protected void loadLocalDrives()
        {
            // Meghajtók megjelenítése
            int iconindex = 0;
            localDrivesComboBox.Items.Clear();
            foreach (DriveInfo drive in System.IO.DriveInfo.GetDrives().ToArray())
            {
				// a meghajtókat a könnyebb azonosítás érdekében egy-egy ikonnal is ellátjuk
                if (drive.IsReady == true)
                {
                    if (drive.DriveType == DriveType.Fixed)			{ iconindex = 11;	}
                    else if (drive.DriveType == DriveType.CDRom)	{ iconindex = 5;	}
                    else if (drive.DriveType == DriveType.Removable){ iconindex = 7;	}
                    else                                            { iconindex = 11;	}
                    ImageDriveComboBox_addItem(localDrivesComboBox, drive.Name, iconindex);
                }
            }
            ImageDriveComboBox_addItem(localDrivesComboBox, "Asztal", 0);
            ImageDriveComboBox_addItem(localDrivesComboBox, "Frissítés", 30);
            if (localDrivesComboBox.Items.Count != 0)
            {
                localDrivesComboBox.SelectedIndex = 0;
            }
        }

		/// <summary>
		/// A helyi meghajtók legördülő menüjében történő navigálást végző eseménykezelő
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void localDrivesComboBox_SelectionChangeCommitted(object sender, EventArgs e)
        {
			// Frissítés
            if (localDrivesComboBox.SelectedIndex == localDrivesComboBox.Items.Count - 1)
            {
                loadLocalDrives();
                displayFolderList(localHeaderLabel.Text);
            }
			// Asztal könyvtár
			else if ( localDrivesComboBox.SelectedIndex == localDrivesComboBox.Items.Count - 2 )
			{
				displayFolders();
			}
			// Ha a meghajtó nem létezik
			else if ( !Directory.Exists( localDrivesComboBox.Items[localDrivesComboBox.SelectedIndex].Text ) )
			{
				MessageBox.Show( String.Format( "A meghajtó nem létezik: {0}", localDrivesComboBox.Items[localDrivesComboBox.SelectedIndex].Text ) );
				loadLocalDrives();
				displayFolders();
			}
			// Egyéb meghajtók
			else
			{
				displayFolders();
			}
        }

		/// <summary>
		/// A legördülő menüben kijelölt meghajtó/könyvtár kiválasztása és tartalmának megjelenítése
		/// </summary>
        protected void displayFolders()
        {
            DirectoryInfo theFolder;
            FileInfo theFile;

            try
            {
                string folderPath = localDrivesComboBox.SelectedItem.ToString();
                if (folderPath.Equals("Asztal"))
                {
                    theFolder = new DirectoryInfo(Environment.GetFolderPath(System.Environment.SpecialFolder.DesktopDirectory));
                    if (theFolder.Exists)
                    {
                        displayFolderList(theFolder.FullName);
                        return;
                    }
                }
                else
                {
                    theFolder = new DirectoryInfo(folderPath);
                    if (theFolder.Exists)
                    {
                        displayFolderList(theFolder.FullName);
                        return;
                    }
                    theFile = new FileInfo(folderPath);
                    if (theFile.Exists)
                    {
                        displayFolderList(theFile.Directory.FullName);
                        return;
                    }
                }
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
				ExceptionHandler();
            }
        }

		/// <summary>
		/// A paraméterként kapott helyi könyvtár tartalmát jeleníti meg a főbb fájltípusoknak megfelelő ikonnal
		/// </summary>
		/// <param name="folderFullName">a megjelenítendő könyvtár</param>
        protected void displayFolderList(string folderFullName)
        {
			try
			{
				DirectoryInfo theFolder;
				string név = string.Empty;
				string méret = string.Empty;
				string jogosultság = string.Empty;
				string módosítva = string.Empty;
				int ikon = 0;

				localFilesListView.Items.Clear();

				theFolder = new DirectoryInfo(folderFullName);
				if (!theFolder.Exists)
				{
					throw new DirectoryNotFoundException("A következő könyvtár nem található: " + folderFullName);
				}
				localHeaderLabel.Text = theFolder.FullName;
				ListView_addItem(localFilesListView, new string[] { "..", "<dir>", "", "" }, 26, COLOR1, String.Empty);

				// minden könyvtárat listázunk az adott szülőkönyvtáron belül
				foreach (DirectoryInfo nextFolder in theFolder.GetDirectories())
				{
					// rejtett könyvtárak megjelenítése/elrejtése
					if (!hiddenFiles && (nextFolder.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
					{
						continue;
					}
					név = nextFolder.Name;
					jogosultság = setAttributes(nextFolder.Attributes);
					méret = "<dir>";
					módosítva = nextFolder.LastWriteTime.Year.ToString("D4") + "-" + nextFolder.LastWriteTime.Month.ToString("D2") + "-" + nextFolder.LastWriteTime.Day.ToString("D2") + " " + nextFolder.LastWriteTime.Hour.ToString("D2") + ":" + nextFolder.LastWriteTime.Minute.ToString("D2");
					ListView_addItem(localFilesListView, new string[] { név, méret, módosítva, jogosultság }, 0, ((nextFolder.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden) ? COLOR4 : COLOR1, méret);
				}
				// minden fájlt listázunk az adott könyvtáron belül
				foreach (FileInfo nextFile in theFolder.GetFiles())
				{
					// rejtett fájlok megjelenítése/elrejtése
					if (!hiddenFiles && (nextFile.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
					{
						continue;
					}
					név = nextFile.Name;
					jogosultság = setAttributes(nextFile.Attributes);
					méret = setSize(nextFile.Length);
					módosítva = nextFile.LastWriteTime.Year.ToString("D4") + "-" + nextFile.LastWriteTime.Month.ToString("D2") + "-" + nextFile.LastWriteTime.Day.ToString("D2") + " " + nextFile.LastWriteTime.Hour.ToString("D2") + ":" + nextFile.LastWriteTime.Minute.ToString("D2");

					// képfájlok
					if (nextFile.Extension.ToLower().Equals(".mng") || nextFile.Extension.ToLower().Equals(".pct") || nextFile.Extension.ToLower().Equals(".bmp") || nextFile.Extension.ToLower().Equals(".gif") || nextFile.Extension.ToLower().Equals(".jpg") || nextFile.Extension.ToLower().Equals(".jpeg") || nextFile.Extension.ToLower().Equals(".png") || nextFile.Extension.ToLower().Equals(".psd") || nextFile.Extension.ToLower().Equals(".psp") || nextFile.Extension.ToLower().Equals(".thm") || nextFile.Extension.ToLower().Equals(".tif") || nextFile.Extension.ToLower().Equals(".3dm") || nextFile.Extension.ToLower().Equals(".ps") || nextFile.Extension.ToLower().Equals(".svg") || nextFile.Extension.ToLower().Equals(".3dmf") || nextFile.Extension.ToLower().Equals(".dwg") || nextFile.Extension.ToLower().Equals(".pln") || nextFile.Extension.ToLower().Equals(".ai") || nextFile.Extension.ToLower().Equals(".eps") || nextFile.Extension.ToLower().Equals(".drw") || nextFile.Extension.ToLower().Equals(".dxf") || nextFile.Extension.ToLower().Equals(".ico"))
						ikon = 9;
					// hangfájlok
					else if (nextFile.Extension.ToLower().Equals(".aac") || nextFile.Extension.ToLower().Equals(".aif") || nextFile.Extension.ToLower().Equals(".iff") || nextFile.Extension.ToLower().Equals(".flac") || nextFile.Extension.ToLower().Equals(".m3u") || nextFile.Extension.ToLower().Equals(".mid") || nextFile.Extension.ToLower().Equals(".midi") || nextFile.Extension.ToLower().Equals(".mp3") || nextFile.Extension.ToLower().Equals(".mpa") || nextFile.Extension.ToLower().Equals(".ra") || nextFile.Extension.ToLower().Equals(".wav") || nextFile.Extension.ToLower().Equals(".wma"))
						ikon = 3;
					// videofájlok
					else if (nextFile.Extension.ToLower().Equals(".3gp") || nextFile.Extension.ToLower().Equals(".asf") || nextFile.Extension.ToLower().Equals(".asx") || nextFile.Extension.ToLower().Equals(".avi") || nextFile.Extension.ToLower().Equals(".flv") || nextFile.Extension.ToLower().Equals(".mkv") || nextFile.Extension.ToLower().Equals(".mov") || nextFile.Extension.ToLower().Equals(".mp4") || nextFile.Extension.ToLower().Equals(".mpg") || nextFile.Extension.ToLower().Equals(".rm") || nextFile.Extension.ToLower().Equals(".qt") || nextFile.Extension.ToLower().Equals(".swf") || nextFile.Extension.ToLower().Equals(".vob") || nextFile.Extension.ToLower().Equals(".wmv"))
						ikon = 10;
					// tömörített fájlok
					else if (nextFile.Extension.ToLower().Equals(".7z") || nextFile.Extension.ToLower().Equals(".rar") || nextFile.Extension.ToLower().Equals(".gz") || nextFile.Extension.ToLower().Equals(".tar") || nextFile.Extension.ToLower().Equals(".sea") || nextFile.Extension.ToLower().Equals(".sit") || nextFile.Extension.ToLower().Equals(".sitx") || nextFile.Extension.ToLower().Equals(".zip"))
						ikon = 15;
					// futtatható állományok
					else if (nextFile.Extension.ToLower().Equals(".cgi") || nextFile.Extension.ToLower().Equals("com") || nextFile.Extension.ToLower().Equals(".exe") || nextFile.Extension.ToLower().Equals(".pif") || nextFile.Extension.ToLower().Equals(".vb") || nextFile.Extension.ToLower().Equals("ws"))
						ikon = 8;
					// batch fájl
					else if (nextFile.Extension.ToLower().Equals(".bat"))
						ikon = 4;
					// általános fájlok
					else
						ikon = 1;

					ListView_addItem(localFilesListView, new string[] { név, méret, módosítva, jogosultság }, ikon, ((nextFile.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden ? COLOR4 : COLOR1), nextFile.Length.ToString());
				}
				localFilesListView.Items[0].Selected = true;
			}
			catch (DirectoryNotFoundException dnfexc)
			{
				// hiba esetén az alapértelmezett könyvtárat jelenítjük meg
				MessageBox.Show(dnfexc.Message);
				loadLocalDrives();
				displayFolders();
				return;
            }
			catch (Exception exc)
			{
				MessageBox.Show( "Hiba a könyvtár tartalmának megjelenítése során.\r\n\r\n" + exc.Message);
				ExceptionHandler();
			}
        }

		/// <summary>
		/// Dupla kattintás eseménykezelője a helyi gépen tárolt fájlok listáján
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void localFilesListView_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            localFilesListView_PerformMouseDoubleClick();
        }

		/// <summary>
		/// Dupla kattintás kezelése a helyi gépen tárolt fájlok listájánál
		/// </summary>
		/// <remarks>
		/// Ha könyvtárat választottunk ki, akkor könyvtárat váltunk, különben megnyitjuk a fájlt az alapértelmezett programmal.
		/// </remarks>
        private void localFilesListView_PerformMouseDoubleClick()
        {
            try
            {
                string selectedString = localFilesListView.SelectedItems[0].Text;
                string fullFileName = Path.Combine(localHeaderLabel.Text, selectedString);
                if (localFilesListView.SelectedItems[0].SubItems[1].Text.Equals("<dir>"))
                {
                    displayFolderList(fullFileName);
                }
                else
                {
					Process p = new Process();
					p.StartInfo.FileName = fullFileName;
					p.StartInfo.ErrorDialog = true;
                    p.Start();
                }
            }
            catch (Exception e)
            {
				MessageBox.Show(e.Message);
				displayFolderList(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments));
				ExceptionHandler();
            }
        }

        #endregion

        #region Segédmetódusok az attribútumok és méret meghatározásához

		/// <summary>
		/// A helyi fájlok főbb attribútumainak megjelenítése a ListView-ben
		/// </summary>
		/// <param name="attributes">az állomány attribútumai</param>
		/// <returns>a főbb attribútumok szöveges formában</returns>
        private string setAttributes(FileAttributes attributes)
        {
            // a helyi fájlok és könyvtárak attribútumainak beállítása
            string jogosultság = string.Empty;
            jogosultság += (((attributes & FileAttributes.Directory) == FileAttributes.Directory) ? "d" : "-");
            jogosultság += (((attributes & FileAttributes.Hidden) == FileAttributes.Hidden) ? "h" : "-");
            jogosultság += (((attributes & FileAttributes.System) == FileAttributes.System) ? "s" : "-");
            jogosultság += (((attributes & FileAttributes.Archive) == FileAttributes.Archive) ? "a" : "-");
            jogosultság += (((attributes & FileAttributes.Compressed) == FileAttributes.Compressed) ? "c" : "-");
            jogosultság += (((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) ? "r" : "-");
            jogosultság += (((attributes & FileAttributes.Temporary) == FileAttributes.Temporary) ? "t" : "-");
            return jogosultság;
        }

		/// <summary>
		/// A fájllista felépítésénél a méret meghatározására szolgáló metódus
		/// </summary>
		/// <param name="size">a fájlméret bájtokban</param>
		/// <returns>a fájlméret a legmegfelelőbb mértékegységben (dinamikusan meghatározva)</returns>
        private string setSize(long size)
        {
            // méret dinamikus meghatározása
            string méret = string.Empty;
            if (size < 1024)
            {
                méret = string.Format( "{0:d} b", size );
            }
            else if (size >= 1024 && size <= System.Math.Pow(1024, 2))
            {
                double kilo = (double)size / 1024;
				méret = string.Format( "{0:.#} k", kilo );
            }
            else if (size >= System.Math.Pow(1024, 2) && size < System.Math.Pow(1024, 3))
            {
                double mega = (double)size / System.Math.Pow(1024, 2);
				méret = string.Format( "{0:.#} M", mega );
            }
            else if (size >= System.Math.Pow(1024, 3) && size < System.Math.Pow(1024, 4))
            {
                double giga = (double)size / System.Math.Pow(1024, 3);
				méret = string.Format( "{0:.#} G", giga );
            }
            return méret;
        }

        #endregion

        #region Segédmetódusok a ComboBox és a ListView elemeinek feltöltéséhez

        /// <summary>
		/// Hozzáadja az első paraméterként kapott ImageComboBox elemeihez a további paraméterek által meghatározott elemet
        /// </summary>
		/// <param name="combobox">az ImageComboBox, amelyhez hozzáadjuk az új elemet</param>
        /// <param name="text">az új elem szöveges tartalma</param>
        /// <param name="iconindex">az új elem ikonja</param>
		private void ImageDriveComboBox_addItem(ImageComboBox.ImageComboBox combobox, string text, int iconindex)
        {
			ImageComboBox.ImageComboBoxItem item = new ImageComboBox.ImageComboBoxItem(text) { ImageIndex = iconindex };
            combobox.Items.Add(item);
        }

		/// <summary>
		/// Hozzáadja az első paraméterként kapott ListView elemeihez a további paraméterek által meghatározott elemet
		/// </summary>
		/// <param name="listview">a ListView, amelyhez hozzáadjuk az új elemet</param>
		/// <param name="content">az új elem szöveges tartalma</param>
		/// <param name="iconindex">az új elem ikonja</param>
		/// <param name="color">az új elem színe (a rejtett fájlok halványabb színnel jelennek meg)</param>
        private void ListView_addItem(ListView listview, string[] content, int iconindex, System.Drawing.Color color, String tag)
        {
			ListViewItem item = new ListViewItem(content) { ImageIndex = iconindex, UseItemStyleForSubItems = false };
            item.SubItems[0].ForeColor = color;
            item.Tag = tag;
            listview.Items.Add(item);
        }

        #endregion

        #region Fájl tulajdonságainak megjelenítése

		/// <summary>
		/// Fájl/könyvtár tulajdonságainak megtekintése a Windows Shell függvényei segítségével
		/// </summary>
		/// <param name="filename">a fájl/könyvtár, amelynek a tulajdonságait szeretnénk megjeleníteni</param>
        public static void ShowFileProperties(string filename)
        {
            SHELLEXECUTEINFO info = new SHELLEXECUTEINFO();
            info.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(info);
            info.lpVerb = "properties";
            info.lpFile = filename;
            info.nShow = SW_SHOW;
            info.fMask = SEE_MASK_INVOKEIDLIST;
            ShellExecuteEx(ref info);
        }

        private const int SW_SHOW = 5;
        private const uint SEE_MASK_INVOKEIDLIST = 12;

        [DllImport("shell32.dll", CharSet = CharSet.Auto)]
        static extern bool ShellExecuteEx(ref SHELLEXECUTEINFO lpExecInfo);

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]

        public struct SHELLEXECUTEINFO
        {
            public int cbSize;
            public uint fMask;
            public IntPtr hwnd;
            public String lpVerb;
            public String lpFile;
            public String lpParameters;
            public String lpDirectory;
            public int nShow;
            public int hInstApp;
            public int lpIDList;
            public String lpClass;
            public int hkeyClass;
            public uint dwHotKey;
            public int hIcon;
            public int hProcess;
        }

        #endregion

        #region Fejlécre (panelre vagy labelre) kattintva váltunk a két panel között

		/// Amikor a valamelyik fejléc Panel-re vagy a Panelben levő Label-re kattintunk,
		/// akkor a fókusz a hozzá tartozó listview-re kerül át

		/// <summary>
		/// A szerver fájljainak feljécére történő kattintással áthelyezzük a fókuszt a hozzá tartozó ListView-re
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void remoteHeaderPanel_Click(object sender, EventArgs e)
        {
            remoteFilesListView.Focus();
        }

		/// <summary>
		/// A helyi fájlok feljécére történő kattintással áthelyezzük a fókuszt a hozzá tartozó ListView-re
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void localHeaderPanel_Click(object sender, EventArgs e)
        {
            localFilesListView.Focus();
        }

		/// <summary>
		/// Az aktuális szerver-könyvtár címkéjére történő kattintással áthelyezzük a fókuszt a hozzá tartozó ListView-re
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void remoteHeaderLabel_Click(object sender, EventArgs e)
        {
            remoteFilesListView.Focus();
        }

		/// <summary>
		/// Az aktuális helyi könyvtár címkéjére történő kattintással áthelyezzük a fókuszt a hozzá tartozó ListView-re
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void localHeaderLabel_Click(object sender, EventArgs e)
        {
            localFilesListView.Focus();
        }

        #endregion

        #region Remote/Local ListView közötti fókusz változásának követése

		/// <summary>
		/// Átállítja a fókusz változását követő adattagokat és a színeket a helyi könyvtárra, amennyiben ez a ListView kerül fókuszba
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        void localFilesListView_GotFocus(object sender, EventArgs e)
        {
            localFilesListViewFocused = true;
            remoteFilesListViewFocused = false;
			changeColor(true);
        }

		/// <summary>
		/// Átállítja a fókusz változását követő adattagokat és a színeket a szerver könyvtárára, amennyiben ez a ListView kerül fókuszba
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        void remoteFilesListView_GotFocus(object sender, EventArgs e)
        {
            localFilesListViewFocused = false;
            remoteFilesListViewFocused = true;
			changeColor(false);
        }

		/// <summary>
		/// Átállítja a fókusz változását követő adattagokat és a színeket a helyi könyvtárra, amennyiben ez a legördülő menü kerül fókuszba
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void localDrivesComboBox_Click(object sender, EventArgs e)
		{
			localFilesListView_GotFocus( sender, e );
		}

		/// <summary>
		/// Átállítja a fókusz változását követő adattagokat és a színeket a szerver könyvtárára, amennyiben ez a legördülő menü kerül fókuszba
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void remoteDrivesComboBox_Click(object sender, EventArgs e)
		{
			remoteFilesListView_GotFocus(sender, e);
		}

        #endregion

        #region Mindent kijelöl / Kijelölés megszüntetése

		/// <summary>
		/// Kiválasztja a szerver könyvtárában levő összes elemet
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void remoteCheckAll_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            foreach (ListViewItem i in remoteFilesListView.Items) { i.Checked = true; }
			remoteFilesListView.Focus();
        }

		/// <summary>
		/// Megszünteti az összes elem kiválasztását a szerver könyvtárában
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void remoteUncheckAll_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
			foreach (ListViewItem i in remoteFilesListView.Items) { i.Checked = false; }
			remoteFilesListView.Focus();
        }

		/// <summary>
		/// Kiválasztja a helyi könyvtárban levő összes elemet
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void localCheckAll_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            foreach (ListViewItem i in localFilesListView.Items) { i.Checked = true; }
			localFilesListView.Focus();
        }

		/// <summary>
		/// Megszünteti az összes elem kiválasztását a helyi könyvtárban
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        private void localUncheckAll_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            foreach (ListViewItem i in localFilesListView.Items) { i.Checked = false; }
			localFilesListView.Focus();
        }

        #endregion
    }
}