use std::fmt::Display;
use std::str::FromStr;
use crate::errors::{FormError, ErrorKind};
use crate::files::common::Properties;
use crate::language::controls::{
Activation, Align, Appearance, DragMode, MousePointer, OLEDropMode, TextDirection, Visibility,
};
use crate::language::Color;
use image::DynamicImage;
use num_enum::TryFromPrimitive;
use serde::Serialize;
#[derive(Debug, PartialEq, Clone)]
pub struct DataProperties {
pub align: Align,
pub appearance: Appearance,
pub back_color: Color,
pub bof_action: BOFAction,
pub caption: String,
pub connection: ConnectionType,
pub database_name: String,
pub default_cursor_type: DefaultCursorType,
pub default_type: DatabaseDriverType,
pub drag_icon: Option<DynamicImage>,
pub drag_mode: DragMode,
pub enabled: Activation,
pub eof_action: EOFAction,
pub exclusive: bool,
pub fore_color: Color,
pub height: i32,
pub left: i32,
pub mouse_icon: Option<DynamicImage>,
pub mouse_pointer: MousePointer,
pub negotiate: bool,
pub ole_drop_mode: OLEDropMode,
pub options: i32,
pub read_only: bool,
pub record_set_type: RecordSetType,
pub record_source: String,
pub right_to_left: TextDirection,
pub tool_tip_text: String,
pub top: i32,
pub visible: Visibility,
pub whats_this_help_id: i32,
pub width: i32,
}
impl Default for DataProperties {
fn default() -> Self {
DataProperties {
align: Align::None,
appearance: Appearance::ThreeD,
back_color: Color::System { index: 5 },
bof_action: BOFAction::MoveFirst,
caption: String::new(),
connection: ConnectionType::Access,
database_name: String::new(),
default_cursor_type: DefaultCursorType::Default,
default_type: DatabaseDriverType::UseJet,
drag_icon: None,
drag_mode: DragMode::Manual,
enabled: Activation::Enabled,
eof_action: EOFAction::MoveLast,
exclusive: false,
fore_color: Color::System { index: 8 },
height: 1215,
left: 480,
mouse_icon: None,
mouse_pointer: MousePointer::Default,
negotiate: false,
ole_drop_mode: OLEDropMode::default(),
options: 0,
read_only: false,
record_set_type: RecordSetType::Dynaset,
record_source: String::new(),
right_to_left: TextDirection::LeftToRight,
tool_tip_text: String::new(),
top: 840,
visible: Visibility::Visible,
whats_this_help_id: 0,
width: 1140,
}
}
}
impl Serialize for DataProperties {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeStruct;
let mut s = serializer.serialize_struct("DataProperties", 30)?;
s.serialize_field("align", &self.align)?;
s.serialize_field("appearance", &self.appearance)?;
s.serialize_field("back_color", &self.back_color)?;
s.serialize_field("bof_action", &self.bof_action)?;
s.serialize_field("caption", &self.caption)?;
s.serialize_field("connection", &self.connection)?;
s.serialize_field("database_name", &self.database_name)?;
s.serialize_field("default_cursor_type", &self.default_cursor_type)?;
s.serialize_field("default_type", &self.default_type)?;
let option_text = self.drag_icon.as_ref().map(|_| "Some(DynamicImage)");
s.serialize_field("drag_icon", &option_text)?;
s.serialize_field("drag_mode", &self.drag_mode)?;
s.serialize_field("enabled", &self.enabled)?;
s.serialize_field("eof_action", &self.eof_action)?;
s.serialize_field("exclusive", &self.exclusive)?;
s.serialize_field("fore_color", &self.fore_color)?;
s.serialize_field("height", &self.height)?;
s.serialize_field("left", &self.left)?;
let option_text = self.mouse_icon.as_ref().map(|_| "Some(DynamicImage)");
s.serialize_field("mouse_icon", &option_text)?;
s.serialize_field("mouse_pointer", &self.mouse_pointer)?;
s.serialize_field("negotiate", &self.negotiate)?;
s.serialize_field("ole_drop_mode", &self.ole_drop_mode)?;
s.serialize_field("options", &self.options)?;
s.serialize_field("read_only", &self.read_only)?;
s.serialize_field("record_set_type", &self.record_set_type)?;
s.serialize_field("record_source", &self.record_source)?;
s.serialize_field("right_to_left", &self.right_to_left)?;
s.serialize_field("tool_tip_text", &self.tool_tip_text)?;
s.serialize_field("top", &self.top)?;
s.serialize_field("visible", &self.visible)?;
s.serialize_field("whats_this_help_id", &self.whats_this_help_id)?;
s.serialize_field("width", &self.width)?;
s.end()
}
}
impl From<Properties> for DataProperties {
fn from(prop: Properties) -> Self {
let mut data_prop = DataProperties::default();
data_prop.align = prop.get_property("Align", data_prop.align);
data_prop.appearance = prop.get_property("Appearance", data_prop.appearance);
data_prop.back_color = prop.get_color("BackColor", data_prop.back_color);
data_prop.bof_action = prop.get_property("BOFAction", data_prop.bof_action);
data_prop.caption = match prop.get("Caption") {
Some(caption) => caption.clone(),
None => data_prop.caption,
};
data_prop.connection = prop
.get("Connection")
.map_or(Ok(ConnectionType::Access), |v| v.as_str().try_into())
.unwrap_or(ConnectionType::Access);
data_prop.database_name = match prop.get("DatabaseName") {
Some(database_name) => database_name.clone(),
None => String::new(),
};
data_prop.default_cursor_type =
prop.get_property("DefaultCursorType", data_prop.default_cursor_type);
data_prop.default_type = prop.get_property("DefaultType", data_prop.default_type);
data_prop.drag_mode = prop.get_property("DragMode", data_prop.drag_mode);
data_prop.enabled = prop.get_property("Enabled", data_prop.enabled);
data_prop.eof_action = prop.get_property("EOFAction", data_prop.eof_action);
data_prop.exclusive = prop.get_bool("Exclusive", data_prop.exclusive);
data_prop.fore_color = prop.get_color("ForeColor", data_prop.fore_color);
data_prop.height = prop.get_i32("Height", data_prop.height);
data_prop.left = prop.get_i32("Left", data_prop.left);
data_prop.mouse_pointer = prop.get_property("MousePointer", data_prop.mouse_pointer);
data_prop.negotiate = prop.get_bool("Negotiate", data_prop.negotiate);
data_prop.ole_drop_mode = prop.get_property("OLEDropMode", data_prop.ole_drop_mode);
data_prop.options = prop.get_i32("Options", data_prop.options);
data_prop.read_only = prop.get_bool("ReadOnly", data_prop.read_only);
data_prop.record_set_type = prop.get_property("RecordsetType", data_prop.record_set_type);
data_prop.record_source = match prop.get("RecordSource") {
Some(record_source) => record_source.into(),
None => String::new(),
};
data_prop.right_to_left = prop.get_property("RightToLeft", data_prop.right_to_left);
data_prop.tool_tip_text = match prop.get("ToolTipText") {
Some(tool_tip_text) => tool_tip_text.into(),
None => String::new(),
};
data_prop.top = prop.get_i32("Top", data_prop.top);
data_prop.visible = prop.get_property("Visible", data_prop.visible);
data_prop.whats_this_help_id =
prop.get_i32("WhatsThisHelpID", data_prop.whats_this_help_id);
data_prop.width = prop.get_i32("Width", data_prop.width);
data_prop
}
}
#[derive(
Debug, PartialEq, Eq, Clone, Serialize, Default, TryFromPrimitive, Copy, Hash, PartialOrd, Ord,
)]
#[repr(i32)]
pub enum BOFAction {
#[default]
MoveFirst = 0,
Bof = 1,
}
impl Display for BOFAction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let text = match self {
BOFAction::MoveFirst => "MoveFirst",
BOFAction::Bof => "BOF",
};
write!(f, "{text}")
}
}
impl FromStr for BOFAction {
type Err = ErrorKind;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"0" => Ok(BOFAction::MoveFirst),
"1" => Ok(BOFAction::Bof),
_ => Err(ErrorKind::Form(FormError::InvalidBOFAction {
value: s.to_string(),
})),
}
}
}
impl TryFrom<&str> for BOFAction {
type Error = ErrorKind;
fn try_from(value: &str) -> Result<Self, Self::Error> {
BOFAction::from_str(value)
}
}
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Default, Copy, Hash, PartialOrd, Ord)]
pub enum ConnectionType {
#[default]
Access,
DBaseIII,
DBaseIV,
DBase5_0,
Excel3_0,
Excel4_0,
Excel5_0,
Excel8_0,
FoxPro2_0,
FoxPro2_5,
FoxPro2_6,
FoxPro3_0,
LotusWk1,
LotusWk3,
LotusWk4,
Paradox3X,
Paradox4X,
Paradox5X,
Text,
}
impl Display for ConnectionType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let text = match self {
ConnectionType::Access => "Access",
ConnectionType::DBaseIII => "dBase III",
ConnectionType::DBaseIV => "dBase IV",
ConnectionType::DBase5_0 => "dBase 5.0",
ConnectionType::Excel3_0 => "Excel 3.0",
ConnectionType::Excel4_0 => "Excel 4.0",
ConnectionType::Excel5_0 => "Excel 5.0",
ConnectionType::Excel8_0 => "Excel 8.0",
ConnectionType::FoxPro2_0 => "FoxPro 2.0",
ConnectionType::FoxPro2_5 => "FoxPro 2.5",
ConnectionType::FoxPro2_6 => "FoxPro 2.6",
ConnectionType::FoxPro3_0 => "FoxPro 3.0",
ConnectionType::LotusWk1 => "Lotus WK1",
ConnectionType::LotusWk3 => "Lotus WK3",
ConnectionType::LotusWk4 => "Lotus WK4",
ConnectionType::Paradox3X => "Paradox 3.X",
ConnectionType::Paradox4X => "Paradox 4.X",
ConnectionType::Paradox5X => "Paradox 5.X",
ConnectionType::Text => "Text",
};
write!(f, "{text}")
}
}
impl FromStr for ConnectionType {
type Err = ErrorKind;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"Access" => Ok(ConnectionType::Access),
"dBase III" => Ok(ConnectionType::DBaseIII),
"dBase IV" => Ok(ConnectionType::DBaseIV),
"dBase 5.0" => Ok(ConnectionType::DBase5_0),
"Excel 3.0" => Ok(ConnectionType::Excel3_0),
"Excel 4.0" => Ok(ConnectionType::Excel4_0),
"Excel 5.0" => Ok(ConnectionType::Excel5_0),
"Excel 8.0" => Ok(ConnectionType::Excel8_0),
"FoxPro 2.0" => Ok(ConnectionType::FoxPro2_0),
"FoxPro 2.5" => Ok(ConnectionType::FoxPro2_5),
"FoxPro 2.6" => Ok(ConnectionType::FoxPro2_6),
"FoxPro 3.0" => Ok(ConnectionType::FoxPro3_0),
"Lotus WK1" => Ok(ConnectionType::LotusWk1),
"Lotus WK3" => Ok(ConnectionType::LotusWk3),
"Lotus WK4" => Ok(ConnectionType::LotusWk4),
"Paradox 3.X" => Ok(ConnectionType::Paradox3X),
"Paradox 4.X" => Ok(ConnectionType::Paradox4X),
"Paradox 5.X" => Ok(ConnectionType::Paradox5X),
"Text" => Ok(ConnectionType::Text),
_ => Err(ErrorKind::Form(FormError::InvalidConnectionType {
value: s.to_string(),
})),
}
}
}
impl TryFrom<&str> for ConnectionType {
type Error = ErrorKind;
fn try_from(value: &str) -> Result<Self, Self::Error> {
ConnectionType::from_str(value)
}
}
#[derive(
Debug, PartialEq, Eq, Clone, Serialize, Default, TryFromPrimitive, Copy, Hash, PartialOrd, Ord,
)]
#[repr(i32)]
pub enum DefaultCursorType {
#[default]
Default = 0,
Odbc = 1,
ServerSide = 2,
}
impl Display for DefaultCursorType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let text = match self {
DefaultCursorType::Default => "Default",
DefaultCursorType::Odbc => "Odbc",
DefaultCursorType::ServerSide => "ServerSide",
};
write!(f, "{text}")
}
}
impl FromStr for DefaultCursorType {
type Err = ErrorKind;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"0" => Ok(DefaultCursorType::Default),
"1" => Ok(DefaultCursorType::Odbc),
"2" => Ok(DefaultCursorType::ServerSide),
_ => Err(ErrorKind::Form(FormError::InvalidDefaultCursorType {
value: s.to_string(),
})),
}
}
}
impl TryFrom<&str> for DefaultCursorType {
type Error = ErrorKind;
fn try_from(value: &str) -> Result<Self, Self::Error> {
DefaultCursorType::from_str(value)
}
}
#[derive(
Debug, PartialEq, Eq, Clone, Serialize, Default, TryFromPrimitive, Copy, Hash, PartialOrd, Ord,
)]
#[repr(i32)]
pub enum DatabaseDriverType {
UseODBC = 1,
#[default]
UseJet = 2,
}
impl Display for DatabaseDriverType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let text = match self {
DatabaseDriverType::UseODBC => "UseODBC",
DatabaseDriverType::UseJet => "UseJet",
};
write!(f, "{text}")
}
}
impl FromStr for DatabaseDriverType {
type Err = ErrorKind;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"1" => Ok(DatabaseDriverType::UseODBC),
"2" => Ok(DatabaseDriverType::UseJet),
_ => Err(ErrorKind::Form(FormError::InvalidDatabaseDriverType {
value: s.to_string(),
})),
}
}
}
impl TryFrom<&str> for DatabaseDriverType {
type Error = ErrorKind;
fn try_from(value: &str) -> Result<Self, Self::Error> {
DatabaseDriverType::from_str(value)
}
}
#[derive(
Debug, PartialEq, Eq, Clone, Serialize, Default, TryFromPrimitive, Copy, Hash, PartialOrd, Ord,
)]
#[repr(i32)]
pub enum EOFAction {
#[default]
MoveLast = 0,
Eof = 1,
AddNew = 2,
}
impl Display for EOFAction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let text = match self {
EOFAction::MoveLast => "MoveLast",
EOFAction::Eof => "EOF",
EOFAction::AddNew => "AddNew",
};
write!(f, "{text}")
}
}
impl FromStr for EOFAction {
type Err = ErrorKind;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"0" => Ok(EOFAction::MoveLast),
"1" => Ok(EOFAction::Eof),
"2" => Ok(EOFAction::AddNew),
_ => Err(ErrorKind::Form(FormError::InvalidEOFAction {
value: s.to_string(),
})),
}
}
}
impl TryFrom<&str> for EOFAction {
type Error = ErrorKind;
fn try_from(value: &str) -> Result<Self, Self::Error> {
EOFAction::from_str(value)
}
}
#[derive(
Debug, PartialEq, Eq, Clone, Serialize, Default, TryFromPrimitive, Copy, Hash, PartialOrd, Ord,
)]
#[repr(i32)]
pub enum RecordSetType {
Table = 0,
#[default]
Dynaset = 1,
Snapshot = 2,
}
impl Display for RecordSetType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let text = match self {
RecordSetType::Table => "Table",
RecordSetType::Dynaset => "Dynaset",
RecordSetType::Snapshot => "Snapshot",
};
write!(f, "{text}")
}
}
impl FromStr for RecordSetType {
type Err = ErrorKind;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"0" => Ok(RecordSetType::Table),
"1" => Ok(RecordSetType::Dynaset),
"2" => Ok(RecordSetType::Snapshot),
_ => Err(ErrorKind::Form(FormError::InvalidRecordSetType {
value: s.to_string(),
})),
}
}
}
impl TryFrom<&str> for RecordSetType {
type Error = ErrorKind;
fn try_from(value: &str) -> Result<Self, Self::Error> {
RecordSetType::from_str(value)
}
}