/// <summary> /// This will create a timetable file from a studentDataBundle instance /// </summary> /// <param name="studentDataBundle">The timetable to save</param> /// <returns></returns> public static async Task <bool> CreateTimetable(StudentDataBundle studentDataBundle) { var found = false; //whether a timetable with the same name exists try { //try to get timetable file with same name await DataFolder.GetFileAsync(studentDataBundle.Name + ".tb"); } catch { found = true; } //if it's found , then it cannot be made. Another name must be chosen if (!found) { var dialog = new MessageDialog("A StudentDataBundle with that name already exists.\nPlease chooose another name.", "Oops"); await dialog.ShowAsync(); return(false); } else { //create the file and asynchronously serialize the data bundle to xml then add the object to the list StorageFile file = await DataFolder.CreateFileAsync(studentDataBundle.Name + ".tb"); Stream filestream = await file.OpenStreamForWriteAsync(); await Task.Run(() => Serializer.Serialize(filestream, studentDataBundle)); Timetables.Add(studentDataBundle); return(true);//return success } }
public void FillWith(StudentDataBundle studentDataBundle) { timeLabels.Children.Clear(); root.Children.Clear(); if (studentDataBundle.Courses.Count > 0 && studentDataBundle.GetTotalInstances() > 0) { lowerBound = CoreTime.GetEarliest(studentDataBundle); upperBound = CoreTime.GetLatest(studentDataBundle); //set size based on whether there is a weekedend or not labelContainer.Width = ((studentDataBundle.hasWeekend()) ? 7 : 5) * Constants.EventControlWidth; this.Width = Constants.EventControlWidth * ((studentDataBundle.hasWeekend()) ? 7 : 5) + 43; this.Height = (upperBound.TotalMinutes - lowerBound.TotalMinutes) / 60 * Constants.EventControlHeight + 43; for (int x = 0; x < studentDataBundle.Courses.Count; x++) { Course model = studentDataBundle.Courses[x]; foreach (Instance instance in model.Instances) { //foreach instance we EventControl cont = new EventControl(model); //create a control cont.setTime(instance.StartTime, instance.EndTime); //set the text instances[instance.Day].Add(cont); //add it to the appropiate list root.Children.Add(cont); //add it to the view Canvas.SetLeft(cont, Constants.EventControlWidth * instance.Day); //set it at the x coord and y coord Canvas.SetTop(cont, ((instance.StartTime.TotalMinutes - lowerBound.TotalMinutes) / 60.0) * Constants.EventControlHeight); //take lenght in account (i.e 2 hour lesson) double dt = (instance.EndTime.TotalMinutes - instance.StartTime.TotalMinutes); double height = dt / 60; cont.Height = height * Constants.EventControlHeight; //set the height proportionately to the duration } } //create the time labels and the outline lines for (int x = lowerBound.TotalMinutes; x <= upperBound.TotalMinutes; x += 30) { TextBlock block = new TextBlock { FontSize = (x % 60 == 0) ? 12 : 10 }; //block.Text = string.Format("{0}:{1}", ((int)x / 60).ToString(), ((x % 60)).ToString()); // block.Text = (x / 60).ToString() + ":00"; double hours = x / 60.0; block.Text = Math.Truncate(hours).ToString() + ":" + ((hours - Math.Truncate(hours)) * 60).ToString(); timeLabels.Children.Add(block); Canvas.SetLeft(block, 0); Canvas.SetTop(block, Constants.EventControlHeight * ((x - lowerBound.TotalMinutes) / 60.0) - block.ActualHeight); Line indicator = new Line { Stroke = new SolidColorBrush(Colors.DarkGray), StrokeThickness = 1 }; root.Children.Add(indicator); indicator.X1 = 0; indicator.Y1 = Constants.EventControlHeight * ((x - lowerBound.TotalMinutes) / 60.0); indicator.X2 = Constants.EventControlWidth * ((studentDataBundle.hasWeekend()) ? 7 : 5) + timeLabels.ActualWidth; indicator.Y2 = indicator.Y1; Canvas.SetZIndex(indicator, -1); } } }
/// <summary> /// Export a timetable to a .tb file /// </summary> /// <param name="table"></param> /// <returns></returns> public static async Task <bool> ExportTimetable(StudentDataBundle table) { //file picker to let the use choose a file FileSavePicker saver = new FileSavePicker(); saver.DefaultFileExtension = ".tb"; saver.SuggestedFileName = table.Name; saver.SuggestedStartLocation = PickerLocationId.DocumentsLibrary; saver.FileTypeChoices.Add("StudentDataBundle file", new List <string> { ".tb" }); //.tb is the file extension StorageFile file = await saver.PickSaveFileAsync(); //le the use pick a file //if the use did not press Cancel , it should not be null , so write to it if (file != null) { Stream stream = await file.OpenStreamForWriteAsync(); await Task.Run(() => { Serializer.Serialize(stream, table); }); } return(true); }
public InstanceControl(Instance instance, StudentDataBundle studentDataBundle) { this.InitializeComponent(); this.Loaded += InstanceControl_Loaded; self = instance; selfParent = studentDataBundle; }
/// <summary> /// Fills the list with all the timetables /// </summary> /// <returns></returns> public static async Task <bool> GetTimetables() { Timetables.Clear(); //empty it just in case it has data var success = true; //assume it works var names = await DataFolder.GetFilesAsync(); //list of all files in data folder foreach (var name in names) { Stream st = await name.OpenStreamForReadAsync(); //open a read-only data stream //asynchrnously deserialize each file await Task.Run(() => { try { StudentDataBundle table = Serializer.Deserialize(st) as StudentDataBundle; Timetables.Add(table); } catch { success = false; } }); st.Dispose(); } return(success); }
public TimetableBox(StudentDataBundle table) { this.InitializeComponent(); _name.Text = table.Name; _description.Text = table.Description; _nameLabel.Text = table.Name; self = table; preview.FillWith(self); }
public void FillWith(ref StudentDataBundle tb) { root.Children.Clear(); currentTarget = tb; for (int x = 0; x < tb.Courses.Count; x++) { Course temp = tb.Courses[x]; addEvent(temp); } }
public void FillWith(StudentDataBundle table) { nextPanel.Visibility = Windows.UI.Xaml.Visibility.Visible; description.Text = table.Description; Course earliest = new Course { Name = "null" }; Instance earliestInstance = new Instance { StartTime = Time.MaximumTime, EndTime = Time.MaximumTime }; foreach (Course model in table.Courses) { EventControl control = new EventControl(model); control.Margin = new Thickness(5, 0, 5, 0); eventHolder.Children.Add(control); foreach (Instance instance in model.Instances) { if (instance.Day == (int)DateTime.Now.DayOfWeek - 1) { Time now = new Time { Hours = DateTime.Now.Hour, Minutes = DateTime.Now.Minute }; if (now < instance.StartTime) { if (earliestInstance.StartTime < now) { earliestInstance = instance; earliest = model; } else { if (instance.StartTime - now < earliestInstance.StartTime - now) { earliestInstance = instance; earliest = model; } } } } } } if (earliest.Name != "null") { eventControl.FillWith(earliest); eventControl.setTime(earliestInstance.StartTime, earliestInstance.EndTime); } else { nextPanel.Visibility = Windows.UI.Xaml.Visibility.Collapsed; } }
protected override void OnNavigatedTo(NavigationEventArgs e) { //a StudentDataBundle must be passed in order to reach this page if (e.Parameter.GetType() == typeof(StudentDataBundle)) { //self will contain a reference to the current StudentDataBundle self = e.Parameter as StudentDataBundle; //fill the StudentDataBundle preview with the StudentDataBundle table.FillWith(self); } else { } }
/// <summary> /// Check for the earliest time for space setting the StudentDataBundle view. /// </summary> /// <param name="tb"></param> /// <returns>Earliest Time</returns> public static Time GetEarliest(StudentDataBundle tb) { Time earliest = Time.MaximumTime; foreach (Course t in tb.Courses) { foreach (Instance instance in t.Instances) { if (instance.StartTime <= earliest) { earliest = instance.StartTime; } } } return(earliest); }
/// <summary> /// Check for the latest time for space setting the StudentDataBundle view. /// </summary> /// <param name="tb"></param> /// <returns>Latest time</returns> public static Time GetLatest(StudentDataBundle tb) { Time latest = Time.MinimumTime; foreach (Course t in tb.Courses) { foreach (Instance instance in t.Instances) { if (instance.EndTime >= latest) { latest = instance.EndTime; } } } return(latest); }
/// <summary> /// This will delete a timetable /// </summary> /// <param name="table"></param> /// <returns></returns> public static async Task <bool> DeleteTimetable(StudentDataBundle table) { //bool success = true; try { //finds the file with that name and deletes. Then removes the object from the list. StorageFile file = await DataFolder.GetFileAsync(table.Name + ".tb"); await file.DeleteAsync(); Timetables.Remove(table); } catch { return(false); } return(true); }
/// <summary> /// Imports a .tb file /// </summary> /// <returns></returns> public static async Task <bool> ImportTimetable() { try { //let the user pick file FileOpenPicker opener = new FileOpenPicker(); opener.FileTypeFilter.Add(".tb"); opener.CommitButtonText = "Open StudentDataBundle"; opener.SuggestedStartLocation = PickerLocationId.DocumentsLibrary; StorageFile file = await opener.PickSingleFileAsync(); Stream str = await file.OpenStreamForReadAsync(); bool doRename = false; //if the user changed the filename it could break the app so it must be renamed await Task.Run(() => { StudentDataBundle table = Serializer.Deserialize(str) as StudentDataBundle; if (file.Name != table.Name) { doRename = true; } Timetables.Add(table); str.Dispose(); }); //copy it to the data folder file = await file.CopyAsync(DataFolder, Timetables.Last().Name + ".tb", NameCollisionOption.FailIfExists); //rename appropiately if (doRename) { await file.RenameAsync(Timetables.Last().Name + ".tb", NameCollisionOption.ReplaceExisting); } return(true); } catch (Exception x) { return(false); } }
/// <summary> /// This method checks whether a proposed instace is overlapping another /// </summary> /// <param name="instance">The instance we are checking the overlap with</param> /// <param name="table">The StudentDataBundle in which we check for overlaps</param> /// <returns></returns> public static TimeOverlapData isOverlapping(Instance instance, StudentDataBundle table) { foreach (Course model in table.Courses) { foreach (Instance current in model.Instances) { if (instance.Day == current.Day) { if (instance != current && !model.Instances.Contains(instance) && !(current.EndTime == instance.EndTime || current.StartTime == instance.StartTime)) { if (instance.StartTime == current.StartTime) { return new TimeOverlapData { isOverlapping = true, OverlappingEventName = model.Name } } ; if (instance.StartTime < current.StartTime) { if (instance.EndTime > current.StartTime) { return(new TimeOverlapData { isOverlapping = true, OverlappingEventName = model.Name }); } } if (instance.StartTime >= current.StartTime && instance.EndTime <= current.EndTime) { return(new TimeOverlapData { isOverlapping = true, OverlappingEventName = model.Name }); } } } } } return(new TimeOverlapData { isOverlapping = false }); }
/// <summary> /// Save a timetable over the old version /// </summary> /// <param name="table">The timetable to save</param> /// <returns></returns> public static async Task <bool> SaveTimetable(StudentDataBundle table) { try { //find timetable file , open for writing and serialize it StorageFile file = await DataFolder.CreateFileAsync(table.Name + ".tb", CreationCollisionOption.ReplaceExisting); Stream dataStream = await file.OpenStreamForWriteAsync(); await Task.Run(() => { Serializer.Serialize(dataStream, table); }); dataStream.Dispose();//to avoid two streams exceptions return(true); } catch { return(false); } }
protected override void OnNavigatedTo(NavigationEventArgs e) { self = e.Parameter as StudentDataBundle;//keep a reference to the timetable refresh(); //go back to previous page back.Tapped += async(a, b) => { await CoreData.SaveTimetable(self); Frame.Navigate(typeof(MainPage), self); }; //create new course add.Tapped += (a, b) => { self.Courses.Add(new Course { Name = "New Class" }); refresh(); }; }
private async void create_clicked(object sender, Windows.UI.Xaml.RoutedEventArgs e) { ValidatorResponse TitleErrors = Validator.isStringValid( target: _name.Text, scope: "title", allowDigits: true, allowEmpty: false, max: Validator.TimetableTitleMax, fileName: true); ValidatorResponse DescriptionErrors = Validator.isStringValid( target: _description.Text, scope: "description", allowDigits: true, allowEmpty: true, max: Validator.TimetableDescriptionMax); if (!TitleErrors.isValid || !DescriptionErrors.isValid) { string errorMessage = TitleErrors.Errors.Aggregate("Cannot create timetable because of the following errors:\n", (current, s) => current + (s + "\n")); errorMessage = DescriptionErrors.Errors.Aggregate(errorMessage, (current, s) => current + (s + "\n")); var dialog = new MessageDialog(content: errorMessage , title: "An error occured"); await dialog.ShowAsync(); } else { var tb = new StudentDataBundle { Name = _name.Text, Description = _description.Text }; if (await CoreData.CreateTimetable(tb)) { // CoreData.Timetables.Add(tb); OnCreate(); toFront.Begin(); _name.Text = ""; _description.Text = ""; } else { var diag = new MessageDialog("There was an error creating it"); await diag.ShowAsync(); } } }
/// <summary> /// handle file double clicking to import /// </summary> /// <param name="args"></param> protected async override void OnFileActivated(FileActivatedEventArgs args) { bool error = false; try { StudentDataBundle fileTable = new StudentDataBundle(); StorageFile file = args.Files[0] as Windows.Storage.StorageFile; Stream stream = await file.OpenStreamForReadAsync(); await Task.Run(() => { fileTable = CoreData.Serializer.Deserialize(stream) as StudentDataBundle; CoreData.Timetables.Add(fileTable); }); await CoreData.SaveTimetable(fileTable); var rootFrame = new Frame(); rootFrame.Navigate(typeof(MainPage), fileTable); Window.Current.Content = rootFrame; MainPage p = rootFrame.Content as MainPage; Window.Current.Activate(); } catch { error = true; } if (error) { //cannot await in catch clause , so a variable is needed Windows.UI.Popups.MessageDialog dialog = new Windows.UI.Popups.MessageDialog("Something is wrong with this file - or there already is a file with the same name", "We have a problem"); await dialog.ShowAsync(); } }
/// <summary> /// Edit name or description of timetable /// </summary> /// <param name="table">The edit target</param> /// <param name="rename">Whether it should be renamed</param> /// <param name="newName">The new name (if rename = true)</param> /// <returns></returns> public static async Task <bool> EditTimetable(StudentDataBundle table, bool rename = false, string newName = "") { try { //get the file and overwrite with new data var file = await DataFolder.GetFileAsync(table.Name + ".tb"); table.Name = newName; Stream dataStream = await file.OpenStreamForWriteAsync(); await Task.Run(() => Serializer.Serialize(dataStream, table)); //if it should rename , rename it asynchrnously if (rename) { await file.RenameAsync(newName + ".tb"); } return(true); } catch { return(false);//error } }
StudentDataBundle selfTB; //reference to parent StudentDataBundle for deletion public ClassBox( Course model, UIElementCollection parent, StudentDataBundle tb) { this.InitializeComponent(); self = model; selfTB = tb; //setting initial values name.Text = model.Name; teacher.Text = model.Teacher; room.Text = model.Class; notes.Text = model.Notes; color.SelectedColor = model.TileColor; border.BorderBrush = new SolidColorBrush(model.TileColor); //lambdas to handle changes color.ColorChanged += (col) => { model.TileColor = col; border.BorderBrush = new SolidColorBrush(model.TileColor); deleteBtn.Foreground = new SolidColorBrush(model.TileColor); }; //when text changes , perform a validation check/fix name.TextChanged += (a, b) => { Validator.isStringValid( target: name.Text, scope: "name", allowDigits: true, allowEmpty: false, max: Validator.EventTitleMax, autoFix: true, fixTarget: name, autoNotify: true); model.Name = name.Text; }; notes.TextChanged += (a, b) => { Validator.isStringValid( target: notes.Text, scope: "note", allowDigits: true, allowEmpty: true, max: Validator.EventNotesMax, autoFix: true, fixTarget: notes, autoNotify: true); model.Notes = notes.Text; }; room.TextChanged += (a, b) => { Validator.isStringValid( target: room.Text, scope: "room name", allowDigits: true, allowEmpty: false, max: Validator.EventClassMax, autoFix: true, fixTarget: room, autoNotify: true); model.Class = room.Text; }; teacher.TextChanged += (a, b) => { Validator.isStringValid( target: teacher.Text, scope: "teacher name", allowDigits: false, allowEmpty: false, max: Validator.EventTeacherMax, autoFix: true, fixTarget: teacher, autoNotify: true); model.Teacher = teacher.Text; }; //lambdas to handle tap events (delete/add) deleteBtn.Tapped += async(a, b) => { MessageDialog diag = new MessageDialog("This action cannot be undone", "Are you sure you want to delete " + model.Name); diag.Commands.Add(new UICommand("Delete", (d) => { parent.Remove(this); tb.Courses.Remove(model); })); diag.Commands.Add(new UICommand("Cancel")); await diag.ShowAsync(); }; add.Tapped += (a, b) => { Instance inst = new Instance { Day = 0, StartTime = new Time { Hours = 9, Minutes = 0 }, EndTime = new Time { Hours = 10, Minutes = 0 }, EventName = self.Name }; self.Instances.Add(inst); refresh(); }; refresh(); }
public void FillWith(ref StudentDataBundle studentDataBundle) { list.FillWith(ref studentDataBundle); self = studentDataBundle; }