#region License Information
/* HeuristicLab
* Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Windows.Forms;
using System.Xml.Serialization;
using HeuristicLab.Calendar;
using HeuristicLab.Hive.Slave.Console.SlaveConsoleService;
using ZedGraph;
namespace HeuristicLab.Hive.Slave.Console {
#region Delegates
//delegate to write text in the textbox from another process
public delegate void AppendTextDelegate(String message);
//delegate to remove text in the textbox from another process
public delegate void RemoveTextDelegate(int newLength, int maxChars);
//delegate fired, if a dialog is being closed
public delegate void OnDialogClosedDelegate(RecurrentEvent e);
#endregion
public partial class HiveSlaveConsole : Form {
#region Declarations
private static bool isfired = false;
//the logfilereader
private ILogReader logFileReader;
//communication with the slave
private SlaveConsoleCommunicatorClient slaveCommunicator;
//the timer for refreshing the gui
private System.Windows.Forms.Timer refreshTimer;
//the list of appointments in the calender
[XmlArray("Appointments")]
[XmlArrayItem("Appointment", typeof(Appointment))]
public List onlineTimes = new List();
public OnDialogClosedDelegate dialogClosedDelegate;
#endregion
#region Constructor
public HiveSlaveConsole() {
InitializeComponent();
InitTimer();
ConnectToSlave();
RefreshGui();
InitCalender();
InitLogFileReader();
}
#endregion
#region Methods
#region Client connection
private void ConnectToSlave() {
try {
slaveCommunicator = new SlaveConsoleCommunicatorClient();
slaveCommunicator.GetStatusInfosCompleted += new EventHandler(slaveCommunicator_GetStatusInfosCompleted);
slaveCommunicator.GetUptimeCalendarCompleted += new EventHandler(slaveCommunicator_GetUptimeCalendarCompleted);
slaveCommunicator.SetUptimeCalendarCompleted += new EventHandler(slaveCommunicator_SetUptimeCalendarCompleted);
} catch (Exception ex) {
ManageFatalException("Connection Error, check if Hive Slave is running!", "Connection Error", ex);
}
}
#endregion
#region Logging
private void InitLogFileReader() {
//logFileReader = new LogFileReader(AppDomain.CurrentDomain.BaseDirectory + @"/Hive.Slave.log");
logFileReader = new LogServiceReader();
logFileReader.MoreData += new MoreDataHandler(logFileReader_MoreData);
logFileReader.Start();
}
private void logFileReader_MoreData(object sender, string newData) {
int maxChars = txtLog.MaxLength;
if (newData.Length > maxChars) {
newData = newData.Remove(0, newData.Length - maxChars);
}
int newLength = this.txtLog.Text.Length + newData.Length;
if (newLength > maxChars) {
RemoveText(newLength, maxChars);
}
AppendText(newData);
}
private void RemoveText(int newLength, int maxChars) {
if (this.txtLog.InvokeRequired) {
this.txtLog.Invoke(new
RemoveTextDelegate(RemoveText), new object[] { newLength, maxChars });
} else {
this.txtLog.Text = this.txtLog.Text.Remove(0, newLength - (int)maxChars);
}
}
private void AppendText(string message) {
if (this.txtLog.InvokeRequired) {
this.txtLog.Invoke(new
AppendTextDelegate(AppendText), new object[] { message });
} else {
this.txtLog.AppendText(message);
}
}
#endregion
#region Gui Refresh
private void InitTimer() {
refreshTimer = new System.Windows.Forms.Timer();
refreshTimer.Interval = 1000;
refreshTimer.Tick += new EventHandler(refreshTimer_Tick);
refreshTimer.Start();
}
private void RefreshGui() {
try {
slaveCommunicator.GetStatusInfosAsync();
} catch (Exception ex) {
ManageFatalException("Connection Error, check if Hive Slave is running!", "Connection Error", ex);
}
}
private void UpdateGraph(StatusCommons sc) {
ZedGraphControl zgc = new ZedGraphControl();
GraphPane myPane = zgc.GraphPane;
myPane.GraphObjList.Clear();
myPane.Title.IsVisible = false; // no title
myPane.Border.IsVisible = false; // no border
myPane.Chart.Border.IsVisible = false; // no border around the chart
myPane.XAxis.IsVisible = false; // no x-axis
myPane.YAxis.IsVisible = false; // no y-axis
myPane.Legend.IsVisible = false; // no legend
myPane.Fill.Color = this.BackColor;
myPane.Chart.Fill.Type = FillType.None;
myPane.Fill.Type = FillType.Solid;
double allProgress = 0;
double done = 0;
/*if (jobs.Length == 0)
{
myPane.AddPieSlice(100, Color.Green, 0.1, "");
}
else
{
for (int i = 0; i < jobs.Length; i++)
{
allProgress += jobs[i].Progress;
} */
//done = allProgress / jobs.Length;
myPane.AddPieSlice((sc.FreeCores / (double)sc.TotalCores), Color.Red, 0, "");
myPane.AddPieSlice(((sc.TotalCores - sc.FreeCores) / (double)sc.TotalCores), Color.Green, 0, "");
// }
//Hides the slice labels
PieItem.Default.LabelType = PieLabelType.None;
myPane.AxisChange();
pbGraph.Image = zgc.GetImage();
}
#region Events
private void refreshTimer_Tick(object sender, EventArgs e) {
RefreshGui();
}
#endregion
#endregion
#region Calendar stuff
private void InitCalender() {
dvOnline.StartDate = DateTime.Now;
dvOnline.OnNewAppointment += new EventHandler(dvOnline_OnNewAppointment);
dvOnline.OnResolveAppointments += new EventHandler(dvOnline_OnResolveAppointments);
//get calender from slave
slaveCommunicator.GetUptimeCalendarAsync();
}
private bool CreateAppointment() {
DateTime from, to;
if (!string.IsNullOrEmpty(dtpFrom.Text) && !string.IsNullOrEmpty(dtpTo.Text)) {
if (chbade.Checked) {
//whole day appointment, only dates are visible
if (DateTime.TryParse(dtpFrom.Text, out from) && DateTime.TryParse(dtpTo.Text, out to) && from <= to)
onlineTimes.Add(CreateAppointment(from, to.AddDays(1), true));
else
MessageBox.Show("Incorrect date format", "Schedule Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
} else if (!string.IsNullOrEmpty(txttimeFrom.Text) && !string.IsNullOrEmpty(txttimeTo.Text)) {
//Timeframe appointment
if (DateTime.TryParse(dtpFrom.Text + " " + txttimeFrom.Text, out from) && DateTime.TryParse(dtpTo.Text + " " + txttimeTo.Text, out to) && from < to) {
if (from.Date == to.Date)
onlineTimes.Add(CreateAppointment(from, to, false));
else {
//more than 1 day selected
while (from.Date != to.Date) {
onlineTimes.Add(CreateAppointment(from, new DateTime(from.Year, from.Month, from.Day, to.Hour, to.Minute, 0, 0), false));
from = from.AddDays(1);
}
onlineTimes.Add(CreateAppointment(from, new DateTime(from.Year, from.Month, from.Day, to.Hour, to.Minute, 0, 0), false));
}
} else
MessageBox.Show("Incorrect date format", "Schedule Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
dvOnline.Invalidate();
return true;
} else {
MessageBox.Show("Error in create appointment, please fill out all textboxes!", "Schedule Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
}
private Appointment CreateAppointment(DateTime startDate, DateTime endDate, bool allDay) {
Appointment App = new Appointment();
App.StartDate = startDate;
App.EndDate = endDate;
App.AllDayEvent = allDay;
App.BorderColor = Color.Red;
App.Locked = true;
App.Subject = "Online";
App.Recurring = false;
return App;
}
private Appointment CreateAppointment(DateTime startDate, DateTime endDate, bool allDay, bool recurring, Guid recurringId) {
Appointment App = new Appointment();
App.StartDate = startDate;
App.EndDate = endDate;
App.AllDayEvent = allDay;
App.BorderColor = Color.Red;
App.Locked = true;
App.Subject = "Online";
App.Recurring = recurring;
App.RecurringId = recurringId;
return App;
}
private void DeleteAppointment() {
onlineTimes.Remove(dvOnline.SelectedAppointment);
}
private void DeleteRecurringAppointment(Guid recurringId) {
onlineTimes.RemoveAll(a => a.RecurringId.ToString() == dvOnline.SelectedAppointment.RecurringId.ToString());
}
private void ChangeRecurrenceAppointment(Guid recurringId) {
int hourfrom = int.Parse(txttimeFrom.Text.Substring(0, txttimeFrom.Text.IndexOf(':')));
int hourTo = int.Parse(txttimeTo.Text.Substring(0, txttimeTo.Text.IndexOf(':')));
List recurringAppointments = onlineTimes.Where(appointment => appointment.RecurringId == recurringId).ToList();
recurringAppointments.ForEach(appointment => appointment.StartDate = new DateTime(appointment.StartDate.Year, appointment.StartDate.Month, appointment.StartDate.Day, hourfrom, 0, 0));
recurringAppointments.ForEach(appointment => appointment.EndDate = new DateTime(appointment.EndDate.Year, appointment.EndDate.Month, appointment.EndDate.Day, hourTo, 0, 0));
DeleteRecurringAppointment(recurringId);
onlineTimes.AddRange(recurringAppointments);
}
public void DialogClosed(RecurrentEvent e) {
CreateDailyRecurrenceAppointments(e.DateFrom, e.DateTo, e.AllDay, e.IncWeeks, e.WeekDays);
}
private void CreateDailyRecurrenceAppointments(DateTime dateFrom, DateTime dateTo, bool allDay, int incWeek, HashSet daysOfWeek) {
DateTime incDate = dateFrom;
Guid guid = Guid.NewGuid();
while (incDate.Date <= dateTo.Date) {
if (daysOfWeek.Contains(incDate.Date.DayOfWeek))
onlineTimes.Add(CreateAppointment(incDate, new DateTime(incDate.Year, incDate.Month, incDate.Day, dateTo.Hour, dateTo.Minute, 0), allDay, true, guid));
incDate = incDate.AddDays(1);
}
dvOnline.Invalidate();
}
#region Calendar Events
private void btbDelete_Click(object sender, EventArgs e) {
Appointment selectedAppointment = dvOnline.SelectedAppointment;
if (dvOnline.SelectedAppointment != null) {
if (!selectedAppointment.Recurring)
DeleteAppointment();
else {
DialogResult res = MessageBox.Show("Delete all events in this series?", "Delete recurrences", MessageBoxButtons.YesNo);
if (res != DialogResult.Yes)
DeleteAppointment();
else
DeleteRecurringAppointment(selectedAppointment.RecurringId);
}
}
dvOnline.Invalidate();
}
private void chbade_CheckedChanged(object sender, EventArgs e) {
txttimeFrom.Visible = !chbade.Checked;
txttimeTo.Visible = !chbade.Checked;
}
private void dvOnline_OnSelectionChanged(object sender, EventArgs e) {
//btCreate.Enabled = true;
if (dvOnline.Selection == SelectionType.DateRange) {
dtpFrom.Text = dvOnline.SelectionStart.ToShortDateString();
dtpTo.Text = dvOnline.SelectionEnd.Date.ToShortDateString();
txttimeFrom.Text = dvOnline.SelectionStart.ToShortTimeString();
txttimeTo.Text = dvOnline.SelectionEnd.ToShortTimeString();
btCreate.Text = "Save";
}
if (dvOnline.Selection == SelectionType.Appointment) {
dtpFrom.Text = dvOnline.SelectedAppointment.StartDate.ToShortDateString();
dtpTo.Text = dvOnline.SelectedAppointment.EndDate.ToShortDateString();
txttimeFrom.Text = dvOnline.SelectedAppointment.StartDate.ToShortTimeString();
txttimeTo.Text = dvOnline.SelectedAppointment.EndDate.ToShortTimeString();
if (dvOnline.SelectedAppointment.Recurring)
//btCreate.Enabled = false;
//also change the caption of the save button
btCreate.Text = "Save changes";
}
if (dvOnline.Selection == SelectionType.None) {
//also change the caption of the save button
btCreate.Text = "Save";
}
}
private void mcOnline_DateChanged(object sender, DateRangeEventArgs e) {
dvOnline.StartDate = mcOnline.SelectionStart;
}
private void btCreate_Click(object sender, EventArgs e) {
if (dvOnline.Selection != SelectionType.Appointment) {
CreateAppointment();
} else {
//now we want to change an existing appointment
if (!dvOnline.SelectedAppointment.Recurring) {
if (CreateAppointment())
DeleteAppointment();
} else {
//change recurring appointment
//check, if only selected appointment has to change or whole recurrence
DialogResult res = MessageBox.Show("Change all events in this series?", "Change recurrences", MessageBoxButtons.YesNo);
if (res != DialogResult.Yes) {
if (CreateAppointment())
DeleteAppointment();
} else
ChangeRecurrenceAppointment(dvOnline.SelectedAppointment.RecurringId);
}
}
dvOnline.Invalidate();
}
private void btnRecurrence_Click(object sender, EventArgs e) {
Recurrence recurrence = new Recurrence();
recurrence.dialogClosedDelegate = new OnDialogClosedDelegate(this.DialogClosed);
recurrence.Show();
}
private void btnSaveCal_Click(object sender, EventArgs e) {
slaveCommunicator.SetUptimeCalendarAsync(onlineTimes);
}
private void dvOnline_OnResolveAppointments(object sender, ResolveAppointmentsEventArgs e) {
List Apps = new List();
foreach (Appointment m_App in onlineTimes)
if ((m_App.StartDate >= e.StartDate) &&
(m_App.StartDate <= e.EndDate))
Apps.Add(m_App);
e.Appointments = Apps;
}
private void btnUpdateCalender_Click(object sender, EventArgs e) {
slaveCommunicator.GetUptimeCalendarAsync();
}
private void dvOnline_OnNewAppointment(object sender, NewAppointmentEventArgs e) {
Appointment Appointment = new Appointment();
Appointment.StartDate = e.StartDate;
Appointment.EndDate = e.EndDate;
onlineTimes.Add(Appointment);
}
#endregion
#endregion
#region Slave communicator events
void slaveCommunicator_SetUptimeCalendarCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) {
if (e.Error == null) {
MessageBox.Show("Calendar successfully saved!", "Calender", MessageBoxButtons.OK, MessageBoxIcon.Information);
} else {
MessageBox.Show("Error saving calender \n" + e.Error.ToString(), "Calender", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
void slaveCommunicator_GetUptimeCalendarCompleted(object sender, GetUptimeCalendarCompletedEventArgs e) {
if (e.Error == null) {
if (e.Result != null) {
onlineTimes = e.Result.ToList();
onlineTimes.ForEach(a => a.BorderColor = Color.Red);
dvOnline.Invalidate();
} else {
onlineTimes = new List();
}
}
}
private void slaveCommunicator_GetStatusInfosCompleted(object sender, GetStatusInfosCompletedEventArgs e) {
if (e.Error == null) {
StatusCommons sc = e.Result;
lbGuid.Text = sc.ClientGuid.ToString();
lbConnectionStatus.Text = sc.Status.ToString();
lbJobdone.Text = sc.JobsDone.ToString();
lbJobsAborted.Text = sc.JobsAborted.ToString();
lbJobsFetched.Text = sc.JobsFetched.ToString();
this.Text = "Slave Console (" + sc.Status.ToString() + ")";
ListViewItem curJobStatusItem;
if (sc.Jobs != null) {
lvJobDetail.Items.Clear();
double progress;
foreach (JobStatus curJob in sc.Jobs) {
curJobStatusItem = new ListViewItem(curJob.JobId.ToString());
curJobStatusItem.SubItems.Add(curJob.Since.ToString());
lvJobDetail.Items.Add(curJobStatusItem);
}
lvJobDetail.Sort();
}
UpdateGraph(sc);
} else {
ManageFatalException("Connection Error, check if Hive Slave is running!", "Connection Error", null);
}
}
#endregion
#region Exception
private void ManageFatalException(string body, string caption, Exception e) {
if (!isfired) {
isfired = true;
refreshTimer.Stop();
DialogResult res;
if (e != null) {
res = MessageBox.Show(body + "\n" + e.Message + ": " + e.StackTrace, caption, MessageBoxButtons.OK, MessageBoxIcon.Error);
} else {
res = MessageBox.Show(body + " (no exception available)", caption, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
if (res == DialogResult.OK)
this.Close();
}
}
#endregion
#endregion
#region GUI Events
private void btn_slaveShutdown_Click(object sender, EventArgs e) {
DialogResult res = MessageBox.Show("Do you really want to shutdown the Hive Slace?", "Hive Slave Console", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (res == DialogResult.Yes) {
logFileReader.Stop();
slaveCommunicator.ShutdownClient();
this.Close();
}
}
#endregion
}
}