Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Windows
pEp for Outlook
Compare Revisions
11a334a6bfe2d78d7fbb29bcabc75d830f898c53...8eeab9eef08e1bec63145065b3696c620bf045c0
Commits (5)
Fix diff algorithm
· 6817211a
Thomas
authored
Sep 17, 2021
6817211a
Don't wrap text in the diff view
· 3545f8c3
Thomas
authored
Sep 20, 2021
3545f8c3
Return error status if invalid request is received.
· adec6d7b
Thomas
authored
Sep 20, 2021
adec6d7b
Remove obsolete code
· de2afc87
Thomas
authored
Sep 20, 2021
de2afc87
Save patch status if patch was supported or rejected
· 8eeab9ee
Thomas
authored
Sep 20, 2021
8eeab9ee
Show whitespace changes
Inline
Side-by-side
DPE/DPEWebServer.cs
View file @
8eeab9ee
...
@@ -28,14 +28,15 @@ namespace pEp.DPE
...
@@ -28,14 +28,15 @@ namespace pEp.DPE
if
(
context
.
Request
.
HttpMethod
!=
"POST"
)
if
(
context
.
Request
.
HttpMethod
!=
"POST"
)
{
{
Log
.
Warning
(
"Process request: Ignoring request of type "
+
context
.
Request
.
HttpMethod
);
Log
.
Warning
(
"Process request: Ignoring request of type "
+
context
.
Request
.
HttpMethod
);
return
;
}
}
string
request
=
null
;
string
request
=
null
;
try
try
{
{
using
(
var
stream
=
context
.
Request
.
InputStream
)
using
(
Stream
stream
=
context
.
Request
.
InputStream
)
using
(
va
r
sr
=
new
StreamReader
(
stream
))
using
(
StreamReade
r
sr
=
new
StreamReader
(
stream
))
{
{
request
=
sr
.
ReadToEnd
();
request
=
sr
.
ReadToEnd
();
}
}
...
@@ -43,6 +44,8 @@ namespace pEp.DPE
...
@@ -43,6 +44,8 @@ namespace pEp.DPE
catch
(
Exception
ex
)
catch
(
Exception
ex
)
{
{
Log
.
Error
(
"ProcessRequest: Error getting request. "
+
ex
.
ToString
());
Log
.
Error
(
"ProcessRequest: Error getting request. "
+
ex
.
ToString
());
context
.
Response
.
StatusCode
=
(
int
)
HttpStatusCode
.
BadRequest
;
context
.
Response
.
Close
();
return
;
return
;
}
}
...
...
DPE/DistributedPolicyEngine.cs
View file @
8eeab9ee
...
@@ -10,8 +10,8 @@ namespace pEp.DPE
...
@@ -10,8 +10,8 @@ namespace pEp.DPE
{
{
internal
class
DistributedPolicyEngine
:
IDistributedPolicyEngine
internal
class
DistributedPolicyEngine
:
IDistributedPolicyEngine
{
{
private
readonly
static
string
DPE_FOLDER
=
Path
.
Combine
(
Globals
.
PEPUserFolder
,
"DPE"
);
private
static
readonly
string
DPE_FOLDER
=
Path
.
Combine
(
Globals
.
PEPUserFolder
,
"DPE"
);
public
readonly
static
string
DPE_TEMP_LOCATION
=
Path
.
Combine
(
DistributedPolicyEngine
.
DPE_FOLDER
,
"temp"
);
public
static
readonly
string
DPE_TEMP_LOCATION
=
Path
.
Combine
(
DistributedPolicyEngine
.
DPE_FOLDER
,
"temp"
);
private
const
string
PATCH_EXTENSION
=
".patch"
;
private
const
string
PATCH_EXTENSION
=
".patch"
;
private
const
string
PATCH_MESSAGE_SUBJECT
=
"Configuration changes"
;
private
const
string
PATCH_MESSAGE_SUBJECT
=
"Configuration changes"
;
public
const
string
DPE_MESSAGE_CLASS
=
"IPM.Note.DPE"
;
public
const
string
DPE_MESSAGE_CLASS
=
"IPM.Note.DPE"
;
...
@@ -127,7 +127,6 @@ namespace pEp.DPE
...
@@ -127,7 +127,6 @@ namespace pEp.DPE
public
void
Reject
(
Patch
patch
,
PEPIdentity
me
)
public
void
Reject
(
Patch
patch
,
PEPIdentity
me
)
{
{
DPEWebClient
.
RejectPatch
(
patch
,
me
);
DPEWebClient
.
RejectPatch
(
patch
,
me
);
this
.
DeletePatch
(
patch
);
AdapterExtensions
.
ShowNotification
(
"Patch rejected"
,
patch
.
CommitMessage
);
AdapterExtensions
.
ShowNotification
(
"Patch rejected"
,
patch
.
CommitMessage
);
}
}
...
@@ -137,9 +136,9 @@ namespace pEp.DPE
...
@@ -137,9 +136,9 @@ namespace pEp.DPE
/// <param name="patchEvents">The patch events to subscribe to.</param>
/// <param name="patchEvents">The patch events to subscribe to.</param>
public
void
Subscribe
(
PatchEvents
patchEvents
)
public
void
Subscribe
(
PatchEvents
patchEvents
)
{
{
patchEvents
.
PatchAccepted
+=
PatchEvents_PatchAccepted
;
patchEvents
.
PatchAccepted
+=
this
.
PatchEvents_PatchAccepted
;
patchEvents
.
PatchRejected
+=
PatchEvents_PatchRejected
;
patchEvents
.
PatchRejected
+=
this
.
PatchEvents_PatchRejected
;
patchEvents
.
PatchSuggested
+=
PatchEvents_PatchSuggested
;
patchEvents
.
PatchSuggested
+=
this
.
PatchEvents_PatchSuggested
;
}
}
/// <summary>
/// <summary>
...
@@ -161,7 +160,6 @@ namespace pEp.DPE
...
@@ -161,7 +160,6 @@ namespace pEp.DPE
public
void
Support
(
Patch
patch
,
PEPIdentity
me
)
public
void
Support
(
Patch
patch
,
PEPIdentity
me
)
{
{
DPEWebClient
.
SupportPatch
(
patch
,
me
);
DPEWebClient
.
SupportPatch
(
patch
,
me
);
this
.
DeletePatch
(
patch
);
AdapterExtensions
.
ShowNotification
(
"Patch supported"
,
patch
.
CommitMessage
);
AdapterExtensions
.
ShowNotification
(
"Patch supported"
,
patch
.
CommitMessage
);
}
}
...
@@ -171,67 +169,9 @@ namespace pEp.DPE
...
@@ -171,67 +169,9 @@ namespace pEp.DPE
/// <param name="patchEvents">The patch events to unsubscribe from.</param>
/// <param name="patchEvents">The patch events to unsubscribe from.</param>
public
void
Unsubscribe
(
PatchEvents
patchEvents
)
public
void
Unsubscribe
(
PatchEvents
patchEvents
)
{
{
patchEvents
.
PatchAccepted
-=
PatchEvents_PatchAccepted
;
patchEvents
.
PatchAccepted
-=
this
.
PatchEvents_PatchAccepted
;
patchEvents
.
PatchRejected
-=
PatchEvents_PatchRejected
;
patchEvents
.
PatchRejected
-=
this
.
PatchEvents_PatchRejected
;
patchEvents
.
PatchSuggested
-=
PatchEvents_PatchSuggested
;
patchEvents
.
PatchSuggested
-=
this
.
PatchEvents_PatchSuggested
;
}
/// <summary>
/// Deletes the patch from the disk.
/// </summary>
/// <param name="patch">The patch to delete.</param>
/// <returns>True if the patch was deleted or not found, otherwise false.</returns>
private
bool
DeletePatch
(
Patch
patch
)
{
try
{
string
fileName
=
Path
.
Combine
(
DistributedPolicyEngine
.
DPE_FOLDER
,
patch
.
Id
+
DistributedPolicyEngine
.
PATCH_EXTENSION
);
if
(
File
.
Exists
(
fileName
))
{
File
.
Delete
(
fileName
);
}
return
true
;
}
catch
(
Exception
ex
)
{
Log
.
Error
(
"DeletePatch: Error occured. "
+
ex
.
ToString
());
}
return
false
;
}
#
endregion
#
region
Static
methods
/// <summary>
/// Gets the patches that are currently saved to disk.
/// </summary>
/// <returns>The list of open patches or an empty list if none was found.</returns>
internal
static
List
<
Tuple
<
Patch
,
bool
>>
GetOpenPatches
()
{
List
<
Tuple
<
Patch
,
bool
>>
patches
=
new
List
<
Tuple
<
Patch
,
bool
>>();
try
{
foreach
(
string
file
in
Directory
.
GetFiles
(
DistributedPolicyEngine
.
DPE_FOLDER
,
"*"
+
DistributedPolicyEngine
.
PATCH_EXTENSION
))
{
string
xml
=
File
.
ReadAllText
(
file
);
if
((
Patch
.
Deserialize
(
xml
)
is
Patch
patch
)
&&
(
patch
!=
null
))
{
patches
.
Add
(
new
Tuple
<
Patch
,
bool
>(
patch
,
false
));
}
}
}
catch
(
Exception
ex
)
{
Log
.
Error
(
"GetPatches: Error getting patches. "
+
ex
.
ToString
());
}
return
patches
;
}
}
#
endregion
#
endregion
...
...
Extensions/MailItemExtensions.cs
View file @
8eeab9ee
...
@@ -17,16 +17,18 @@ namespace pEp
...
@@ -17,16 +17,18 @@ namespace pEp
/// </summary>
/// </summary>
internal
static
class
MailItemExtensions
internal
static
class
MailItemExtensions
{
{
public
const
string
USER_PROPERTY_KEY_ORIG_ENTRY_ID
=
"origEntryID"
;
public
const
string
USER_PROPERTY_KEY_DPE_PATCH_STATUS
=
"patchStatus"
;
public
const
string
USER_PROPERTY_KEY_DPE_PATCH_EDIT_DATE
=
"patchEditDate"
;
public
const
string
USER_PROPERTY_KEY_INSPECTOR_CLOSED
=
"inspectorClosed"
;
public
const
string
USER_PROPERTY_KEY_INSPECTOR_CLOSED
=
"inspectorClosed"
;
public
const
string
USER_PROPERTY_KEY_IS_INCOMING
=
"isIncoming"
;
public
const
string
USER_PROPERTY_KEY_IS_INCOMING
=
"isIncoming"
;
public
const
string
USER_PROPERTY_KEY_IS_MIRROR
=
"isMirror"
;
public
const
string
USER_PROPERTY_KEY_IS_MIRROR
=
"isMirror"
;
public
const
string
USER_PROPERTY_KEY_ORIG_ENTRY_ID
=
"origEntryID"
;
public
const
string
USER_PROPERTY_KEY_PROCESSING_STATE
=
"processingState"
;
public
const
string
USER_PROPERTY_KEY_PROCESSING_STATE
=
"processingState"
;
public
const
string
USER_PROPERTY_KEY_REPLY_ACTION
=
"replyAction"
;
public
const
string
USER_PROPERTY_KEY_REPLY_ACTION
=
"replyAction"
;
public
const
string
UNKNOWN_SENDER
=
"unknown"
;
public
const
string
UNKNOWN_SENDER
=
"unknown"
;
private
static
readonly
object
mutexCopiedItemsList
=
new
object
();
private
static
readonly
object
mutexCopiedItemsList
=
new
object
();
private
static
List
<
string
>
copiedItemsList
=
new
List
<
string
>();
private
static
readonly
List
<
string
>
copiedItemsList
=
new
List
<
string
>();
/// <summary>
/// <summary>
/// Enumeration defining the standard, setable pEp properties of an extended MailItem.
/// Enumeration defining the standard, setable pEp properties of an extended MailItem.
...
@@ -1190,7 +1192,6 @@ namespace pEp
...
@@ -1190,7 +1192,6 @@ namespace pEp
/// <returns>True if it is an attached mail, otherwise false.</returns>
/// <returns>True if it is an attached mail, otherwise false.</returns>
public
static
bool
GetIsAttachedMail
(
this
Outlook
.
MailItem
omi
,
out
string
messageId
)
public
static
bool
GetIsAttachedMail
(
this
Outlook
.
MailItem
omi
,
out
string
messageId
)
{
{
messageId
=
null
;
HeaderList
headers
=
omi
.
GetParsedTransportMessageHeaders
();
HeaderList
headers
=
omi
.
GetParsedTransportMessageHeaders
();
try
try
...
...
PEPMessage.cs
View file @
8eeab9ee
...
@@ -1614,7 +1614,6 @@ namespace pEp
...
@@ -1614,7 +1614,6 @@ namespace pEp
// TODO: Check whether this method should be part of the engine?
// TODO: Check whether this method should be part of the engine?
int
unencryptedCount
=
0
;
int
unencryptedCount
=
0
;
pEpRating
rating
=
pEpRating
.
pEpRatingUndefined
;
pEpRating
rating
=
pEpRating
.
pEpRatingUndefined
;
List
<
PEPIdentity
>
forceUnencryptedList
=
new
List
<
PEPIdentity
>();
PEPIdentity
[]
recipients
;
PEPIdentity
[]
recipients
;
PEPMessage
workingMessage
;
PEPMessage
workingMessage
;
...
...
UI/FormRegionDPE.cs
View file @
8eeab9ee
using
pEp.DPE
;
using
pEp.DPE
;
using
pEp.UI.Models
;
using
pEp.UI.ViewModels
;
using
pEp.UI.ViewModels
;
using
System
;
using
System
;
using
System.ComponentModel
;
using
Outlook
=
Microsoft
.
Office
.
Interop
.
Outlook
;
using
Outlook
=
Microsoft
.
Office
.
Interop
.
Outlook
;
namespace
pEp
namespace
pEp
{
{
partial
class
FormRegionDPE
internal
partial
class
FormRegionDPE
{
{
#
region
Form
Region
Factory
#
region
Form
Region
Factory
...
@@ -33,10 +33,41 @@ namespace pEp
...
@@ -33,10 +33,41 @@ namespace pEp
try
try
{
{
omi
=
this
.
OutlookItem
as
Outlook
.
MailItem
;
omi
=
this
.
OutlookItem
as
Outlook
.
MailItem
;
string
xml
=
omi
.
HTMLBody
;
string
xml
=
omi
.
HTMLBody
;
Patch
patch
=
Patch
.
Deserialize
(
xml
);
Patch
patch
=
Patch
.
Deserialize
(
xml
);
PEPIdentity
.
GetFromIdentity
(
omi
,
out
PEPIdentity
submitter
);
FormControlPatchViewModel
.
PatchStatus
patchStatus
=
FormControlPatchViewModel
.
PatchStatus
.
Open
;
this
.
FormControlPatchView
.
DataContext
=
new
FormControlPatchViewModel
(
patch
,
submitter
);
DateTime
?
editDate
=
null
;
// Get patch status if available
if
((
omi
.
GetUserProperty
(
MailItemExtensions
.
USER_PROPERTY_KEY_DPE_PATCH_STATUS
,
FormControlPatchViewModel
.
PatchStatus
.
Open
)
is
string
patchStatusString
)
&&
Enum
.
TryParse
(
patchStatusString
,
out
FormControlPatchViewModel
.
PatchStatus
status
))
{
patchStatus
=
status
;
}
// Get last edit date if available
if
((
omi
.
GetUserProperty
(
MailItemExtensions
.
USER_PROPERTY_KEY_DPE_PATCH_EDIT_DATE
)
is
string
editDateString
)
&&
DateTime
.
TryParse
(
editDateString
,
out
DateTime
savedEditDate
))
{
editDate
=
savedEditDate
;
}
// Get the patch submitter
if
(
PEPIdentity
.
GetFromIdentity
(
omi
,
out
PEPIdentity
submitter
)
==
Globals
.
ReturnStatus
.
Success
)
{
this
.
FormControlPatchView
.
DataContext
=
new
FormControlPatchViewModel
(
patch
,
submitter
,
patchStatus
,
editDate
);
// Subscribe to property changed event
if
(
this
.
FormControlPatchView
.
DataContext
is
FormControlPatchViewModel
formControlPatchViewModel
)
{
formControlPatchViewModel
.
PropertyChanged
+=
this
.
FormRegionDPE_PropertyChanged
;
}
}
else
{
throw
new
Exception
(
"FormRegionDPE_FormRegionShowing: Error getting patch submitter."
);
}
}
}
catch
(
Exception
ex
)
catch
(
Exception
ex
)
{
{
...
@@ -48,11 +79,55 @@ namespace pEp
...
@@ -48,11 +79,55 @@ namespace pEp
}
}
}
}
/// <summary>
/// Event handler for when a property in the associated view model changes.
/// </summary>
private
void
FormRegionDPE_PropertyChanged
(
object
sender
,
PropertyChangedEventArgs
e
)
{
// Set patch status and edit date as user properties if being changed
if
((
e
.
PropertyName
==
nameof
(
FormControlPatchViewModel
.
Status
))
||
(
e
.
PropertyName
==
nameof
(
FormControlPatchViewModel
.
EditDate
)))
{
Outlook
.
MailItem
omi
=
null
;
try
{
omi
=
this
.
OutlookItem
as
Outlook
.
MailItem
;
FormControlPatchViewModel
.
PatchStatus
patchStatus
=
(
sender
as
FormControlPatchViewModel
).
Status
;
DateTime
?
editDate
=
(
sender
as
FormControlPatchViewModel
).
EditDate
;
if
(
patchStatus
!=
FormControlPatchViewModel
.
PatchStatus
.
Open
)
{
omi
.
SetUserProperty
(
MailItemExtensions
.
USER_PROPERTY_KEY_DPE_PATCH_STATUS
,
Enum
.
GetName
(
typeof
(
FormControlPatchViewModel
.
PatchStatus
),
patchStatus
));
}
if
(
editDate
!=
null
)
{
omi
.
SetUserProperty
(
MailItemExtensions
.
USER_PROPERTY_KEY_DPE_PATCH_EDIT_DATE
,
editDate
?.
ToString
(
"f"
));
}
omi
.
Save
();
}
catch
(
Exception
ex
)
{
Log
.
Error
(
"FormRegionDPE_PropertyChanged: Error setting user property. "
+
ex
);
}
finally
{
omi
=
null
;
}
}
}
// Occurs when the form region is closed.
// Occurs when the form region is closed.
// Use this.OutlookItem to get a reference to the current Outlook item.
// Use this.OutlookItem to get a reference to the current Outlook item.
// Use this.OutlookFormRegion to get a reference to the form region.
// Use this.OutlookFormRegion to get a reference to the form region.
private
void
FormRegionDPE_FormRegionClosed
(
object
sender
,
EventArgs
e
)
private
void
FormRegionDPE_FormRegionClosed
(
object
sender
,
EventArgs
e
)
{
{
// Unsubscribe from property changed event
if
(
this
.
FormControlPatchView
.
DataContext
is
FormControlPatchViewModel
formControlPatchViewModel
)
{
formControlPatchViewModel
.
PropertyChanged
-=
this
.
FormRegionDPE_PropertyChanged
;
}
}
}
}
}
}
}
UI/ViewModels/FormControlPatchViewModel.cs
View file @
8eeab9ee
using
pEp.DPE
;
using
pEp.DPE
;
using
System
;
using
System.Windows.Documents
;
using
System.Windows.Documents
;
using
System.Windows.Media
;
namespace
pEp.UI.ViewModels
namespace
pEp.UI.ViewModels
{
{
internal
class
FormControlPatchViewModel
:
ViewModelBase
internal
class
FormControlPatchViewModel
:
ViewModelBase
{
{
public
enum
PatchStatus
{
Open
,
Accepted
,
Supported
,
Rejected
}
#
region
Fields
#
region
Fields
private
Patch
patch
;
private
readonly
Patch
patch
;
private
PatchStatus
_Status
=
PatchStatus
.
Open
;
private
DateTime
?
_EditDate
=
null
;
private
string
_Explanation
=
null
;
#
endregion
#
endregion
...
@@ -48,12 +60,17 @@ namespace pEp.UI.ViewModels
...
@@ -48,12 +60,17 @@ namespace pEp.UI.ViewModels
/// <summary>
/// <summary>
/// Gets the diff of this patch as formatted flow document.
/// Gets the diff of this patch as formatted flow document.
/// </summary>
/// </summary>
public
FlowDocument
DisplayDiff
{
get
;
}
public
FlowDocument
DisplayDiff
=>
PatchDialogViewModel
.
FormatDiff
(
this
.
Diff
);
/// <summary>
/// Gets or sets the last date the patch was edited.
/// </summary>
public
DateTime
?
EditDate
{
get
=>
this
.
_EditDate
;
set
=>
this
.
SetProperty
(
ref
this
.
_EditDate
,
value
);
}
/// <summary>
/// <summary>
/// The explanation shown in the UI regarding this patch.
/// The explanation shown in the UI regarding this patch.
/// </summary>
/// </summary>
public
string
Explanation
{
get
;
}
public
string
Explanation
{
get
=>
this
.
_Explanation
;
set
=>
this
.
SetProperty
(
ref
this
.
_Explanation
,
value
)
;
}
/// <summary>
/// <summary>
/// Gets whether the OK button is visible.
/// Gets whether the OK button is visible.
...
@@ -68,7 +85,7 @@ namespace pEp.UI.ViewModels
...
@@ -68,7 +85,7 @@ namespace pEp.UI.ViewModels
/// <summary>
/// <summary>
/// The command to accept the patch dialog.
/// The command to accept the patch dialog.
/// </summary>
/// </summary>
public
RelayCommand
OKButtonCommand
=>
new
RelayCommand
(
this
.
SupportPatch
);
public
RelayCommand
OKButtonCommand
=>
new
RelayCommand
(
this
.
SupportPatch
,
p
=>
(
this
.
Status
==
PatchStatus
.
Open
)
);
/// <summary>
/// <summary>
/// Gets the OK button text.
/// Gets the OK button text.
...
@@ -78,7 +95,7 @@ namespace pEp.UI.ViewModels
...
@@ -78,7 +95,7 @@ namespace pEp.UI.ViewModels
/// <summary>
/// <summary>
/// The command to reject the dialog.
/// The command to reject the dialog.
/// </summary>
/// </summary>
public
RelayCommand
RejectButtonCommand
=>
new
RelayCommand
(
this
.
RejectPatch
);
public
RelayCommand
RejectButtonCommand
=>
new
RelayCommand
(
this
.
RejectPatch
,
p
=>
(
this
.
Status
==
PatchStatus
.
Open
)
);
/// <summary>
/// <summary>
/// Gets the Reject button text.
/// Gets the Reject button text.
...
@@ -90,6 +107,11 @@ namespace pEp.UI.ViewModels
...
@@ -90,6 +107,11 @@ namespace pEp.UI.ViewModels
/// </summary>
/// </summary>
public
PEPIdentity
Submitter
{
get
;
}
public
PEPIdentity
Submitter
{
get
;
}
/// <summary>
/// Gets or sets the status of this patch.
/// </summary>
public
PatchStatus
Status
{
get
=>
this
.
_Status
;
set
=>
this
.
SetProperty
(
ref
this
.
_Status
,
value
);
}
/// <summary>
/// <summary>
/// Gets or sets the tag of the patch.
/// Gets or sets the tag of the patch.
/// </summary>
/// </summary>
...
@@ -125,14 +147,17 @@ namespace pEp.UI.ViewModels
...
@@ -125,14 +147,17 @@ namespace pEp.UI.ViewModels
/// </summary>
/// </summary>
/// <param name="patch">The patch to create the form region with.</param>
/// <param name="patch">The patch to create the form region with.</param>
/// <param name="submitter">The submitter of the patch.</param>
/// <param name="submitter">The submitter of the patch.</param>
public
FormControlPatchViewModel
(
Patch
patch
,
PEPIdentity
submitter
)
/// <param name="status">The status of the patch.</param>
/// <param name="editDate">The last time this patch was edited (accepted/supported/rejected).</param>
public
FormControlPatchViewModel
(
Patch
patch
,
PEPIdentity
submitter
,
PatchStatus
status
=
PatchStatus
.
Open
,
DateTime
?
editDate
=
null
)
{
{
this
.
EditDate
=
editDate
;
this
.
patch
=
patch
;
this
.
patch
=
patch
;
this
.
Submitter
=
submitter
;
this
.
Submitter
=
submitter
;
this
.
Explanation
=
"New configuration changes pending approval"
;
this
.
Status
=
status
;
this
.
IsRejectButtonVisible
=
true
;
this
.
IsRejectButtonVisible
=
true
;
this
.
OKButtonText
=
"Support"
;
this
.
OKButtonText
=
"Support"
;
this
.
DisplayDiff
=
this
.
FormatDiff
();
this
.
SetExplanation
();
}
}
#
endregion
#
endregion
...
@@ -140,58 +165,44 @@ namespace pEp.UI.ViewModels
...
@@ -140,58 +165,44 @@ namespace pEp.UI.ViewModels
#
region
Methods
#
region
Methods
/// <summary>
/// <summary>
///
Formats the diff displaying colors of changes
.
///
Rejects this patch
.
/// </summary>
/// </summary>
/// <returns>The formatted diff or null if no diff is available.</returns>
/// <param name="parameter">The command parameter.</param>
private
FlowDocument
FormatDiff
()
private
void
RejectPatch
(
object
parameter
)
{
if
(
string
.
IsNullOrEmpty
(
this
.
Diff
))
{
{
return
null
;
Globals
.
ThisAddIn
.
DistributedPolicyEngine
.
Reject
(
this
.
patch
,
new
PEPIdentity
());
this
.
Status
=
PatchStatus
.
Rejected
;
this
.
EditDate
=
DateTime
.
UtcNow
;
this
.
SetExplanation
();
}
}
FlowDocument
document
=
new
FlowDocument
/// <summary>
{
/// Sets the explanation text.
FontFamily
=
new
FontFamily
(
"Courier New"
),
/// </summary>
FontSize
=
12.0
,
private
void
SetExplanation
()
Background
=
Brushes
.
White
};
string
[]
lines
=
this
.
Diff
?.
Replace
(
"\r\n"
,
"\n"
)?.
Split
(
'\n'
)
??
new
string
[]
{
};
foreach
(
string
line
in
lines
)
{
Paragraph
paragraph
=
new
Paragraph
(
new
Run
(
line
))
{
Margin
=
new
System
.
Windows
.
Thickness
(
1
),
LineHeight
=
14.0
};
if
(
line
.
StartsWith
(
"-"
))
{
paragraph
.
Background
=
Globals
.
ResourceDict
[
"BrushRedBackground"
]
as
Brush
;
}
else
if
(
line
.
StartsWith
(
"+"
))
{
{
paragraph
.
Background
=
Globals
.
ResourceDict
[
"BrushGreenBackground"
]
as
Brush
;
string
editDate
=
"<n/a>"
;
}
if
(
this
.
EditDate
!=
null
)
else
if
(
line
.
StartsWith
(
"@@"
))
{
{
paragraph
.
Background
=
Brushes
.
LightGray
;
editDate
=
((
DateTime
)
this
.
EditDate
).
ToLocalTime
().
ToString
(
"F"
)
;
}
}
document
.
Blocks
.
Add
(
paragraph
);
switch
(
this
.
Status
)
}
return
document
;
}
/// <summary>
/// Rejects this patch.
/// </summary>
/// <param name="parameter">The command parameter.</param>
private
void
RejectPatch
(
object
parameter
)
{
{
Globals
.
ThisAddIn
.
DistributedPolicyEngine
.
Reject
(
this
.
patch
,
new
PEPIdentity
());
case
PatchStatus
.
Accepted
:
this
.
Explanation
=
$"Accepted on
{
editDate
}
"
;
break
;
case
PatchStatus
.
Supported
:
this
.
Explanation
=
$"Supported on
{
editDate
}
"
;
break
;
case
PatchStatus
.
Rejected
:
this
.
Explanation
=
$"Rejected on
{
editDate
}
"
;
break
;
case
PatchStatus
.
Open
:
default
:
this
.
Explanation
=
"New configuration changes pending approval"
;
break
;
}
}
}
/// <summary>
/// <summary>
...
@@ -201,6 +212,9 @@ namespace pEp.UI.ViewModels
...
@@ -201,6 +212,9 @@ namespace pEp.UI.ViewModels
private
void
SupportPatch
(
object
parameter
)
private
void
SupportPatch
(
object
parameter
)
{
{
Globals
.
ThisAddIn
.
DistributedPolicyEngine
.
Support
(
this
.
patch
,
new
PEPIdentity
());
Globals
.
ThisAddIn
.
DistributedPolicyEngine
.
Support
(
this
.
patch
,
new
PEPIdentity
());
this
.
Status
=
PatchStatus
.
Supported
;
this
.
EditDate
=
DateTime
.
UtcNow
;
this
.
SetExplanation
();
}
}
#
endregion
#
endregion
...
...
UI/ViewModels/OptionsViewModel.cs
View file @
8eeab9ee
...
@@ -31,7 +31,7 @@ namespace pEp.UI.ViewModels
...
@@ -31,7 +31,7 @@ namespace pEp.UI.ViewModels
MessageGroups
=
5
MessageGroups
=
5
}
}
private
PEPSettings
pEpSettings
;
private
readonly
PEPSettings
pEpSettings
;
private
int
_AccountSettingsListSelectedIndex
=
-
1
;
private
int
_AccountSettingsListSelectedIndex
=
-
1
;
private
RelayCommand
_CommandButtonAddGroup
=
null
;
private
RelayCommand
_CommandButtonAddGroup
=
null
;
...
@@ -45,9 +45,6 @@ namespace pEp.UI.ViewModels
...
@@ -45,9 +45,6 @@ namespace pEp.UI.ViewModels
private
RelayCommand
_CommandButtonRefreshLogs
=
null
;
private
RelayCommand
_CommandButtonRefreshLogs
=
null
;
private
RelayCommand
_CommandButtonResetPEPStore
=
null
;
private
RelayCommand
_CommandButtonResetPEPStore
=
null
;
private
RelayCommand
_CommandButtonResetAllOwnKeys
=
null
;
private
RelayCommand
_CommandButtonResetAllOwnKeys
=
null
;
private
RelayCommand
<
IList
<
object
>>
_CommandOpenPatch
=
null
;
private
RelayCommand
<
IList
<
object
>>
_CommandRejectPatch
=
null
;
private
RelayCommand
<
IList
<
object
>>
_CommandSupportPatch
=
null
;
private
bool
_IsAdvancedEnabled
=
false
;
private
bool
_IsAdvancedEnabled
=
false
;
private
string
_LogEngine
=
null
;
private
string
_LogEngine
=
null
;
private
string
_LogOutlook
=
null
;
private
string
_LogOutlook
=
null
;
...
@@ -78,12 +75,6 @@ namespace pEp.UI.ViewModels
...
@@ -78,12 +75,6 @@ namespace pEp.UI.ViewModels
this
.
AccountSettingsList
.
Add
(
new
AccountViewModel
(
accountSettings
,
this
.
CalculateDependentProperties
));
this
.
AccountSettingsList
.
Add
(
new
AccountViewModel
(
accountSettings
,
this
.
CalculateDependentProperties
));
});
});
// Add patches
DistributedPolicyEngine
.
GetOpenPatches
()?.
ForEach
((
tuple
)
=>
{
this
.
Patches
.
Add
(
new
PatchViewModel
(
tuple
.
Item1
,
tuple
.
Item2
));
});
// Calculate dependent properties
// Calculate dependent properties
this
.
calcDepPropIsEnabled
=
true
;
this
.
calcDepPropIsEnabled
=
true
;
this
.
CalculateDependentProperties
();
this
.
CalculateDependentProperties
();
...
@@ -305,55 +296,6 @@ namespace pEp.UI.ViewModels
...
@@ -305,55 +296,6 @@ namespace pEp.UI.ViewModels
}
}
}
}
/// <summary>
/// Gets the command to open a patch.
/// </summary>
public
RelayCommand
<
IList
<
object
>>
CommandOpenPatch
{
get
{
if
(
this
.
_CommandOpenPatch
==
null
)
{
this
.
_CommandOpenPatch
=
new
RelayCommand
<
IList
<
object
>>(
p
=>
(
p
?.
First
()
as
PatchViewModel
)?.
OpenPatchDialog
(
PatchDialog
.
PatchAction
.
SupportOrRejectPatch
));
}
return
this
.
_CommandOpenPatch
;
}
}
/// <summary>
/// Gets the command to reject a patch.
/// </summary>
public
RelayCommand
<
IList
<
object
>>
CommandRejectPatch
{
get
{
if
(
this
.
_CommandRejectPatch
==
null
)
{
this
.
_CommandRejectPatch
=
new
RelayCommand
<
IList
<
object
>>(
p
=>
this
.
RejectPatch
(
p
?.
First
()
as
PatchViewModel
));
}
return
this
.
_CommandRejectPatch
;
}
}
/// <summary>
/// Gets the command to support a patch.
/// </summary>
public
RelayCommand
<
IList
<
object
>>
CommandSupportPatch
{
get
{
if
(
this
.
_CommandSupportPatch
==
null
)
{
this
.
_CommandSupportPatch
=
new
RelayCommand
<
IList
<
object
>>(
p
=>
this
.
SupportPatch
(
p
?.
First
()
as
PatchViewModel
));
}
return
this
.
_CommandSupportPatch
;
}
}
/// <summary>
/// <summary>
/// Gets the list of projects that are used in pEp for Outlook and that
/// Gets the list of projects that are used in pEp for Outlook and that
/// are being credited.
/// are being credited.
...
@@ -1113,37 +1055,6 @@ namespace pEp.UI.ViewModels
...
@@ -1113,37 +1055,6 @@ namespace pEp.UI.ViewModels
}
while
(
retry
);
}
while
(
retry
);
}
}
/// <summary>
/// Opens the Patch dialog.
/// </summary>
/// <param name="patchViewModel">The patch view model that </param>
/// <param name="patchAction">The patch action to execute.</param>
/// <returns>The dialog result.</returns>
public
System
.
Windows
.
Forms
.
DialogResult
OpenPatchDialog
(
PatchViewModel
patchViewModel
,
PatchDialog
.
PatchAction
patchAction
)
{
if
(
patchViewModel
==
null
)
{
Log
.
ErrorAndFailInDebugMode
(
"OpenPatchDialog: patch view model is null."
);
}
System
.
Windows
.
Forms
.
DialogResult
dialogResult
=
patchViewModel
?.
OpenPatchDialog
(
patchAction
)
??
System
.
Windows
.
Forms
.
DialogResult
.
Cancel
;
if
(
dialogResult
!=
System
.
Windows
.
Forms
.
DialogResult
.
Cancel
)
{
this
.
Patches
.
Clear
();
// Add patches
DistributedPolicyEngine
.
GetOpenPatches
()?.
ForEach
((
tuple
)
=>
{
this
.
Patches
.
Add
(
new
PatchViewModel
(
tuple
.
Item1
,
tuple
.
Item2
));
});
this
.
OnPropertyChanged
(
nameof
(
this
.
Patches
));
}
return
dialogResult
;
}
/// <summary>
/// <summary>
/// Resets the logs.
/// Resets the logs.
/// </summary>
/// </summary>
...
@@ -1179,43 +1090,6 @@ namespace pEp.UI.ViewModels
...
@@ -1179,43 +1090,6 @@ namespace pEp.UI.ViewModels
}
}
}
}
/// <summary>
/// Removes the given patch from the list of patches.
/// </summary>
/// <param name="patchViewModel">The patch view model to remove.</param>
private
void
RemovePatch
(
PatchViewModel
patchViewModel
)
{
if
(
patchViewModel
==
null
)
{
Log
.
ErrorAndFailInDebugMode
(
"RemovePatch: patch view model is null."
);
}
if
(!
this
.
Patches
.
Remove
(
patchViewModel
))
{
Log
.
Error
(
"RemovePatch: Could not remove patch."
);
}
}
/// <summary>
/// Rejects the patch.
/// </summary>
/// <param name="patchViewModel">The patch's view model.</param>
private
void
RejectPatch
(
PatchViewModel
patchViewModel
)
{
patchViewModel
?.
RejectPatch
();
this
.
RemovePatch
(
patchViewModel
);
}
/// <summary>
/// Supports the patch.
/// </summary>
/// <param name="patchViewModel">The patch's view model.</param>
private
void
SupportPatch
(
PatchViewModel
patchViewModel
)
{
patchViewModel
?.
SupportPatch
();
this
.
RemovePatch
(
patchViewModel
);
}
#
endregion
#
endregion
}
}
}
}
UI/ViewModels/PatchDialogViewModel.cs
View file @
8eeab9ee
...
@@ -10,6 +10,7 @@ using System.Diagnostics;
...
@@ -10,6 +10,7 @@ using System.Diagnostics;
using
System.IO
;
using
System.IO
;
using
System.Linq
;
using
System.Linq
;
using
System.Windows
;
using
System.Windows
;
using
System.Windows.Controls
;
using
System.Windows.Documents
;
using
System.Windows.Documents
;
using
System.Windows.Media
;
using
System.Windows.Media
;
...
@@ -372,40 +373,30 @@ namespace pEp.UI.ViewModels
...
@@ -372,40 +373,30 @@ namespace pEp.UI.ViewModels
List
<
DiffPiece
>
newLines
=
sideBySideDiffModel
.
NewText
.
Lines
;
List
<
DiffPiece
>
newLines
=
sideBySideDiffModel
.
NewText
.
Lines
;
List
<
DiffPiece
>
oldLines
=
sideBySideDiffModel
.
OldText
.
Lines
;
List
<
DiffPiece
>
oldLines
=
sideBySideDiffModel
.
OldText
.
Lines
;
List
<
string
>
block
=
new
List
<
string
>();
List
<
string
>
block
=
new
List
<
string
>();
int
unchangedCount
=
0
;
bool
newBlock
=
true
;
bool
newBlock
=
true
;
int
oldFileIndex
=
0
,
newFileIndex
=
0
;
int
oldFileIndex
=
0
,
newFileIndex
=
0
;
for
(
int
i
=
0
;
i
<
newLines
.
Count
;
i
++)
for
(
int
i
=
0
;
i
<
newLines
.
Count
;
i
++)
{
{
// Add lines as necessary
// Add lines as necessary
if
((
newLines
[
i
].
Type
==
ChangeType
.
Unchanged
)
&&
if
(
newLines
[
i
].
Type
==
ChangeType
.
Imaginary
)
(
block
.
Count
>
0
))
{
block
.
Add
(
" "
+
newLines
[
i
].
Text
);
unchangedCount
++;
}
else
if
(
newLines
[
i
].
Type
==
ChangeType
.
Imaginary
)
{
{
block
.
Add
(
"-"
+
oldLines
[
i
].
Text
);
block
.
Add
(
"-"
+
oldLines
[
i
].
Text
);
unchangedCount
=
0
;
}
}
else
if
(
newLines
[
i
].
Type
==
ChangeType
.
Inserted
)
else
if
(
newLines
[
i
].
Type
==
ChangeType
.
Inserted
)
{
{
block
.
Add
(
"+"
+
newLines
[
i
].
Text
);
block
.
Add
(
"+"
+
newLines
[
i
].
Text
);
unchangedCount
=
0
;
}
}
else
if
(
newLines
[
i
].
Type
==
ChangeType
.
Modified
)
else
if
(
newLines
[
i
].
Type
==
ChangeType
.
Modified
)
{
{
block
.
Add
(
"-"
+
oldLines
[
i
].
Text
);
block
.
Add
(
"-"
+
oldLines
[
i
].
Text
);
block
.
Add
(
"+"
+
newLines
[
i
].
Text
);
block
.
Add
(
"+"
+
newLines
[
i
].
Text
);
unchangedCount
=
0
;
}
}
// If a block is being constructed, add additional parts as necessary
// If a block is being constructed, add additional parts as necessary
if
(
block
.
Count
>
0
)
if
(
block
.
Count
>
0
)
{
{
//
If we have a new block
, add the three preceding unchanged lines
//
First
, add the three preceding unchanged lines
(if available)
if
(
newBlock
)
if
(
newBlock
)
{
{
newBlock
=
false
;
newBlock
=
false
;
...
@@ -425,14 +416,32 @@ namespace pEp.UI.ViewModels
...
@@ -425,14 +416,32 @@ namespace pEp.UI.ViewModels
newFileIndex
=
newLines
[
index
].
Position
??
1
;
newFileIndex
=
newLines
[
index
].
Position
??
1
;
oldFileIndex
=
oldLines
[
index
].
Position
??
1
;
oldFileIndex
=
oldLines
[
index
].
Position
??
1
;
}
}
else
if
((
unchangedCount
>
2
)
||
(
i
==
newLines
.
Count
-
1
))
// Then, add the three following lines (if available)
int
counter
=
0
;
while
((++
i
<
newLines
.
Count
)
&&
(
newLines
[
i
].
Type
==
ChangeType
.
Unchanged
))
{
if
(
counter
++
<
3
)
{
block
.
Add
(
" "
+
newLines
[
i
].
Text
);
}
else
{
break
;
}
}
// Close block
if
((
counter
>
3
)
||
(
i
>=
newLines
.
Count
))
{
{
// Once a block is complete, add descriptor at the beginning and add lines to diff
// Once a block is complete, add descriptor at the beginning and add lines to diff
int
oldFileLineCount
=
block
.
Count
(
s
=>
!
s
.
StartsWith
(
"+"
));
int
oldFileLineCount
=
block
.
Count
(
s
=>
!
s
.
StartsWith
(
"+"
));
int
newFileLineCount
=
block
.
Count
(
s
=>
!
s
.
StartsWith
(
"-"
));
int
newFileLineCount
=
block
.
Count
(
s
=>
!
s
.
StartsWith
(
"-"
));
diff
+=
$"@@ -
{
oldFileIndex
}
,
{
oldFileLineCount
}
+
{
newFileIndex
}
,
{
newFileLineCount
}
@@\n"
;
diff
+=
$"@@ -
{
oldFileIndex
}
,
{
oldFileLineCount
}
+
{
newFileIndex
}
,
{
newFileLineCount
}
@@\n"
;
foreach
(
var
line
in
block
)
foreach
(
string
line
in
block
)
{
{
diff
+=
line
+
'\n'
;
diff
+=
line
+
'\n'
;
}
}
...
@@ -440,6 +449,8 @@ namespace pEp.UI.ViewModels
...
@@ -440,6 +449,8 @@ namespace pEp.UI.ViewModels
block
=
new
List
<
string
>();
block
=
new
List
<
string
>();
newBlock
=
true
;
newBlock
=
true
;
}
}
i
--;
}
}
}
}
...
@@ -512,53 +523,6 @@ namespace pEp.UI.ViewModels
...
@@ -512,53 +523,6 @@ namespace pEp.UI.ViewModels
Log
.
Error
(
$"EditFileAndCreateDiff: Error reading file content from
{
fileName
}
:
{
ex
}
"
);
Log
.
Error
(
$"EditFileAndCreateDiff: Error reading file content from
{
fileName
}
:
{
ex
}
"
);
}
}
}
}
/// <summary>
/// Formats the diff displaying colors of changes.
/// </summary>
/// <returns>The formatted diff or null if no diff is available.</returns>
private
FlowDocument
FormatDiff
(
string
diff
)
{
if
(
string
.
IsNullOrEmpty
(
diff
))
{
return
null
;
}
FlowDocument
document
=
new
FlowDocument
{
FontFamily
=
new
FontFamily
(
"Courier New"
),
FontSize
=
12.0
,
Background
=
Brushes
.
White
,
};
string
[]
lines
=
diff
?.
Replace
(
"\r\n"
,
"\n"
)?.
Split
(
'\n'
)
??
new
string
[]
{
};
foreach
(
string
line
in
lines
)
{
Paragraph
paragraph
=
new
Paragraph
(
new
Run
(
line
))
{
Margin
=
new
System
.
Windows
.
Thickness
(
1
),
LineHeight
=
14.0
};
if
(
line
.
StartsWith
(
"-"
))
{
paragraph
.
Background
=
Globals
.
ResourceDict
[
"BrushRedBackground"
]
as
Brush
;
}
else
if
(
line
.
StartsWith
(
"+"
))
{
paragraph
.
Background
=
Globals
.
ResourceDict
[
"BrushGreenBackground"
]
as
Brush
;
}
else
if
(
line
.
StartsWith
(
"@@"
))
{
paragraph
.
Background
=
Brushes
.
LightGray
;
}
document
.
Blocks
.
Add
(
paragraph
);
}
return
document
;
}
/// <summary>
/// <summary>
/// Gets a common root URI from all selected files in the dialog.
/// Gets a common root URI from all selected files in the dialog.
/// </summary>
/// </summary>
...
@@ -620,7 +584,7 @@ namespace pEp.UI.ViewModels
...
@@ -620,7 +584,7 @@ namespace pEp.UI.ViewModels
/// </summary>
/// </summary>
private
void
UpdateVisibleDiff
()
private
void
UpdateVisibleDiff
()
{
{
this
.
VisibleDiff
=
this
.
FormatDiff
(
this
.
SelectedFile
?.
Diff
);
this
.
VisibleDiff
=
PatchDialogViewModel
.
FormatDiff
(
this
.
SelectedFile
?.
Diff
);
}
}
/// <summary>
/// <summary>
...
@@ -635,5 +599,73 @@ namespace pEp.UI.ViewModels
...
@@ -635,5 +599,73 @@ namespace pEp.UI.ViewModels
}
}
#
endregion
#
endregion
#
region
Static
methods
/// <summary>
/// Formats the diff displaying colors of changes.
/// </summary>
/// <returns>The formatted diff or null if no diff is available.</returns>
public
static
FlowDocument
FormatDiff
(
string
diff
)
{
if
(
string
.
IsNullOrEmpty
(
diff
))
{
return
null
;
}
// Initialize the document with zero width to set the real width later
FlowDocument
document
=
new
FlowDocument
{
Background
=
Brushes
.
White
,
PageWidth
=
0
};
string
[]
lines
=
diff
.
Replace
(
"\r\n"
,
"\n"
)?.
Split
(
'\n'
)
??
new
string
[]
{
};
foreach
(
string
line
in
lines
)
{
Paragraph
paragraph
=
new
Paragraph
()
{
Margin
=
new
Thickness
(
1
),
};
TextBlock
textBlock
=
new
TextBlock
()
{
Text
=
line
,
FontFamily
=
new
FontFamily
(
"Courier New"
),
LineHeight
=
14.0
,
FontSize
=
12.0
,
TextWrapping
=
TextWrapping
.
NoWrap
};
// Set the document width to the biggest textblock width plus some margin
// to account for padding inside the scroll viewer
textBlock
.
Measure
(
new
Size
(
double
.
PositiveInfinity
,
double
.
PositiveInfinity
));
if
(
textBlock
.
DesiredSize
.
Width
>
document
.
PageWidth
)
{
document
.
PageWidth
=
textBlock
.
DesiredSize
.
Width
+
50
;
}
paragraph
.
Inlines
.
Add
(
textBlock
);
// Color the added and removed lines accordingly
if
(
line
.
StartsWith
(
"-"
))
{
paragraph
.
Background
=
Globals
.
ResourceDict
[
"BrushRedBackground"
]
as
Brush
;
}
else
if
(
line
.
StartsWith
(
"+"
))
{
paragraph
.
Background
=
Globals
.
ResourceDict
[
"BrushGreenBackground"
]
as
Brush
;
}
else
if
(
line
.
StartsWith
(
"@@"
))
{
paragraph
.
Background
=
Brushes
.
LightGray
;
}
document
.
Blocks
.
Add
(
paragraph
);
}
return
document
;
}
#
endregion
}
}
}
}
UI/Views/FormControlPatchView.xaml
View file @
8eeab9ee
...
@@ -72,6 +72,7 @@
...
@@ -72,6 +72,7 @@
<FlowDocumentScrollViewer Grid.Column="1"
<FlowDocumentScrollViewer Grid.Column="1"
Grid.ColumnSpan="2"
Grid.ColumnSpan="2"
Grid.Row="3"
Grid.Row="3"
HorizontalScrollBarVisibility="Auto"
BorderBrush="Black"
BorderBrush="Black"
BorderThickness="1"
BorderThickness="1"
Margin="5,10,10,10"
Margin="5,10,10,10"
...
...
UI/Views/FormControlPatchView.xaml.cs
View file @
8eeab9ee
using
System
;
using
System.Windows.Controls
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
using
System.Threading.Tasks
;
using
System.Windows
;
using
System.Windows.Controls
;
using
System.Windows.Data
;
using
System.Windows.Documents
;
using
System.Windows.Input
;
using
System.Windows.Media
;
using
System.Windows.Media.Imaging
;
using
System.Windows.Navigation
;
using
System.Windows.Shapes
;
namespace
pEp.UI.Views
namespace
pEp.UI.Views
{
{
...
...
UI/Views/OptionsView.xaml
View file @
8eeab9ee
...
@@ -976,52 +976,7 @@
...
@@ -976,52 +976,7 @@
FontSize="16" />
FontSize="16" />
<Separator />
<Separator />
<!--Patch management-->
<!--New patch button-->
<ListBox Name="patchManagementListBox"
HorizontalContentAlignment="Stretch"
VerticalAlignment="Stretch"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ItemsSource="{Binding Patches}"
MinHeight="300"
Margin="10,5" >
<ListBox.ContextMenu>
<ContextMenu DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Open"
Command="{Binding DataContext.CommandOpenPatch}"
CommandParameter="{Binding Path=SelectedItems}"/>
<MenuItem Header="Support"
Command="{Binding DataContext.CommandSupportPatch}"
CommandParameter="{Binding Path=SelectedItems}"/>
<MenuItem Header="Reject"
Command="{Binding DataContext.CommandRejectPatch}"
CommandParameter="{Binding Path=SelectedItems}"/>
</ContextMenu>
</ListBox.ContextMenu>
<ListBox.ItemTemplate>
<DataTemplate>
<ContentControl MouseDoubleClick="ContentControl_MouseDoubleClick">
<Grid Background="{Binding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="{Binding CommitMessage}"
TextTrimming="CharacterEllipsis"
VerticalAlignment="Center"
Foreground="{Binding Foreground}"
Margin="10"/>
<TextBlock Grid.Column="1"
Text="{Binding LastUpdate}"
TextTrimming="CharacterEllipsis"
VerticalAlignment="Center"
Foreground="{Binding Foreground}"
Margin="10"/>
</Grid>
</ContentControl>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Content="New patch"
<Button Content="New patch"
Style="{StaticResource StyleButtonGray}"
Style="{StaticResource StyleButtonGray}"
Margin="10,5,5,5"
Margin="10,5,5,5"
...
...
UI/Views/PatchDialogView.xaml
View file @
8eeab9ee
...
@@ -72,6 +72,7 @@
...
@@ -72,6 +72,7 @@
BorderBrush="Black"
BorderBrush="Black"
BorderThickness="1"
BorderThickness="1"
Margin="5,10,10,10"
Margin="5,10,10,10"
HorizontalScrollBarVisibility="Auto"
Document="{Binding VisibleDiff}"/>
Document="{Binding VisibleDiff}"/>
<ui:TextBoxWithPlaceholder Grid.Column="0"
<ui:TextBoxWithPlaceholder Grid.Column="0"
Grid.ColumnSpan="3"
Grid.ColumnSpan="3"
...
...